cfl_platform.cpp
Go to the documentation of this file.
1 /** @file cfl_platform.cpp Platform dependant wrappers */
2 
3 /* FAU Discrete Event Systems Library (libfaudes)
4 
5  Copyright (C) 2013 Thomas Moor
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License as published by the Free Software Foundation; either
10  version 2.1 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 
22 
23 
24 // My header
25 #include "cfl_definitions.h"
26 #include "cfl_platform.h"
27 
28 // Extra header
29 #include <signal.h>
30 #include <exception>
31 #include <ostream>
32 
33 #ifdef FAUDES_GENERIC
34 void faudes_invalid(const std::string& msg) {
35  std::cerr << msg << std:endl;
36  throw 0;
37 }
38 #endif
39 
40 
41 
42 // Path separator (statics, see faudes_pathsep)
43 #ifdef FAUDES_POSIX
44 const std::string faudes_pathseps_str = "/";
45 const std::string faudes_pathsep_str = "/";
46 #endif
47 #ifdef FAUDES_WINDOWS
48 const std::string faudes_pathseps_str = "\\:/";
49 const std::string faudes_pathsep_str = "\\";
50 #endif
51 #ifdef FAUDES_GENERIC
52 const std::string faudes_pathseps_str = "/";
53 const std::string faudes_pathsep_str = "/";
54 #endif
55 
56 
57 // Uniform signalhandler on termination
58 void faudes_termsignal(void (*sighandler)(int)) {
59 #ifdef SIGTERM
60  signal(SIGTERM, sighandler);
61 #endif
62 #ifdef SIGINT
63  signal(SIGINT, sighandler);
64 #endif
65 #ifdef SIGQUIT
66  signal(SIGQUIT, sighandler);
67 #endif
68 #ifdef SIGHUP
69  signal(SIGHUP, sighandler);
70 #endif
71 #ifdef SIGABRT
72  signal(SIGABRT, sighandler);
73 #endif
74 }
75 
76 // Uniform signal names for POSIX / Windows/MinGW (see e.g. simfaudes.cpp)
77 const char* faudes_strsignal(int sig) {
78 #ifdef FAUDES_POSIX
79  return strsignal(sig);
80 #endif
81 #ifdef FAUDES_WINDOWS
82  return "unknown";
83 #endif
84 }
85 
86 
87 #ifdef FAUDES_SYSTIME
88 
89 // static debugging timer
90 faudes_systime_t gPerfTimer1;
91 
92 // Uniform system time (using pthread timespec semantics, trust MinGW to provide)
93 #if defined(FAUDES_POSIX)
94 void faudes_gettimeofday(faudes_systime_t* now) {
95  timeval nowval;
96  gettimeofday(&nowval,0);
97  now->tv_sec=nowval.tv_sec;
98  now->tv_nsec=nowval.tv_usec * 1000;
99 }
100 #endif
101 
102 #if defined(FAUDES_WINDOWS)
103 void faudes_gettimeofday(faudes_systime_t* now) {
104  DWORD nowval;
105  nowval= timeGetTime();
106  now->tv_sec=nowval / 1000;
107  now->tv_nsec=(nowval % 1000) *1000000;
108 }
109 #endif
110 
111 
112 
113 // Uniform system time (supporting functions)
114 void faudes_diffsystime(const faudes_systime_t& end, const faudes_systime_t& begin, faudes_systime_t* res) {
115  res->tv_sec = end.tv_sec-begin.tv_sec;
116  res->tv_nsec = end.tv_nsec-begin.tv_nsec;
117  if(res->tv_nsec <= 0){
118  res->tv_sec--;
119  res->tv_nsec += 1000000000;
120  }
121 }
122 
123 // Uniform system time (supporting functions)
124 void faudes_diffsystime(const faudes_systime_t& end, const faudes_systime_t& begin, faudes_mstime_t* res) {
125  *res = 1000*( end.tv_sec-begin.tv_sec);
126  *res += (end.tv_nsec-begin.tv_nsec) / 1000000;
127 }
128 
129 // Uniform system time (supporting functions)
130 void faudes_sumsystime(const faudes_systime_t& begin, const faudes_systime_t& duration, faudes_systime_t* res) {
131  res->tv_sec = begin.tv_sec + duration.tv_sec;
132  res->tv_nsec = begin.tv_nsec + duration.tv_nsec;
133  if(res->tv_nsec >= 1000000000) {
134  res->tv_sec++;
135  res->tv_nsec-=1000000000;
136  }
137 }
138 
139 // Uniform system time (supporting functions)
140 void faudes_msdelay(faudes_mstime_t msecs,faudes_systime_t* end) {
141  faudes_systime_t now;
142  faudes_gettimeofday(&now);
143  faudes_systime_t delta;
144  delta.tv_sec = msecs/1000;
145  delta.tv_nsec = (msecs % 1000) *1000000;
146  faudes_sumsystime(now,delta,end);
147 }
148 
149 // Uniform system time (supporting functions)
150 void faudes_usdelay(faudes_mstime_t usecs,faudes_systime_t* end) {
151  faudes_systime_t now;
152  faudes_gettimeofday(&now);
153  faudes_systime_t delta;
154  delta.tv_sec = usecs/1000000;
155  delta.tv_nsec = (usecs % 1000000) * 1000;
156  faudes_sumsystime(now,delta,end);
157 }
158 
159 
160 #endif // systime
161 
162 
163 #ifdef FAUDES_NETWORK
164 
165 
166 // Uniform socketoption: test for error
168 #ifdef FAUDES_POSIX
169  int opt=0;
170  socklen_t len = sizeof(opt);
171  int res = getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &len) < 0 ? -1 : 0;
172  if(opt!=0) res=-1;
173  return res;
174 #endif
175 #ifdef FAUDES_WINDOWS
176  int opt=0;
177  socklen_t len = sizeof(opt);
178  int res = getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0 ? -1 : 0;
179  if(opt!=0) res=-1;
180  return res;
181 #endif
182 }
183 
184 // Uniform socketoption: set nonblocking
185 int faudes_setsocket_nonblocking(int fd, bool noblo) {
186 #ifdef FAUDES_POSIX
187  int sopt=fcntl(fd, F_GETFL, NULL);
188  if(sopt<0) return -1; // error
189  if(noblo) {
190  int rc=fcntl(fd, F_SETFL, sopt|O_NONBLOCK);
191  return rc < 0 ? -1 : 0;
192  } else {
193  int rc=fcntl(fd, F_SETFL, sopt& (~O_NONBLOCK));
194  return rc < 0 ? -1 : 0;
195  }
196 #endif
197 #ifdef FAUDES_WINDOWS
198  unsigned long onoff=0;
199  if(noblo) onoff=1;
200  return ioctlsocket(fd, FIONBIO, &onoff) == SOCKET_ERROR ? -1 : 0;
201 #endif
202 }
203 
204 
205 
206 
207 
208 
209 #endif // network
210 
211 
212 #ifdef FAUDES_THREADS
213 
214 
215 // Use Windows thread local storage to implement pointer-typed return values
216 #ifdef FAUDES_WINDOWS
217 DWORD faudes_thread_tlsidx=TLS_OUT_OF_INDEXES;
218 #endif
219 
220 // Windows thread function wrapper with faudes_thread_t argument;
221 #ifdef FAUDES_WINDOWS
222 static unsigned WINAPI faudes_thread_wrapper(void *argfth) {
223  // access my thread struct
224  faudes_thread_t fthread = (faudes_thread_t) argfth;
225  // record my thread struct as tls
226  TlsSetValue(faudes_thread_tlsidx,fthread);
227  // extract actual function an arguments
228  void *(*fnct)(void*) = fthread->mFnct;
229  void *arg = fthread->mArg;
230  // call function
231  void* res = fnct(arg);
232  // uniform exit to retrieve return value
233  faudes_thread_exit(res);
234  // return dummy
235  return 0;
236 }
237 #endif
238 
239 // Thread functions (Windows to mimic pthreads)
240 #ifdef FAUDES_WINDOWS
241 int faudes_thread_create(faudes_thread_t *thr, void *(*fnct)(void *), void *arg){
242  // initialize thread local storage block
243  if(faudes_thread_tlsidx==TLS_OUT_OF_INDEXES)
244  faudes_thread_tlsidx=TlsAlloc();
245  if(faudes_thread_tlsidx==TLS_OUT_OF_INDEXES)
246  return FAUDES_THREAD_ERROR;
247  // malloc my thread structure
248  *thr = (faudes_thread_t) malloc(sizeof(faudes_thread_record_t));
249  if(!*thr) return FAUDES_THREAD_ERROR;
250  // initialze my thread structure with function and argument
251  (*thr)->mFnct = fnct;
252  (*thr)->mArg = arg;
253  (*thr)->mRes = NULL;
254  // start the thread
255  (*thr)->mHandle = (HANDLE) _beginthreadex(NULL, 0, faudes_thread_wrapper, (void*) (*thr), 0, NULL);
256  // done
257  return (*thr)->mHandle ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
258 }
259 #endif
260 
261 #ifdef FAUDES_WINDOWS
262 // Thread functions (Windows to mimic pthreads)
263 faudes_thread_t faudes_thread_current(void) {
264  // retrieve my thread struct from tls
265  faudes_thread_t fthread = (faudes_thread_t) TlsGetValue(faudes_thread_tlsidx);
266  // note: returns NULL for parent thread
267  return fthread;
268 }
269 #endif
270 
271 #ifdef FAUDES_WINDOWS
272 // Thread functions (Windows to mimic pthreads)
273 int faudes_thread_detach(faudes_thread_t thr) {
274  CloseHandle(thr->mHandle);
275  // free my mem
276  free(thr);
277  return FAUDES_THREAD_SUCCESS;
278 }
279 #endif
280 
281 #ifdef FAUDES_WINDOWS
282 // Thread functions (Windows to mimic pthreads)
283 int faudes_thread_equal(faudes_thread_t thr0, faudes_thread_t thr1) {
284  // the parent thread has no tls record and thus reports NULL
285  if( (thr0==NULL) && (thr1=NULL) ) return true;
286  if( (thr0==NULL) || (thr1=NULL) ) return false;
287  // std case, compare by handle
288  return thr0->mHandle == thr1->mHandle;
289 }
290 #endif
291 
292 #ifdef FAUDES_WINDOWS
293 // Thread functions (Windows to mimic pthreads)
294 void faudes_thread_exit(void *res) {
295  // retrieve thread structure from tls to pass on result
296  faudes_thread_t fthread = (faudes_thread_t) TlsGetValue(faudes_thread_tlsidx);
297  if(fthread) fthread->mRes=res;
298  // call winapi
299  ExitThread(0);
300 }
301 #endif
302 
303 #ifdef FAUDES_WINDOWS
304 // Thread functions (Windows to mimic pthreads)
305 int faudes_thread_join(faudes_thread_t thr, void **res) {
306  // default result
307  if(res) *res = 0;
308  // do the join
309  DWORD rc = WaitForSingleObject(thr->mHandle, INFINITE);
310  // retrieve result from thread structure
311  if( (rc!=WAIT_FAILED) && (res)) *res = thr->mRes;
312  // free mem
313  free(thr);
314  // done
315  if(rc == WAIT_FAILED) return FAUDES_THREAD_ERROR;
316  return FAUDES_THREAD_SUCCESS;
317 }
318 #endif
319 
320 // The approach to condition variables on Windows is taken from
321 // "Strategies for Implementing POSIX Condition Variables on Win32"
322 // by Douglas C. Schmidt and Irfan Pyarali, Department of Computer
323 // Science, Washington University.
324 
325 // Convenience access my two condition events
326 #ifdef FAUDES_WINDOWS
327 #define EVENT_SIGNAL 0
328 #define EVENT_BROADCAST 1
329 #endif
330 
331 // Condition functions (Windows to mimic plain pthread)
332 #ifdef FAUDES_WINDOWS
333 int faudes_cond_init(faudes_cond_t* cond) {
334  // #waiters=0, with mutexed access
335  cond->mWaitersCount = 0;
336  InitializeCriticalSection(&cond->mWaitersCountMutex);
337  // auto-reset event to signal the condition
338  cond->mEvents[EVENT_SIGNAL]=CreateEvent(NULL, FALSE, FALSE, NULL);
339  // manual-reset event to broadcast the condition
340  cond->mEvents[EVENT_BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
341  // initialisation succeeded
342  if(cond->mEvents[EVENT_SIGNAL] != NULL)
343  if(cond->mEvents[EVENT_BROADCAST] != NULL)
344  return FAUDES_THREAD_SUCCESS;
345  // allow for destroy even on failed initialisation
346  if(cond->mEvents[EVENT_SIGNAL] != NULL)
347  CloseHandle(cond->mEvents[EVENT_SIGNAL]);
348  if(cond->mEvents[EVENT_BROADCAST] != NULL)
349  CloseHandle(cond->mEvents[EVENT_BROADCAST]);
350  cond->mEvents[EVENT_BROADCAST] = NULL;
351  cond->mEvents[EVENT_SIGNAL]=NULL;
352  return FAUDES_THREAD_ERROR;
353 }
354 #endif
355 
356 #ifdef FAUDES_WINDOWS
357 // Condition functions (Windows to mimic plain pthread)
358 void faudes_cond_destroy(faudes_cond_t* cond) {
359  if(cond->mEvents[EVENT_SIGNAL] != NULL)
360  CloseHandle(cond->mEvents[EVENT_SIGNAL]);
361  if(cond->mEvents[EVENT_BROADCAST] != NULL)
362  CloseHandle(cond->mEvents[EVENT_BROADCAST]);
363  DeleteCriticalSection(&cond->mWaitersCountMutex);
364 }
365 #endif
366 
367 #ifdef FAUDES_WINDOWS
368 // Condition functions (Windows to mimic plain pthread)
369 int faudes_cond_signal(faudes_cond_t *cond){
370  int waiters;
371  // any waiters ?
372  EnterCriticalSection(&cond->mWaitersCountMutex);
373  waiters = (cond->mWaitersCount > 0);
374  LeaveCriticalSection(&cond->mWaitersCountMutex);
375  // set event (one waiter will see the auto-reset event)
376  if(waiters){
377  if(SetEvent(cond->mEvents[EVENT_SIGNAL]) == 0)
378  return FAUDES_THREAD_ERROR;
379  }
380  return FAUDES_THREAD_SUCCESS;
381 }
382 #endif
383 
384 #ifdef FAUDES_WINDOWS
385 // Condition functions (Windows to mimic plain pthread)
386 int faudes_cond_broadcast(faudes_cond_t *cond) {
387  int waiters;
388  // any waiters ?
389  EnterCriticalSection(&cond->mWaitersCountMutex);
390  waiters = (cond->mWaitersCount > 0);
391  LeaveCriticalSection(&cond->mWaitersCountMutex);
392  // set event (all waiters will see, last waiter does the manual-reset)
393  if(waiters) {
394  if(SetEvent(cond->mEvents[EVENT_BROADCAST]) == 0)
395  return FAUDES_THREAD_ERROR;
396  }
397  return FAUDES_THREAD_SUCCESS;
398 }
399 #endif
400 
401 #ifdef FAUDES_WINDOWS
402 // Condition functions (Windows to mimic plain pthread)
403 int faudes_cond_reltimedwait(faudes_cond_t *cond, faudes_mutex_t *mtx, faudes_mstime_t duration) {
404  // increment #waiters
405  EnterCriticalSection(&cond->mWaitersCountMutex);
406  ++ cond->mWaitersCount;
407  LeaveCriticalSection(&cond->mWaitersCountMutex);
408  // release mutex while waiting
409  LeaveCriticalSection(mtx);
410  // wait for either event to be set
411  int res = WaitForMultipleObjects(2, cond->mEvents, FALSE, (DWORD) duration);
412  // maintane my data ...
413  EnterCriticalSection(&cond->mWaitersCountMutex);
414  // ... a) decrement #waiters
415  -- cond->mWaitersCount;
416  // ... b) test if this was a broadcast and we were the last waiter ...
417  int last =
418  (res == (WAIT_OBJECT_0 + EVENT_BROADCAST)) &&
419  (cond->mWaitersCount == 0);
420  LeaveCriticalSection(&cond->mWaitersCountMutex);
421  // ... c) if so, do a manual-reset of the event
422  if(last) ResetEvent(cond->mEvents[EVENT_BROADCAST]);
423  // reaquire mutex
424  EnterCriticalSection(mtx);
425  // uniform return value
426  if(res == (int) WAIT_TIMEOUT)
427  return FAUDES_THREAD_TIMEOUT;
428  if(res == (int) WAIT_FAILED)
429  return FAUDES_THREAD_ERROR;
430  return FAUDES_THREAD_SUCCESS;
431 }
432 #endif
433 
434 #ifdef FAUDES_WINDOWS
435 // Condition functions (Windows to mimic plain pthread)
436 int faudes_cond_wait(faudes_cond_t *cond, faudes_mutex_t *mtx) {
437  return faudes_cond_reltimedwait(cond, mtx, INFINITE);
438 }
439 #endif
440 
441 #ifdef FAUDES_WINDOWS
442 // Condition functions (Windows to mimic plain pthread)
443 int faudes_cond_timedwait(faudes_cond_t *cond, faudes_mutex_t *mtx, const faudes_systime_t *abstime) {
444  // get absolute time
445  faudes_systime_t now;
446  faudes_gettimeofday(&now);
447  // convert to rel. time in secs
448  DWORD rels = abstime->tv_sec - now.tv_sec;
449  // saturation on overflow
450  if(rels > (4294967295u/1000)-1) rels = 4294967295u/1000-1;
451  // convert to rel. time in msecs
452  DWORD relms = rels*1000 + (abstime->tv_nsec - now.tv_nsec + 500000) / 1000000;
453  // pass on to reltimedwait
454  return faudes_cond_reltimedwait(cond, mtx, relms);
455 }
456 #endif
457 
458 
459 #endif // threads
460 
461 
462 
463 
Compiletime options.
faudes_systime_t gPerfTimer1
void faudes_usdelay(faudes_mstime_t usecs, faudes_systime_t *end)
const char * faudes_strsignal(int sig)
int faudes_setsocket_nonblocking(int fd, bool noblo)
void faudes_termsignal(void(*sighandler)(int))
int faudes_getsocket_error(int fd)
void faudes_sumsystime(const faudes_systime_t &begin, const faudes_systime_t &duration, faudes_systime_t *res)
const std::string faudes_pathseps_str
const std::string faudes_pathsep_str
void faudes_invalid(const std::string &msg)
void faudes_msdelay(faudes_mstime_t msecs, faudes_systime_t *end)
void faudes_diffsystime(const faudes_systime_t &end, const faudes_systime_t &begin, faudes_systime_t *res)
Platform dependant wrappers.

libFAUDES 2.32b --- 2024.03.01 --- c++ api documentaion by doxygen