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 <signal.h>
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 #endif
184 #ifdef FAUDES_WINDOWS
185  return "unknown";
186 #endif
187 }
188 
189 // Uniform sleep for POSIX/Windows (see e.g. iodevice plug-in)
190 #ifdef FAUDES_POSIX
191 void faudes_sleep(long int sec) {sleep(sec);}
192 void faudes_usleep(long int usec) {usleep(usec);}
193 #endif
194 #ifdef FAUDES_WINDOWS
195 void faudes_sleep(long int sec) {Sleep((sec) * 1000);}
196 void faudes_usleep(long int usec) {Sleep((usec) / 1000);}
197 #endif
198 #ifdef FAUDES_GENERIC
199 void faudes_sleep(long int sec) { faudes_invalid("faudes_sleep()"); }
200 void faudes_usleep(long int usec) { faudes_invalid("faudes_usleep()"); }
201 #endif
202 
203 
204 
205 #ifdef FAUDES_SYSTIME
206 
207 // static debugging timer
208 faudes_systime_t gPerfTimer1;
209 
210 // Uniform system time (using pthread timespec semantics, trust MinGW to provide)
211 #if defined(FAUDES_POSIX)
212 void faudes_gettimeofday(faudes_systime_t* now) {
213  timeval nowval;
214  gettimeofday(&nowval,0);
215  now->tv_sec=nowval.tv_sec;
216  now->tv_nsec=nowval.tv_usec * 1000;
217 }
218 #endif
219 
220 #if defined(FAUDES_WINDOWS)
221 void faudes_gettimeofday(faudes_systime_t* now) {
222  DWORD nowval;
223  nowval= timeGetTime();
224  now->tv_sec=nowval / 1000;
225  now->tv_nsec=(nowval % 1000) *1000000;
226 }
227 #endif
228 
229 
230 
231 // Uniform system time (supporting functions)
232 void faudes_diffsystime(const faudes_systime_t& end, const faudes_systime_t& begin, faudes_systime_t* res) {
233  res->tv_sec = end.tv_sec-begin.tv_sec;
234  res->tv_nsec = end.tv_nsec-begin.tv_nsec;
235  if(res->tv_nsec <= 0){
236  res->tv_sec--;
237  res->tv_nsec += 1000000000;
238  }
239 }
240 
241 // Uniform system time (supporting functions)
242 void faudes_diffsystime(const faudes_systime_t& end, const faudes_systime_t& begin, faudes_mstime_t* res) {
243  *res = 1000*( end.tv_sec-begin.tv_sec);
244  *res += (end.tv_nsec-begin.tv_nsec) / 1000000;
245 }
246 
247 // Uniform system time (supporting functions)
248 void faudes_sumsystime(const faudes_systime_t& begin, const faudes_systime_t& duration, faudes_systime_t* res) {
249  res->tv_sec = begin.tv_sec + duration.tv_sec;
250  res->tv_nsec = begin.tv_nsec + duration.tv_nsec;
251  if(res->tv_nsec >= 1000000000) {
252  res->tv_sec++;
253  res->tv_nsec-=1000000000;
254  }
255 }
256 
257 // Uniform system time (supporting functions)
258 void faudes_msdelay(faudes_mstime_t msecs,faudes_systime_t* end) {
259  faudes_systime_t now;
260  faudes_gettimeofday(&now);
261  faudes_systime_t delta;
262  delta.tv_sec = msecs/1000;
263  delta.tv_nsec = (msecs % 1000) *1000000;
264  faudes_sumsystime(now,delta,end);
265 }
266 
267 // Uniform system time (supporting functions)
268 void faudes_usdelay(faudes_mstime_t usecs,faudes_systime_t* end) {
269  faudes_systime_t now;
270  faudes_gettimeofday(&now);
271  faudes_systime_t delta;
272  delta.tv_sec = usecs/1000000;
273  delta.tv_nsec = (usecs % 1000000) * 1000;
274  faudes_sumsystime(now,delta,end);
275 }
276 
277 
278 #endif // systime
279 
280 
281 #ifdef FAUDES_NETWORK
282 
283 #ifdef FAUDES_POSIX
284 int faudes_closesocket(int fd) {
285  return close(fd);
286 }
287 int faudes_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) {
288  return setsockopt(fd,level,optname,optval,optlen);
289 }
290 int faudes_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) {
291  return getsockopt(fd,level,optname,optval,optlen);
292 }
293 int faudes_getsocket_error(int fd) {
294  int opt=0;
295  socklen_t len = sizeof(opt);
296  int res = getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &len) < 0 ? -1 : 0;
297  if(opt!=0) res=-1;
298  return res;
299 }
300 int faudes_setsocket_nonblocking(int fd, bool noblo) {
301  int sopt=fcntl(fd, F_GETFL, NULL);
302  if(sopt<0) return -1; // error
303  if(noblo) {
304  int rc=fcntl(fd, F_SETFL, sopt|O_NONBLOCK);
305  return rc < 0 ? -1 : 0;
306  } else {
307  int rc=fcntl(fd, F_SETFL, sopt& (~O_NONBLOCK));
308  return rc < 0 ? -1 : 0;
309  }
310 }
311 #endif
312 #ifdef FAUDES_WINDOWS
313 typedef int socklen_t;
314 int faudes_closesocket(int fd) {
315  return closesocket(fd);
316 }
317 int faudes_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) {
318  return setsockopt(fd,level,optname,(char*) optval,optlen);
319 }
320 int faudes_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) {
321  return getsockopt(fd,level,optname,(char*) optval,optlen);
322 }
323 int faudes_getsocket_error(int fd) {
324  int opt=0;
325  socklen_t len = sizeof(opt);
326  int res = getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0 ? -1 : 0;
327  if(opt!=0) res=-1;
328  return res;
329 }
330 int faudes_setsocket_nonblocking(int fd, bool noblo) {
331  unsigned long onoff=0;
332  if(noblo) onoff=1;
333  return ioctlsocket(fd, FIONBIO, &onoff) == SOCKET_ERROR ? -1 : 0;
334 }
335 #endif
336 #ifdef FAUDES_GENERIC
337 #error option network not available on generic platform
338 #endif
339 
340 #endif // network
341 
342 
343 
344 // straight PPOSIX threads (aka plain wrappers)
345 #ifdef FAUDES_THREADS
346 #ifdef FAUDES_POSIX
347 // Thread data type (use plain POSIX thread)
348 typedef pthread_t faudes_thread_t;
349 // Thread functions (plain pthread wrapper)
350 int faudes_thread_create(faudes_thread_t *thr, void *(*fnct)(void *), void *arg){
351  // prepare attribute for plain joinable thread
352  pthread_attr_t attr;
353  pthread_attr_init(&attr);
354  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
355  // start execute
356  int ret = pthread_create(thr, &attr, fnct, arg);
357  // done
358  pthread_attr_destroy(&attr);
359  return ret == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
360 }
361 faudes_thread_t faudes_thread_current(void) {
362  return pthread_self();
363 }
364 int faudes_thread_detach(faudes_thread_t thr) {
365  return pthread_detach(thr)==0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
366 }
367 int faudes_thread_equal(faudes_thread_t thr0, faudes_thread_t thr1) {
368  return pthread_equal(thr0, thr1);
369 }
370 void faudes_thread_exit(void* res) {
371  pthread_exit(res);
372 }
373 int faudes_thread_join(faudes_thread_t thr, void **res) {
374  return pthread_join(thr, res) == 0 ? FAUDES_THREAD_ERROR : FAUDES_THREAD_SUCCESS;
375 }
376 #endif
377 #endif // POSIX threads
378 
379 // Windows to mimique PPOSIX threads
380 #ifdef FAUDES_THREADS
381 #ifdef FAUDES_WINDOWS
382 
383 // Use Windows thread local storage to implement pointer-typed return values
384 DWORD faudes_thread_tlsidx=TLS_OUT_OF_INDEXES;
385 
386 // Windows thread function wrapper with faudes_thread_t argument;
387 static unsigned WINAPI faudes_thread_wrapper(void *argfth) {
388  // access my thread struct
389  faudes_thread_t fthread = (faudes_thread_t) argfth;
390  // record my thread struct as tls
391  TlsSetValue(faudes_thread_tlsidx,fthread);
392  // extract actual function and arguments
393  void *(*fnct)(void*) = fthread->mFnct;
394  void *arg = fthread->mArg;
395  // call function
396  void* res = fnct(arg);
397  // uniform exit to retrieve return value
398  faudes_thread_exit(res);
399  // return dummy
400  return 0;
401 }
402 
403 // Thread functions (Windows to mimic pthreads)
404 int faudes_thread_create(faudes_thread_t *thr, void *(*fnct)(void *), void *arg){
405  // initialize thread local storage block
406  if(faudes_thread_tlsidx==TLS_OUT_OF_INDEXES)
407  faudes_thread_tlsidx=TlsAlloc();
408  if(faudes_thread_tlsidx==TLS_OUT_OF_INDEXES)
409  return FAUDES_THREAD_ERROR;
410  // malloc my thread structure
411  *thr = (faudes_thread_t) malloc(sizeof(faudes_thread_record_t));
412  if(!*thr) return FAUDES_THREAD_ERROR;
413  // initialze my thread structure with function and argument
414  (*thr)->mFnct = fnct;
415  (*thr)->mArg = arg;
416  (*thr)->mRes = NULL;
417  // start the thread
418  (*thr)->mHandle = (HANDLE) _beginthreadex(NULL, 0, faudes_thread_wrapper, (void*) (*thr), 0, NULL);
419  // done
420  return (*thr)->mHandle ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
421 }
422 
423 // Thread functions (Windows to mimic pthreads)
424 faudes_thread_t faudes_thread_current(void) {
425  // retrieve my thread struct from tls
426  faudes_thread_t fthread = (faudes_thread_t) TlsGetValue(faudes_thread_tlsidx);
427  // note: returns NULL for parent thread
428  return fthread;
429 }
430 
431 // Thread functions (Windows to mimic pthreads)
432 int faudes_thread_detach(faudes_thread_t thr) {
433  CloseHandle(thr->mHandle);
434  // free my mem
435  free(thr);
436  return FAUDES_THREAD_SUCCESS;
437 }
438 
439 // Thread functions (Windows to mimic pthreads)
440 int faudes_thread_equal(faudes_thread_t thr0, faudes_thread_t thr1) {
441  // the parent thread has no tls record and thus reports NULL
442  if( (thr0==NULL) && (thr1=NULL) ) return true;
443  if( (thr0==NULL) || (thr1=NULL) ) return false;
444  // std case, compare by handle
445  return thr0->mHandle == thr1->mHandle;
446 }
447 
448 // Thread functions (Windows to mimic pthreads)
449 void faudes_thread_exit(void *res) {
450  // retrieve thread structure from tls to pass on result
451  faudes_thread_t fthread = (faudes_thread_t) TlsGetValue(faudes_thread_tlsidx);
452  if(fthread) fthread->mRes=res;
453  // call winapi
454  ExitThread(0);
455 }
456 
457 // Thread functions (Windows to mimic pthreads)
458 int faudes_thread_join(faudes_thread_t thr, void **res) {
459  // default result
460  if(res) *res = 0;
461  // do the join
462  DWORD rc = WaitForSingleObject(thr->mHandle, INFINITE);
463  // retrieve result from thread structure
464  if( (rc!=WAIT_FAILED) && (res)) *res = thr->mRes;
465  // free mem
466  free(thr);
467  // done
468  if(rc == WAIT_FAILED) return FAUDES_THREAD_ERROR;
469  return FAUDES_THREAD_SUCCESS;
470 }
471 
472 #endif
473 #endif // Windows threads
474 
475 
476 
477 // straight PPOSIX mutexes (aka plain wrappers)
478 #ifdef FAUDES_THREADS
479 #ifdef FAUDES_POSIX
480 int faudes_mutex_init(faudes_mutex_t* mtx){
481  return pthread_mutex_init(mtx, NULL)==0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
482 }
483 void faudes_mutex_destroy(faudes_mutex_t* mtx){
484  pthread_mutex_destroy(mtx);
485 }
486 int faudes_mutex_lock(faudes_mutex_t *mtx) {
487  return pthread_mutex_lock(mtx) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
488 }
489 int faudes_mutex_trylock(faudes_mutex_t *mtx){
490  return (pthread_mutex_trylock(mtx) == 0) ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
491 }
492 int faudes_mutex_unlock(faudes_mutex_t *mtx){
493  return pthread_mutex_unlock(mtx) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
494 }
495 #endif
496 #endif // POSIX mutexes
497 
498 // Windows to mimique PPOSIX mutexes
499 #ifdef FAUDES_THREADS
500 #ifdef FAUDES_WINDOWS
501 int faudes_mutex_init(faudes_mutex_t *mtx){
502  InitializeCriticalSection(mtx);
503  return FAUDES_THREAD_SUCCESS;
504 }
505 void faudes_mutex_destroy(faudes_mutex_t *mtx){
506  DeleteCriticalSection(mtx);
507 }
508 int faudes_mutex_lock(faudes_mutex_t *mtx) {
509  EnterCriticalSection(mtx);
510  return FAUDES_THREAD_SUCCESS;
511 }
512 int faudes_mutex_trylock(faudes_mutex_t *mtx){
513  return TryEnterCriticalSection(mtx) ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
514 }
515 int faudes_mutex_unlock(faudes_mutex_t *mtx){
516  LeaveCriticalSection(mtx);
517  return FAUDES_THREAD_SUCCESS;
518 }
519 #endif
520 #endif // Windows mutexes
521 
522 
523 // straight PPOSIX conditions (aka plain wrappers)
524 #ifdef FAUDES_THREADS
525 #ifdef FAUDES_POSIX
526 int faudes_cond_init(faudes_cond_t* cond) {
527  return pthread_cond_init(cond, NULL) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
528 }
529 void faudes_cond_destroy(faudes_cond_t* cond) {
530  pthread_cond_destroy(cond);
531 }
532 int faudes_cond_signal(faudes_cond_t *cond){
533  return pthread_cond_signal(cond) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
534 }
535 int faudes_cond_broadcast(faudes_cond_t *cond) {
536  return pthread_cond_signal(cond) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
537 }
538 int faudes_cond_wait(faudes_cond_t *cond, faudes_mutex_t *mtx) {
539  return pthread_cond_wait(cond, mtx) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
540 }
541 int faudes_cond_timedwait(faudes_cond_t *cond, faudes_mutex_t *mtx, const faudes_systime_t *abstime) {
542  int ret = pthread_cond_timedwait(cond, mtx, abstime);
543  if(ret == ETIMEDOUT) return FAUDES_THREAD_TIMEOUT;
544  return ret == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
545 }
546 // Extension: timed wait with duration as opposed to absolute time
547 int faudes_cond_reltimedwait(faudes_cond_t *cond, faudes_mutex_t *mtx, faudes_mstime_t duration) {
548  faudes_systime_t abstime;
549  faudes_msdelay(duration,&abstime);
550  return faudes_cond_timedwait(cond,mtx,&abstime);
551 }
552 #endif
553 #endif // POSIX condition
554 
555 
556 // Windows to mimique POSIX conditions
557 // The approach to condition variables on Windows is taken from
558 // "Strategies for Implementing POSIX Condition Variables on Win32"
559 // by Douglas C. Schmidt and Irfan Pyarali, Department of Computer
560 // Science, Washington University.
561 #ifdef FAUDES_THREADS
562 #ifdef FAUDES_WINDOWS
563 
564 // Convenience access my two condition events
565 #define EVENT_SIGNAL 0
566 #define EVENT_BROADCAST 1
567 
568 // Condition functions (Windows to mimic plain pthread)
569 int faudes_cond_init(faudes_cond_t* cond) {
570  // #waiters=0, with mutexed access
571  cond->mWaitersCount = 0;
572  InitializeCriticalSection(&cond->mWaitersCountMutex);
573  // auto-reset event to signal the condition
574  cond->mEvents[EVENT_SIGNAL]=CreateEvent(NULL, FALSE, FALSE, NULL);
575  // manual-reset event to broadcast the condition
576  cond->mEvents[EVENT_BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
577  // initialisation succeeded
578  if(cond->mEvents[EVENT_SIGNAL] != NULL)
579  if(cond->mEvents[EVENT_BROADCAST] != NULL)
580  return FAUDES_THREAD_SUCCESS;
581  // allow for destroy even on failed initialisation
582  if(cond->mEvents[EVENT_SIGNAL] != NULL)
583  CloseHandle(cond->mEvents[EVENT_SIGNAL]);
584  if(cond->mEvents[EVENT_BROADCAST] != NULL)
585  CloseHandle(cond->mEvents[EVENT_BROADCAST]);
586  cond->mEvents[EVENT_BROADCAST] = NULL;
587  cond->mEvents[EVENT_SIGNAL]=NULL;
588  return FAUDES_THREAD_ERROR;
589 }
590 
591 // Condition functions (Windows to mimic plain pthread)
592 void faudes_cond_destroy(faudes_cond_t* cond) {
593  if(cond->mEvents[EVENT_SIGNAL] != NULL)
594  CloseHandle(cond->mEvents[EVENT_SIGNAL]);
595  if(cond->mEvents[EVENT_BROADCAST] != NULL)
596  CloseHandle(cond->mEvents[EVENT_BROADCAST]);
597  DeleteCriticalSection(&cond->mWaitersCountMutex);
598 }
599 
600 // Condition functions (Windows to mimic plain pthread)
601 int faudes_cond_signal(faudes_cond_t *cond){
602  int waiters;
603  // any waiters ?
604  EnterCriticalSection(&cond->mWaitersCountMutex);
605  waiters = (cond->mWaitersCount > 0);
606  LeaveCriticalSection(&cond->mWaitersCountMutex);
607  // set event (one waiter will see the auto-reset event)
608  if(waiters){
609  if(SetEvent(cond->mEvents[EVENT_SIGNAL]) == 0)
610  return FAUDES_THREAD_ERROR;
611  }
612  return FAUDES_THREAD_SUCCESS;
613 }
614 
615 // Condition functions (Windows to mimic plain pthread)
616 int faudes_cond_broadcast(faudes_cond_t *cond) {
617  int waiters;
618  // any waiters ?
619  EnterCriticalSection(&cond->mWaitersCountMutex);
620  waiters = (cond->mWaitersCount > 0);
621  LeaveCriticalSection(&cond->mWaitersCountMutex);
622  // set event (all waiters will see, last waiter does the manual-reset)
623  if(waiters) {
624  if(SetEvent(cond->mEvents[EVENT_BROADCAST]) == 0)
625  return FAUDES_THREAD_ERROR;
626  }
627  return FAUDES_THREAD_SUCCESS;
628 }
629 
630 // Condition functions (Windows to mimic plain pthread)
631 int faudes_cond_reltimedwait(faudes_cond_t *cond, faudes_mutex_t *mtx, faudes_mstime_t duration) {
632  // increment #waiters
633  EnterCriticalSection(&cond->mWaitersCountMutex);
634  ++ cond->mWaitersCount;
635  LeaveCriticalSection(&cond->mWaitersCountMutex);
636  // release mutex while waiting
637  LeaveCriticalSection(mtx);
638  // wait for either event to be set
639  int res = WaitForMultipleObjects(2, cond->mEvents, FALSE, (DWORD) duration);
640  // maintane my data ...
641  EnterCriticalSection(&cond->mWaitersCountMutex);
642  // ... a) decrement #waiters
643  -- cond->mWaitersCount;
644  // ... b) test if this was a broadcast and we were the last waiter ...
645  int last =
646  (res == (WAIT_OBJECT_0 + EVENT_BROADCAST)) &&
647  (cond->mWaitersCount == 0);
648  LeaveCriticalSection(&cond->mWaitersCountMutex);
649  // ... c) if so, do a manual-reset of the event
650  if(last) ResetEvent(cond->mEvents[EVENT_BROADCAST]);
651  // reaquire mutex
652  EnterCriticalSection(mtx);
653  // uniform return value
654  if(res == (int) WAIT_TIMEOUT)
655  return FAUDES_THREAD_TIMEOUT;
656  if(res == (int) WAIT_FAILED)
657  return FAUDES_THREAD_ERROR;
658  return FAUDES_THREAD_SUCCESS;
659 }
660 
661 // Condition functions (Windows to mimic plain pthread)
662 int faudes_cond_wait(faudes_cond_t *cond, faudes_mutex_t *mtx) {
663  return faudes_cond_reltimedwait(cond, mtx, INFINITE);
664 }
665 
666 // Condition functions (Windows to mimic plain pthread)
667 int faudes_cond_timedwait(faudes_cond_t *cond, faudes_mutex_t *mtx, const faudes_systime_t *abstime) {
668  // get absolute time
669  faudes_systime_t now;
670  faudes_gettimeofday(&now);
671  // convert to rel. time in secs
672  DWORD rels = abstime->tv_sec - now.tv_sec;
673  // saturation on overflow
674  if(rels > (4294967295u/1000)-1) rels = 4294967295u/1000-1;
675  // convert to rel. time in msecs
676  DWORD relms = rels*1000 + (abstime->tv_nsec - now.tv_nsec + 500000) / 1000000;
677  // pass on to reltimedwait
678  return faudes_cond_reltimedwait(cond, mtx, relms);
679 }
680 
681 #endif
682 #endif // Windows conditions
683 
684 
685 
686 
687 
688 
689 
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.33h --- 2025.06.18 --- c++ api documentaion by doxygen