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, 2024 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 <csignal>
30 #include <exception>
31 #include <ostream>
32 
33 #ifdef FAUDES_GENERIC
34 void faudes_invalid(const std::string& msg) {
35  std::cerr << "faudes_invalid(): " << msg << std:endl;
36  throw 0;
37 }
38 #endif
39 
40 
41 // Path separator (statics, see faudes_pathsep)
42 #ifdef FAUDES_POSIX
43 const std::string& faudes_pathseps(void) {
44  static std::string faudes_pathsep_str = "/";
45  return faudes_pathsep_str;
46 }
47 const std::string& faudes_pathsep(void) {
48  return faudes_pathseps();
49 }
50 #endif
51 #ifdef FAUDES_WINDOWS
52 const std::string& faudes_pathseps(void) {
53  static std::string faudes_pathseps_str = "/\\:";
54  return faudes_pathseps_str;
55 }
56 const std::string& faudes_pathsep(void) {
57  static std::string faudes_pathsep_str = "";
58  if(faudes_pathsep_str=="")
59  faudes_pathsep_str=faudes_pathseps().substr(0,1);
60  return faudes_pathsep_str;
61 }
62 #endif
63 #ifdef FAUDES_GENERIC
64 const std::string& faudes_pathseps(void) {
65  static std::string faudes_pathsep_str = "/";
66  return faudes_pathsep_str;
67 }
68 const std::string& faudes_pathsep(void) {
69  return faudes_pathseps();
70 }
71 #endif
72 
73 
74 // Noramliese to internal path representation (as of 2.32 posix)
75 std::string faudes_normpath(const std::string& rPath){
76  std::string res;
77  // if the path begins with "drive-letter+':'" it become '/'+drive-letter+'/'
78  res=rPath;
79  if(rPath.size()>=2) {
80  if(rPath.at(1)==':')
81  res=faudes_pathsep() + rPath.at(0) + faudes_pathsep() + rPath.substr(2);
82  }
83  // all seps become my sep (as of 2.32 '/')
84  size_t pos;
85  for(pos=0; pos<res.size(); ++pos) {
86  char c=res.at(pos);
87  if(faudes_pathseps().find(c)!=std::string::npos)
88  res.at(pos)=faudes_pathseps().at(0);
89  }
90  // could do more here: "//"? "NUL:"?
91  return res;
92 }
93 
94 // Externalise internal path representation to shell compatile format
95 // note: this addresse windows cmd.exe only
96 std::string faudes_extpath(const std::string& rPath){
97  std::string res=rPath;
98 #ifdef FAUDES_WINDOWS
99  // all seps become cmd.exe-sep (aka \‍)
100  size_t pos;
101  for(pos=0; pos<res.size(); ++pos) {
102  char c=res.at(pos);
103  if(c==faudes_pathseps().at(0))
104  res.at(pos)='\\';
105  }
106  // if the path begins with "\drive-letter+'\' it becomes 'drive-letter+':'
107  // TODO
108  //std::cerr << "faudes_extpath(): ---> " << res << std::endl;
109 #endif
110  return res;
111 }
112 
113 
114 // uniform get/set dir (use posix style interface)
115 #ifdef FAUDES_POSIX
116 std::string faudes_getwd(void) {
117  std::string res;
118  char buf[(PATH_MAX)+1];
119  char* wd =getcwd(buf,PATH_MAX);
120  if(wd==nullptr) return res;
121  res=wd;
122  return res;
123 }
124 int faudes_chdir(const std::string& nwd) {
125  return (chdir(nwd.c_str())==0 ? 0 : -1);
126 }
127 #endif
128 #ifdef FAUDES_WINDOWS
129 #include <tchar.h>
130 std::string faudes_getwd(void) {
131  std::string res;
132  TCHAR buf[MAX_PATH];
133  DWORD ret = GetCurrentDirectory(MAX_PATH, buf);
134  if((ret == 0) || (ret>MAX_PATH)) return res;
135  res=buf;
136  return res;
137 }
138 int faudes_chdir(const std::string& nwd) {
139  TCHAR buf[MAX_PATH];
140  if(nwd.size()+1>MAX_PATH)
141  return -1;
142  strncpy(buf,nwd.c_str(),MAX_PATH-1);
143  if(!SetCurrentDirectory(buf))
144  return -1;
145  return 0;
146 }
147 #endif
148 #ifdef FAUDES_GENERIC
149 std::string faudes_getwd(void) {
150  faudes_invalid("faudes_getwd()");
151  std::string res;
152  return res;
153 }
154 int faudes_chdir(const std::string& nwd) {
155  faudes_invalid("faudes_chdir()");
156  return -1;
157 }
158 #endif
159 
160 // Uniform signalhandler on termination
161 void faudes_termsignal(void (*sighandler)(int)) {
162 #ifdef SIGTERM
163  signal(SIGTERM, sighandler);
164 #endif
165 #ifdef SIGINT
166  signal(SIGINT, sighandler);
167 #endif
168 #ifdef SIGQUIT
169  signal(SIGQUIT, sighandler);
170 #endif
171 #ifdef SIGHUP
172  signal(SIGHUP, sighandler);
173 #endif
174 #ifdef SIGABRT
175  signal(SIGABRT, sighandler);
176 #endif
177 }
178 
179 // Uniform signal names for POSIX / Windows/MinGW (see e.g. simfaudes.cpp)
180 const char* faudes_strsignal(int sig) {
181 #ifdef FAUDES_POSIX
182  return strsignal(sig);
183 #else
184  return "unknown";
185 #endif
186 }
187 
188 // Uniform sleep for POSIX/Windows (see e.g. iodevice plug-in)
189 #ifdef FAUDES_POSIX
190 void faudes_sleep(long int sec) {sleep(sec);}
191 void faudes_usleep(long int usec) {usleep(usec);}
192 #endif
193 #ifdef FAUDES_WINDOWS
194 void faudes_sleep(long int sec) {Sleep((sec) * 1000);}
195 void faudes_usleep(long int usec) {Sleep((usec) / 1000);}
196 #endif
197 #ifdef FAUDES_GENERIC
198 void faudes_sleep(long int sec) { faudes_invalid("faudes_sleep()"); }
199 void faudes_usleep(long int usec) { faudes_invalid("faudes_usleep()"); }
200 #endif
201 
202 
203 
204 #ifdef FAUDES_SYSTIME
205 
206 // static debugging timer
207 faudes_systime_t gPerfTimer1;
208 
209 // Uniform system time (using pthread timespec semantics, trust MinGW to provide)
210 #if defined(FAUDES_POSIX)
211 void faudes_gettimeofday(faudes_systime_t* now) {
212  timeval nowval;
213  gettimeofday(&nowval,0);
214  now->tv_sec=nowval.tv_sec;
215  now->tv_nsec=nowval.tv_usec * 1000;
216 }
217 #endif
218 
219 #if defined(FAUDES_WINDOWS)
220 void faudes_gettimeofday(faudes_systime_t* now) {
221  DWORD nowval;
222  nowval= timeGetTime();
223  now->tv_sec=nowval / 1000;
224  now->tv_nsec=(nowval % 1000) *1000000;
225 }
226 #endif
227 
228 
229 
230 // Uniform system time (supporting functions)
231 void faudes_diffsystime(const faudes_systime_t& end, const faudes_systime_t& begin, faudes_systime_t* res) {
232  res->tv_sec = end.tv_sec-begin.tv_sec;
233  res->tv_nsec = end.tv_nsec-begin.tv_nsec;
234  if(res->tv_nsec <= 0){
235  res->tv_sec--;
236  res->tv_nsec += 1000000000;
237  }
238 }
239 
240 // Uniform system time (supporting functions)
241 void faudes_diffsystime(const faudes_systime_t& end, const faudes_systime_t& begin, faudes_mstime_t* res) {
242  *res = 1000*( end.tv_sec-begin.tv_sec);
243  *res += (end.tv_nsec-begin.tv_nsec) / 1000000;
244 }
245 
246 // Uniform system time (supporting functions)
247 void faudes_sumsystime(const faudes_systime_t& begin, const faudes_systime_t& duration, faudes_systime_t* res) {
248  res->tv_sec = begin.tv_sec + duration.tv_sec;
249  res->tv_nsec = begin.tv_nsec + duration.tv_nsec;
250  if(res->tv_nsec >= 1000000000) {
251  res->tv_sec++;
252  res->tv_nsec-=1000000000;
253  }
254 }
255 
256 // Uniform system time (supporting functions)
257 void faudes_msdelay(faudes_mstime_t msecs,faudes_systime_t* end) {
258  faudes_systime_t now;
259  faudes_gettimeofday(&now);
260  faudes_systime_t delta;
261  delta.tv_sec = msecs/1000;
262  delta.tv_nsec = (msecs % 1000) *1000000;
263  faudes_sumsystime(now,delta,end);
264 }
265 
266 // Uniform system time (supporting functions)
267 void faudes_usdelay(faudes_mstime_t usecs,faudes_systime_t* end) {
268  faudes_systime_t now;
269  faudes_gettimeofday(&now);
270  faudes_systime_t delta;
271  delta.tv_sec = usecs/1000000;
272  delta.tv_nsec = (usecs % 1000000) * 1000;
273  faudes_sumsystime(now,delta,end);
274 }
275 
276 
277 #endif // systime
278 
279 
280 #ifdef FAUDES_NETWORK
281 
282 #ifdef FAUDES_POSIX
283 int faudes_closesocket(int fd) {
284  return close(fd);
285 }
286 int faudes_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) {
287  return setsockopt(fd,level,optname,optval,optlen);
288 }
289 int faudes_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) {
290  return getsockopt(fd,level,optname,optval,optlen);
291 }
292 int faudes_getsocket_error(int fd) {
293  int opt=0;
294  socklen_t len = sizeof(opt);
295  int res = getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &len) < 0 ? -1 : 0;
296  if(opt!=0) res=-1;
297  return res;
298 }
299 int faudes_setsocket_nonblocking(int fd, bool noblo) {
300  int sopt=fcntl(fd, F_GETFL, NULL);
301  if(sopt<0) return -1; // error
302  if(noblo) {
303  int rc=fcntl(fd, F_SETFL, sopt|O_NONBLOCK);
304  return rc < 0 ? -1 : 0;
305  } else {
306  int rc=fcntl(fd, F_SETFL, sopt& (~O_NONBLOCK));
307  return rc < 0 ? -1 : 0;
308  }
309 }
310 #endif
311 #ifdef FAUDES_WINDOWS
312 typedef int socklen_t;
313 int faudes_closesocket(int fd) {
314  return closesocket(fd);
315 }
316 int faudes_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) {
317  return setsockopt(fd,level,optname,(char*) optval,optlen);
318 }
319 int faudes_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) {
320  return getsockopt(fd,level,optname,(char*) optval,optlen);
321 }
322 int faudes_getsocket_error(int fd) {
323  int opt=0;
324  socklen_t len = sizeof(opt);
325  int res = getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0 ? -1 : 0;
326  if(opt!=0) res=-1;
327  return res;
328 }
329 int faudes_setsocket_nonblocking(int fd, bool noblo) {
330  unsigned long onoff=0;
331  if(noblo) onoff=1;
332  return ioctlsocket(fd, FIONBIO, &onoff) == SOCKET_ERROR ? -1 : 0;
333 }
334 #endif
335 #ifdef FAUDES_GENERIC
336 #error option network not available on generic platform
337 #endif
338 
339 #endif // network
340 
341 
342 
343 // straight PPOSIX threads (aka plain wrappers)
344 #ifdef FAUDES_THREADS
345 #ifdef FAUDES_POSIX
346 // Thread data type (use plain POSIX thread)
347 typedef pthread_t faudes_thread_t;
348 // Thread functions (plain pthread wrapper)
349 int faudes_thread_create(faudes_thread_t *thr, void *(*fnct)(void *), void *arg){
350  // prepare attribute for plain joinable thread
351  pthread_attr_t attr;
352  pthread_attr_init(&attr);
353  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
354  // start execute
355  int ret = pthread_create(thr, &attr, fnct, arg);
356  // done
357  pthread_attr_destroy(&attr);
358  return ret == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
359 }
360 faudes_thread_t faudes_thread_current(void) {
361  return pthread_self();
362 }
363 int faudes_thread_detach(faudes_thread_t thr) {
364  return pthread_detach(thr)==0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
365 }
366 int faudes_thread_equal(faudes_thread_t thr0, faudes_thread_t thr1) {
367  return pthread_equal(thr0, thr1);
368 }
369 void faudes_thread_exit(void* res) {
370  pthread_exit(res);
371 }
372 int faudes_thread_join(faudes_thread_t thr, void **res) {
373  return pthread_join(thr, res) == 0 ? FAUDES_THREAD_ERROR : FAUDES_THREAD_SUCCESS;
374 }
375 #endif
376 #endif // POSIX threads
377 
378 // Windows to mimique PPOSIX threads
379 #ifdef FAUDES_THREADS
380 #ifdef FAUDES_WINDOWS
381 
382 // Use Windows thread local storage to implement pointer-typed return values
383 DWORD faudes_thread_tlsidx=TLS_OUT_OF_INDEXES;
384 
385 // Windows thread function wrapper with faudes_thread_t argument;
386 static unsigned WINAPI faudes_thread_wrapper(void *argfth) {
387  // access my thread struct
388  faudes_thread_t fthread = (faudes_thread_t) argfth;
389  // record my thread struct as tls
390  TlsSetValue(faudes_thread_tlsidx,fthread);
391  // extract actual function and arguments
392  void *(*fnct)(void*) = fthread->mFnct;
393  void *arg = fthread->mArg;
394  // call function
395  void* res = fnct(arg);
396  // uniform exit to retrieve return value
397  faudes_thread_exit(res);
398  // return dummy
399  return 0;
400 }
401 
402 // Thread functions (Windows to mimic pthreads)
403 int faudes_thread_create(faudes_thread_t *thr, void *(*fnct)(void *), void *arg){
404  // initialize thread local storage block
405  if(faudes_thread_tlsidx==TLS_OUT_OF_INDEXES)
406  faudes_thread_tlsidx=TlsAlloc();
407  if(faudes_thread_tlsidx==TLS_OUT_OF_INDEXES)
408  return FAUDES_THREAD_ERROR;
409  // malloc my thread structure
410  *thr = (faudes_thread_t) malloc(sizeof(faudes_thread_record_t));
411  if(!*thr) return FAUDES_THREAD_ERROR;
412  // initialze my thread structure with function and argument
413  (*thr)->mFnct = fnct;
414  (*thr)->mArg = arg;
415  (*thr)->mRes = NULL;
416  // start the thread
417  (*thr)->mHandle = (HANDLE) _beginthreadex(NULL, 0, faudes_thread_wrapper, (void*) (*thr), 0, NULL);
418  // done
419  return (*thr)->mHandle ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
420 }
421 
422 // Thread functions (Windows to mimic pthreads)
423 faudes_thread_t faudes_thread_current(void) {
424  // retrieve my thread struct from tls
425  faudes_thread_t fthread = (faudes_thread_t) TlsGetValue(faudes_thread_tlsidx);
426  // note: returns NULL for parent thread
427  return fthread;
428 }
429 
430 // Thread functions (Windows to mimic pthreads)
431 int faudes_thread_detach(faudes_thread_t thr) {
432  CloseHandle(thr->mHandle);
433  // free my mem
434  free(thr);
435  return FAUDES_THREAD_SUCCESS;
436 }
437 
438 // Thread functions (Windows to mimic pthreads)
439 int faudes_thread_equal(faudes_thread_t thr0, faudes_thread_t thr1) {
440  // the parent thread has no tls record and thus reports NULL
441  if( (thr0==NULL) && (thr1=NULL) ) return true;
442  if( (thr0==NULL) || (thr1=NULL) ) return false;
443  // std case, compare by handle
444  return thr0->mHandle == thr1->mHandle;
445 }
446 
447 // Thread functions (Windows to mimic pthreads)
448 void faudes_thread_exit(void *res) {
449  // retrieve thread structure from tls to pass on result
450  faudes_thread_t fthread = (faudes_thread_t) TlsGetValue(faudes_thread_tlsidx);
451  if(fthread) fthread->mRes=res;
452  // call winapi
453  ExitThread(0);
454 }
455 
456 // Thread functions (Windows to mimic pthreads)
457 int faudes_thread_join(faudes_thread_t thr, void **res) {
458  // default result
459  if(res) *res = 0;
460  // do the join
461  DWORD rc = WaitForSingleObject(thr->mHandle, INFINITE);
462  // retrieve result from thread structure
463  if( (rc!=WAIT_FAILED) && (res)) *res = thr->mRes;
464  // free mem
465  free(thr);
466  // done
467  if(rc == WAIT_FAILED) return FAUDES_THREAD_ERROR;
468  return FAUDES_THREAD_SUCCESS;
469 }
470 
471 #endif
472 #endif // Windows threads
473 
474 
475 
476 // straight PPOSIX mutexes (aka plain wrappers)
477 #ifdef FAUDES_THREADS
478 #ifdef FAUDES_POSIX
479 int faudes_mutex_init(faudes_mutex_t* mtx){
480  return pthread_mutex_init(mtx, NULL)==0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
481 }
482 void faudes_mutex_destroy(faudes_mutex_t* mtx){
483  pthread_mutex_destroy(mtx);
484 }
485 int faudes_mutex_lock(faudes_mutex_t *mtx) {
486  return pthread_mutex_lock(mtx) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
487 }
488 int faudes_mutex_trylock(faudes_mutex_t *mtx){
489  return (pthread_mutex_trylock(mtx) == 0) ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
490 }
491 int faudes_mutex_unlock(faudes_mutex_t *mtx){
492  return pthread_mutex_unlock(mtx) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
493 }
494 #endif
495 #endif // POSIX mutexes
496 
497 // Windows to mimique PPOSIX mutexes
498 #ifdef FAUDES_THREADS
499 #ifdef FAUDES_WINDOWS
500 int faudes_mutex_init(faudes_mutex_t *mtx){
501  InitializeCriticalSection(mtx);
502  return FAUDES_THREAD_SUCCESS;
503 }
504 void faudes_mutex_destroy(faudes_mutex_t *mtx){
505  DeleteCriticalSection(mtx);
506 }
507 int faudes_mutex_lock(faudes_mutex_t *mtx) {
508  EnterCriticalSection(mtx);
509  return FAUDES_THREAD_SUCCESS;
510 }
511 int faudes_mutex_trylock(faudes_mutex_t *mtx){
512  return TryEnterCriticalSection(mtx) ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
513 }
514 int faudes_mutex_unlock(faudes_mutex_t *mtx){
515  LeaveCriticalSection(mtx);
516  return FAUDES_THREAD_SUCCESS;
517 }
518 #endif
519 #endif // Windows mutexes
520 
521 
522 // straight PPOSIX conditions (aka plain wrappers)
523 #ifdef FAUDES_THREADS
524 #ifdef FAUDES_POSIX
525 int faudes_cond_init(faudes_cond_t* cond) {
526  return pthread_cond_init(cond, NULL) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
527 }
528 void faudes_cond_destroy(faudes_cond_t* cond) {
529  pthread_cond_destroy(cond);
530 }
531 int faudes_cond_signal(faudes_cond_t *cond){
532  return pthread_cond_signal(cond) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
533 }
534 int faudes_cond_broadcast(faudes_cond_t *cond) {
535  return pthread_cond_signal(cond) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
536 }
537 int faudes_cond_wait(faudes_cond_t *cond, faudes_mutex_t *mtx) {
538  return pthread_cond_wait(cond, mtx) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
539 }
540 int faudes_cond_timedwait(faudes_cond_t *cond, faudes_mutex_t *mtx, const faudes_systime_t *abstime) {
541  int ret = pthread_cond_timedwait(cond, mtx, abstime);
542  if(ret == ETIMEDOUT) return FAUDES_THREAD_TIMEOUT;
543  return ret == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
544 }
545 // Extension: timed wait with duration as opposed to absolute time
546 int faudes_cond_reltimedwait(faudes_cond_t *cond, faudes_mutex_t *mtx, faudes_mstime_t duration) {
547  faudes_systime_t abstime;
548  faudes_msdelay(duration,&abstime);
549  return faudes_cond_timedwait(cond,mtx,&abstime);
550 }
551 #endif
552 #endif // POSIX condition
553 
554 
555 // Windows to mimique POSIX conditions
556 // The approach to condition variables on Windows is taken from
557 // "Strategies for Implementing POSIX Condition Variables on Win32"
558 // by Douglas C. Schmidt and Irfan Pyarali, Department of Computer
559 // Science, Washington University.
560 #ifdef FAUDES_THREADS
561 #ifdef FAUDES_WINDOWS
562 
563 // Convenience access my two condition events
564 #define EVENT_SIGNAL 0
565 #define EVENT_BROADCAST 1
566 
567 // Condition functions (Windows to mimic plain pthread)
568 int faudes_cond_init(faudes_cond_t* cond) {
569  // #waiters=0, with mutexed access
570  cond->mWaitersCount = 0;
571  InitializeCriticalSection(&cond->mWaitersCountMutex);
572  // auto-reset event to signal the condition
573  cond->mEvents[EVENT_SIGNAL]=CreateEvent(NULL, FALSE, FALSE, NULL);
574  // manual-reset event to broadcast the condition
575  cond->mEvents[EVENT_BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
576  // initialisation succeeded
577  if(cond->mEvents[EVENT_SIGNAL] != NULL)
578  if(cond->mEvents[EVENT_BROADCAST] != NULL)
579  return FAUDES_THREAD_SUCCESS;
580  // allow for destroy even on failed initialisation
581  if(cond->mEvents[EVENT_SIGNAL] != NULL)
582  CloseHandle(cond->mEvents[EVENT_SIGNAL]);
583  if(cond->mEvents[EVENT_BROADCAST] != NULL)
584  CloseHandle(cond->mEvents[EVENT_BROADCAST]);
585  cond->mEvents[EVENT_BROADCAST] = NULL;
586  cond->mEvents[EVENT_SIGNAL]=NULL;
587  return FAUDES_THREAD_ERROR;
588 }
589 
590 // Condition functions (Windows to mimic plain pthread)
591 void faudes_cond_destroy(faudes_cond_t* cond) {
592  if(cond->mEvents[EVENT_SIGNAL] != NULL)
593  CloseHandle(cond->mEvents[EVENT_SIGNAL]);
594  if(cond->mEvents[EVENT_BROADCAST] != NULL)
595  CloseHandle(cond->mEvents[EVENT_BROADCAST]);
596  DeleteCriticalSection(&cond->mWaitersCountMutex);
597 }
598 
599 // Condition functions (Windows to mimic plain pthread)
600 int faudes_cond_signal(faudes_cond_t *cond){
601  int waiters;
602  // any waiters ?
603  EnterCriticalSection(&cond->mWaitersCountMutex);
604  waiters = (cond->mWaitersCount > 0);
605  LeaveCriticalSection(&cond->mWaitersCountMutex);
606  // set event (one waiter will see the auto-reset event)
607  if(waiters){
608  if(SetEvent(cond->mEvents[EVENT_SIGNAL]) == 0)
609  return FAUDES_THREAD_ERROR;
610  }
611  return FAUDES_THREAD_SUCCESS;
612 }
613 
614 // Condition functions (Windows to mimic plain pthread)
615 int faudes_cond_broadcast(faudes_cond_t *cond) {
616  int waiters;
617  // any waiters ?
618  EnterCriticalSection(&cond->mWaitersCountMutex);
619  waiters = (cond->mWaitersCount > 0);
620  LeaveCriticalSection(&cond->mWaitersCountMutex);
621  // set event (all waiters will see, last waiter does the manual-reset)
622  if(waiters) {
623  if(SetEvent(cond->mEvents[EVENT_BROADCAST]) == 0)
624  return FAUDES_THREAD_ERROR;
625  }
626  return FAUDES_THREAD_SUCCESS;
627 }
628 
629 // Condition functions (Windows to mimic plain pthread)
630 int faudes_cond_reltimedwait(faudes_cond_t *cond, faudes_mutex_t *mtx, faudes_mstime_t duration) {
631  // increment #waiters
632  EnterCriticalSection(&cond->mWaitersCountMutex);
633  ++ cond->mWaitersCount;
634  LeaveCriticalSection(&cond->mWaitersCountMutex);
635  // release mutex while waiting
636  LeaveCriticalSection(mtx);
637  // wait for either event to be set
638  int res = WaitForMultipleObjects(2, cond->mEvents, FALSE, (DWORD) duration);
639  // maintane my data ...
640  EnterCriticalSection(&cond->mWaitersCountMutex);
641  // ... a) decrement #waiters
642  -- cond->mWaitersCount;
643  // ... b) test if this was a broadcast and we were the last waiter ...
644  int last =
645  (res == (WAIT_OBJECT_0 + EVENT_BROADCAST)) &&
646  (cond->mWaitersCount == 0);
647  LeaveCriticalSection(&cond->mWaitersCountMutex);
648  // ... c) if so, do a manual-reset of the event
649  if(last) ResetEvent(cond->mEvents[EVENT_BROADCAST]);
650  // reaquire mutex
651  EnterCriticalSection(mtx);
652  // uniform return value
653  if(res == (int) WAIT_TIMEOUT)
654  return FAUDES_THREAD_TIMEOUT;
655  if(res == (int) WAIT_FAILED)
656  return FAUDES_THREAD_ERROR;
657  return FAUDES_THREAD_SUCCESS;
658 }
659 
660 // Condition functions (Windows to mimic plain pthread)
661 int faudes_cond_wait(faudes_cond_t *cond, faudes_mutex_t *mtx) {
662  return faudes_cond_reltimedwait(cond, mtx, INFINITE);
663 }
664 
665 // Condition functions (Windows to mimic plain pthread)
666 int faudes_cond_timedwait(faudes_cond_t *cond, faudes_mutex_t *mtx, const faudes_systime_t *abstime) {
667  // get absolute time
668  faudes_systime_t now;
669  faudes_gettimeofday(&now);
670  // convert to rel. time in secs
671  DWORD rels = abstime->tv_sec - now.tv_sec;
672  // saturation on overflow
673  if(rels > (4294967295u/1000)-1) rels = 4294967295u/1000-1;
674  // convert to rel. time in msecs
675  DWORD relms = rels*1000 + (abstime->tv_nsec - now.tv_nsec + 500000) / 1000000;
676  // pass on to reltimedwait
677  return faudes_cond_reltimedwait(cond, mtx, relms);
678 }
679 
680 #endif
681 #endif // Windows conditions
682 
683 
684 
685 
686 
687 
688 
faudes_systime_t gPerfTimer1
const std::string & faudes_pathseps(void)
void faudes_usdelay(faudes_mstime_t usecs, faudes_systime_t *end)
int faudes_chdir(const std::string &nwd)
const char * faudes_strsignal(int sig)
void faudes_termsignal(void(*sighandler)(int))
std::string faudes_normpath(const std::string &rPath)
void faudes_sumsystime(const faudes_systime_t &begin, const faudes_systime_t &duration, faudes_systime_t *res)
void faudes_sleep(long int sec)
const std::string & faudes_pathsep(void)
std::string faudes_extpath(const std::string &rPath)
void faudes_invalid(const std::string &msg)
void faudes_usleep(long int usec)
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)
std::string faudes_getwd(void)

libFAUDES 2.33l --- 2025.09.16 --- c++ api documentaion by doxygen