foobar2000 SDK  2015-08-03
nix-objects.cpp
Go to the documentation of this file.
1 #include "pfc.h"
2 
3 #ifndef _WIN32
4 #include <stdio.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <errno.h>
8 #include <poll.h>
9 
10 #ifdef __APPLE__
11 #include <mach-o/dyld.h>
12 #endif
13 
14 namespace pfc {
15  void nixFormatError( string_base & str, int code ) {
16  char buffer[512] = {};
17  strerror_r(code, buffer, sizeof(buffer));
18  str = buffer;
19  }
20 
21  void setNonBlocking( int fd, bool bNonBlocking ) {
22  int flags = fcntl(fd, F_GETFL, 0);
23  int flags2 = flags;
24  if (bNonBlocking) flags2 |= O_NONBLOCK;
25  else flags2 &= ~O_NONBLOCK;
26  if (flags2 != flags) fcntl(fd, F_SETFL, flags2);
27  }
28 
29  void setCloseOnExec( int fd, bool bCloseOnExec ) {
30  int flags = fcntl(fd, F_GETFD);
31  int flags2 = flags;
32  if (bCloseOnExec) flags2 |= FD_CLOEXEC;
33  else flags2 &= ~FD_CLOEXEC;
34  if (flags != flags2) fcntl(fd, F_SETFD, flags2);
35  }
36 
37  void setInheritable( int fd, bool bInheritable ) {
38  setCloseOnExec( fd, !bInheritable );
39  }
40 
41  void createPipe( int fd[2], bool bInheritable ) {
42 #if defined(__linux__) && defined(O_CLOEXEC)
43  if (pipe2(fd, bInheritable ? 0 : O_CLOEXEC) < 0) throw exception_nix();
44 #else
45  if (pipe(fd) < 0) throw exception_nix();
46  if (!bInheritable) {
47  setInheritable( fd[0], false );
48  setInheritable( fd[1], false );
49  }
50 #endif
51  }
52 
54  _init(errno);
55  }
57  _init(code);
58  }
60  m_code = code;
61  nixFormatError(m_msg, code);
62  }
63 
64  timeval makeTimeVal( double timeSeconds ) {
65  timeval tv = {};
66  uint64_t temp = (uint64_t) floor( timeSeconds * 1000000.0 + 0.5);
67  tv.tv_usec = (uint32_t) (temp % 1000000);
68  tv.tv_sec = (uint32_t) (temp / 1000000);
69  return tv;
70  }
71  double importTimeval(const timeval & in) {
72  return (double)in.tv_sec + (double)in.tv_usec / 1000000.0;
73  }
74 
75  void fdSet::operator+=( int fd ) {
76  m_fds.insert( fd );
77  }
78  void fdSet::operator-=( int fd ) {
79  m_fds.erase(fd);
80  }
81  bool fdSet::operator[] (int fd ) {
82  return m_fds.find( fd ) != m_fds.end();
83  }
84  void fdSet::clear() {
85  m_fds.clear();
86  }
87 
88  void fdSet::operator+=( fdSet const & other ) {
89  for(auto i = other.m_fds.begin(); i != other.m_fds.end(); ++ i ) {
90  (*this) += *i;
91  }
92  }
93 
95  return Select_( -1 );
96  }
97  int fdSelect::Select( double timeOutSeconds ) {
98  int ms;
99  if (timeOutSeconds < 0) {
100  ms = -1;
101  } else if (timeOutSeconds == 0) {
102  ms = 0;
103  } else {
104  ms = pfc::rint32( timeOutSeconds * 1000 );
105  if (ms < 1) ms = 1;
106  }
107  return Select_( ms );
108  }
109 
110  int fdSelect::Select_( int timeOutMS ) {
111  fdSet total = Reads;
112  total += Writes;
113  total += Errors;
114  const size_t count = total.m_fds.size();
116  v.set_size_discard( count );
117  size_t walk = 0;
118  for( auto i = total.m_fds.begin(); i != total.m_fds.end(); ++ i ) {
119  const int fd = *i;
120  auto & f = v[walk++];
121  f.fd = fd;
122  f.events = (Reads[fd] ? POLLIN : 0) | (Writes[fd] ? POLLOUT : 0);
123  f.revents = 0;
124  }
125  int status = poll(v.get_ptr(), (int)count, timeOutMS);
126  if (status < 0) throw exception_nix();
127 
128  Reads.clear(); Writes.clear(); Errors.clear();
129 
130  if (status > 0) {
131  for(walk = 0; walk < count; ++walk) {
132  auto & f = v[walk];
133  if (f.revents & POLLIN) Reads += f.fd;
134  if (f.events & POLLOUT) Writes += f.fd;
135  if (f.events & POLLERR) Errors += f.fd;
136  }
137  }
138 
139  return status;
140  }
141 
142  bool fdCanRead( int fd ) {
143  return fdWaitRead( fd, 0 );
144  }
145  bool fdCanWrite( int fd ) {
146  return fdWaitWrite( fd, 0 );
147  }
148 
149  bool fdWaitRead( int fd, double timeOutSeconds ) {
150  fdSelect sel; sel.Reads += fd;
151  return sel.Select( timeOutSeconds ) > 0;
152  }
153  bool fdWaitWrite( int fd, double timeOutSeconds ) {
154  fdSelect sel; sel.Writes += fd;
155  return sel.Select( timeOutSeconds ) > 0;
156  }
157 
159  createPipe( m_fd );
160  setNonBlocking( m_fd[0] );
161  setNonBlocking( m_fd[1] );
162  }
164  close( m_fd[0] );
165  close( m_fd[1] );
166  }
167 
168  void nix_event::set_state( bool state ) {
169  if (state) {
170  // Ensure that there is a byte in the pipe
171  if (!fdCanRead(m_fd[0] ) ) {
172  uint8_t dummy = 0;
173  write( m_fd[1], &dummy, 1);
174  }
175  } else {
176  // Keep reading until clear
177  for(;;) {
178  uint8_t dummy;
179  if (read(m_fd[0], &dummy, 1 ) != 1) break;
180  }
181  }
182  }
183 
184  bool nix_event::wait_for( double p_timeout_seconds ) {
185  return fdWaitRead( m_fd[0], p_timeout_seconds );
186  }
187  bool nix_event::g_wait_for( int p_event, double p_timeout_seconds ) {
188  return fdWaitRead( p_event, p_timeout_seconds );
189  }
190  int nix_event::g_twoEventWait( int h1, int h2, double timeout ) {
191  fdSelect sel;
192  sel.Reads += h1;
193  sel.Reads += h2;
194  int state = sel.Select( timeout );
195  if (state < 0) throw exception_nix();
196  if (state == 0) return 0;
197  if (sel.Reads[ h1 ] ) return 1;
198  if (sel.Reads[ h2 ] ) return 2;
199  crash(); // should not get here
200  return 0;
201  }
202  int nix_event::g_twoEventWait( nix_event & ev1, nix_event & ev2, double timeout ) {
203  return g_twoEventWait( ev1.get_handle(), ev2.get_handle(), timeout );
204  }
205 
206  void nixSleep(double seconds) {
207  fdSelect sel; sel.Select( seconds );
208  }
209 
210  double nixGetTime() {
211  timeval tv = {};
212  gettimeofday(&tv, NULL);
213  return importTimeval(tv);
214  }
215 
216  bool nixReadSymLink( string_base & strOut, const char * path ) {
217  size_t l = 1024;
218  for(;;) {
219  array_t<char> buffer; buffer.set_size( l + 1 );
220  ssize_t rv = (size_t) readlink(path, buffer.get_ptr(), l);
221  if (rv < 0) return false;
222  if ((size_t)rv <= l) {
223  buffer.get_ptr()[rv] = 0;
224  strOut = buffer.get_ptr();
225  return true;
226  }
227  l *= 2;
228  }
229  }
230  bool nixSelfProcessPath( string_base & strOut ) {
231 #ifdef __APPLE__
232  uint32_t len = 0;
233  _NSGetExecutablePath(NULL, &len);
234  array_t<char> temp; temp.set_size( len + 1 ); temp.fill_null();
235  _NSGetExecutablePath(temp.get_ptr(), &len);
236  strOut = temp.get_ptr();
237  return true;
238 #else
239  return nixReadSymLink( strOut, PFC_string_formatter() << "/proc/" << (unsigned) getpid() << "/exe");
240 #endif
241  }
242 
243  void nixGetRandomData( void * outPtr, size_t outBytes ) {
244  try {
245  fileHandle randomData;
246  randomData = open("/dev/urandom", O_RDONLY);
247  if (randomData.h < 0) throw exception_nix();
248  if (read(randomData.h, outPtr, outBytes) != outBytes) throw exception_nix();
249  }
250  catch (std::exception const & e) {
251  throw std::runtime_error("getRandomData failure");
252  }
253  }
254 
255 #ifndef __APPLE__ // for Apple they are implemented in Obj-C
256  bool isShiftKeyPressed() {return false;}
257  bool isCtrlKeyPressed() {return false;}
258  bool isAltKeyPressed() {return false;}
259 #endif
260 }
261 
262 void uSleepSeconds( double seconds, bool ) {
263  pfc::nixSleep( seconds );
264 }
265 #endif // _WIN32
266 
void read(const service_ptr_t< file > &p_file, abort_callback &p_abort, pfc::string_base &p_out, bool &is_utf8)
int Select_(int timeOutMS)
void _init(int code)
Definition: nix-objects.cpp:59
void setNonBlocking(int fd, bool bNonBlocking)
Definition: nix-objects.cpp:21
std::set< int > m_fds
Definition: nix-objects.h:49
bool nixSelfProcessPath(string_base &strOut)
const t_item * get_ptr() const
Definition: array.h:213
void setCloseOnExec(int fd, bool bCloseOnExec)
Definition: nix-objects.cpp:29
void set_state(bool state)
void nixGetRandomData(void *outPtr, size_t outBytes)
bool isShiftKeyPressed()
void nixFormatError(string_base &str, int code)
Definition: nix-objects.cpp:15
bool isCtrlKeyPressed()
fileHandle_t h
Definition: filehandle.h:24
bool isAltKeyPressed()
void clear()
Definition: nix-objects.cpp:84
bool nixReadSymLink(string_base &strOut, const char *path)
double nixGetTime()
void operator+=(int fd)
Definition: nix-objects.cpp:75
void uSleepSeconds(double seconds, bool)
void crash()
Definition: other.cpp:112
void set_size(t_size p_size)
Definition: array.h:104
bool fdWaitRead(int fd, double timeOutSeconds)
t_int32 rint32(double p_val)
Definition: other.cpp:209
bool fdCanRead(int fd)
bool fdWaitWrite(int fd, double timeOutSeconds)
void operator-=(int fd)
Definition: nix-objects.cpp:78
void write(const service_ptr_t< file > &p_file, abort_callback &p_abort, const char *p_string, bool is_utf8)
static int g_twoEventWait(nix_event &ev1, nix_event &ev2, double timeout)
void fill_null()
Definition: array.h:203
std::exception exception
Definition: primitives.h:193
bool fdCanWrite(int fd)
timeval makeTimeVal(double timeSeconds)
Definition: nix-objects.cpp:64
void createPipe(int fd[2], bool bInheritable)
Definition: nix-objects.cpp:41
int code() const
Definition: nix-objects.h:16
int get_handle() const
Definition: nix-objects.h:84
void set_size_discard(t_size p_size)
Definition: array.h:128
bool operator[](int fd)
Definition: nix-objects.cpp:81
void setInheritable(int fd, bool bInheritable)
Definition: nix-objects.cpp:37
static bool g_wait_for(int p_event, double p_timeout_seconds)
void nixSleep(double seconds)
bool wait_for(double p_timeout_seconds)
double importTimeval(const timeval &in)
Definition: nix-objects.cpp:71