foobar2000 SDK  2015-01-14
nix-objects.cpp
Go to the documentation of this file.
1 #include "pfc.h"
2 
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <errno.h>
7 
8 #ifdef __APPLE__
9 #include <mach-o/dyld.h>
10 #endif
11 
12 namespace pfc {
13  void nixFormatError( string_base & str, int code ) {
14  char buffer[512] = {};
15  strerror_r(code, buffer, sizeof(buffer));
16  str = buffer;
17  }
18 
19  void setNonBlocking( int fd, bool bNonBlocking ) {
20  int flags = fcntl(fd, F_GETFL, 0);
21  int flags2 = flags;
22  if (bNonBlocking) flags2 |= O_NONBLOCK;
23  else flags2 &= ~O_NONBLOCK;
24  if (flags2 != flags) fcntl(fd, F_SETFL, flags2);
25  }
26 
27  void setCloseOnExec( int fd, bool bCloseOnExec ) {
28  int flags = fcntl(fd, F_GETFD);
29  int flags2 = flags;
30  if (bCloseOnExec) flags2 |= FD_CLOEXEC;
31  else flags2 &= ~FD_CLOEXEC;
32  if (flags != flags2) fcntl(fd, F_SETFD, flags2);
33  }
34 
35  void setInheritable( int fd, bool bInheritable ) {
36  setCloseOnExec( fd, !bInheritable );
37  }
38 
39  void createPipe( int fd[2], bool bInheritable ) {
40 #if defined(__linux__) && defined(O_CLOEXEC)
41  if (pipe2(fd, bInheritable ? 0 : O_CLOEXEC) < 0) throw exception_nix();
42 #else
43  if (pipe(fd) < 0) throw exception_nix();
44  if (!bInheritable) {
45  setInheritable( fd[0], false );
46  setInheritable( fd[1], false );
47  }
48 #endif
49  }
50 
52  _init(errno);
53  }
55  _init(code);
56  }
57  void exception_nix::_init(int code) {
58  m_code = code;
59  nixFormatError(m_msg, code);
60  }
61 
62  timeval makeTimeVal( double timeSeconds ) {
63  timeval tv = {};
64  uint64_t temp = (uint64_t) floor( timeSeconds * 1000000.0 + 0.5);
65  tv.tv_usec = (uint32_t) (temp % 1000000);
66  tv.tv_sec = (uint32_t) (temp / 1000000);
67  return tv;
68  }
69  double importTimeval(const timeval & in) {
70  return (double)in.tv_sec + (double)in.tv_usec / 1000000.0;
71  }
72 
73  void fdSet::operator+=( int fd ) {
74  FD_SET( fd, &m_set );
75  max_acc( m_nfds, fd + 1 );
76  }
77  void fdSet::operator-=( int fd ) {
78  FD_CLR( fd, &m_set );
79  }
80  bool fdSet::operator[] (int fd ) {
81  return FD_ISSET( fd, &m_set ) != 0;
82  }
83  void fdSet::clear() {
84  FD_ZERO( &m_set ); m_nfds = 0;
85  }
86 
88  return Select( (timeval*) NULL );
89  }
90  int fdSelect::Select( double timeOutSeconds ) {
91  if (timeOutSeconds < 0) {
92  return Select( );
93  } else {
94  timeval tv = makeTimeVal( timeOutSeconds );
95  return Select( & tv );
96  }
97  }
98  int fdSelect::Select( timeval * tv ) {
99  int nfds = 0;
100  max_acc(nfds, Reads.m_nfds);
101  max_acc(nfds, Writes.m_nfds);
102  max_acc(nfds, Errors.m_nfds);
103  int rv = select(nfds, &Reads.m_set, &Writes.m_set, &Errors.m_set, tv);
104  if (rv < 0) {
105  throw exception_nix();
106  }
107  return rv;
108  }
109 
110  bool fdCanRead( int fd ) {
111  return fdWaitRead( fd, 0 );
112  }
113  bool fdCanWrite( int fd ) {
114  return fdWaitWrite( fd, 0 );
115  }
116 
117  bool fdWaitRead( int fd, double timeOutSeconds ) {
118  fdSelect sel; sel.Reads += fd;
119  return sel.Select( timeOutSeconds ) > 0;
120  }
121  bool fdWaitWrite( int fd, double timeOutSeconds ) {
122  fdSelect sel; sel.Writes += fd;
123  return sel.Select( timeOutSeconds ) > 0;
124  }
125 
127  createPipe( m_fd );
128  setNonBlocking( m_fd[0] );
129  setNonBlocking( m_fd[1] );
130  }
132  close( m_fd[0] );
133  close( m_fd[1] );
134  }
135 
136  void nix_event::set_state( bool state ) {
137  if (state) {
138  // Ensure that there is a byte in the pipe
139  if (!fdCanRead(m_fd[0] ) ) {
140  uint8_t dummy = 0;
141  write( m_fd[1], &dummy, 1);
142  }
143  } else {
144  // Keep reading until clear
145  for(;;) {
146  uint8_t dummy;
147  if (read(m_fd[0], &dummy, 1 ) != 1) break;
148  }
149  }
150  }
151 
152  bool nix_event::wait_for( double p_timeout_seconds ) {
153  return fdWaitRead( m_fd[0], p_timeout_seconds );
154  }
155  bool nix_event::g_wait_for( int p_event, double p_timeout_seconds ) {
156  return fdWaitRead( p_event, p_timeout_seconds );
157  }
158  int nix_event::g_twoEventWait( int h1, int h2, double timeout ) {
159  fdSelect sel;
160  sel.Reads += h1;
161  sel.Reads += h2;
162  int state = sel.Select( timeout );
163  if (state < 0) throw exception_nix();
164  if (state == 0) return 0;
165  if (sel.Reads[ h1 ] ) return 1;
166  if (sel.Reads[ h2 ] ) return 2;
167  crash(); // should not get here
168  return 0;
169  }
170  int nix_event::g_twoEventWait( nix_event & ev1, nix_event & ev2, double timeout ) {
171  return g_twoEventWait( ev1.get_handle(), ev2.get_handle(), timeout );
172  }
173 
174  void nixSleep(double seconds) {
175  fdSelect sel; sel.Select( seconds );
176  }
177 
178  double nixGetTime() {
179  timeval tv = {};
180  gettimeofday(&tv, NULL);
181  return importTimeval(tv);
182  }
183 
184  bool nixReadSymLink( string_base & strOut, const char * path ) {
185  size_t l = 1024;
186  for(;;) {
187  array_t<char> buffer; buffer.set_size( l + 1 );
188  ssize_t rv = (size_t) readlink(path, buffer.get_ptr(), l);
189  if (rv < 0) return false;
190  if ((size_t)rv <= l) {
191  buffer.get_ptr()[rv] = 0;
192  strOut = buffer.get_ptr();
193  return true;
194  }
195  l *= 2;
196  }
197  }
198  bool nixSelfProcessPath( string_base & strOut ) {
199 #ifdef __APPLE__
200  uint32_t len = 0;
201  _NSGetExecutablePath(NULL, &len);
202  array_t<char> temp; temp.set_size( len + 1 ); temp.fill_null();
203  _NSGetExecutablePath(temp.get_ptr(), &len);
204  strOut = temp.get_ptr();
205  return true;
206 #else
207  return nixReadSymLink( strOut, PFC_string_formatter() << "/proc/" << (unsigned) getpid() << "/exe");
208 #endif
209  }
210 
211  void nixGetRandomData( void * outPtr, size_t outBytes ) {
212  fileHandle randomData;
213  randomData = open("/dev/random", O_RDONLY);
214  if (randomData.h < 0) throw exception_nix();
215  if ( read( randomData.h, outPtr, outBytes ) != outBytes ) throw exception_nix();
216  }
217 }
218 
219 void uSleepSeconds( double seconds, bool ) {
220  pfc::nixSleep( seconds );
221 }
void read(const service_ptr_t< file > &p_file, abort_callback &p_abort, pfc::string_base &p_out, bool &is_utf8)
void _init(int code)
Definition: nix-objects.cpp:57
void setNonBlocking(int fd, bool bNonBlocking)
Definition: nix-objects.cpp:19
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:27
void set_state(bool state)
void nixGetRandomData(void *outPtr, size_t outBytes)
void nixFormatError(string_base &str, int code)
Definition: nix-objects.cpp:13
fileHandle_t h
Definition: filehandle.h:24
void clear()
Definition: nix-objects.cpp:83
bool nixReadSymLink(string_base &strOut, const char *path)
double nixGetTime()
void operator+=(int fd)
Definition: nix-objects.cpp:73
void max_acc(t_val &p_acc, const t_val &p_val)
Definition: primitives.h:834
void uSleepSeconds(double seconds, bool)
void crash()
Definition: other.cpp:105
void set_size(t_size p_size)
Definition: array.h:104
bool fdWaitRead(int fd, double timeOutSeconds)
bool fdCanRead(int fd)
bool fdWaitWrite(int fd, double timeOutSeconds)
void operator-=(int fd)
Definition: nix-objects.cpp:77
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
fd_set m_set
Definition: nix-objects.h:47
bool fdCanWrite(int fd)
timeval makeTimeVal(double timeSeconds)
Definition: nix-objects.cpp:62
void createPipe(int fd[2], bool bInheritable)
Definition: nix-objects.cpp:39
int code() const
Definition: nix-objects.h:15
int get_handle() const
Definition: nix-objects.h:83
bool operator[](int fd)
Definition: nix-objects.cpp:80
void setInheritable(int fd, bool bInheritable)
Definition: nix-objects.cpp:35
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:69