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
34void 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
43const std::string& faudes_pathseps(void) {
44 static std::string faudes_pathsep_str = "/";
45 return faudes_pathsep_str;
46}
47const std::string& faudes_pathsep(void) {
48 return faudes_pathseps();
49}
50#endif
51#ifdef FAUDES_WINDOWS
52const std::string& faudes_pathseps(void) {
53 static std::string faudes_pathseps_str = "/\\:";
54 return faudes_pathseps_str;
55}
56const 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
64const std::string& faudes_pathseps(void) {
65 static std::string faudes_pathsep_str = "/";
66 return faudes_pathsep_str;
67}
68const 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)
75std::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
96std::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
116std::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}
124int 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>
130std::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}
138int 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
149std::string faudes_getwd(void) {
150 faudes_invalid("faudes_getwd()");
151 std::string res;
152 return res;
153}
154int faudes_chdir(const std::string& nwd) {
155 faudes_invalid("faudes_chdir()");
156 return -1;
157}
158#endif
159
160// Uniform signalhandler on termination
161void 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)
180const 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
190void faudes_sleep(long int sec) {sleep(sec);}
191void faudes_usleep(long int usec) {usleep(usec);}
192#endif
193#ifdef FAUDES_WINDOWS
194void faudes_sleep(long int sec) {Sleep((sec) * 1000);}
195void faudes_usleep(long int usec) {Sleep((usec) / 1000);}
196#endif
197#ifdef FAUDES_GENERIC
198void faudes_sleep(long int sec) { faudes_invalid("faudes_sleep()"); }
199void faudes_usleep(long int usec) { faudes_invalid("faudes_usleep()"); }
200#endif
201
202
203
204#ifdef FAUDES_SYSTIME
205
206// static debugging timer
207faudes_systime_t gPerfTimer1;
208
209// Uniform system time (using pthread timespec semantics, trust MinGW to provide)
210#if defined(FAUDES_POSIX)
211void 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)
220void 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)
231void 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)
241void 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)
247void 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)
257void 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)
267void 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
283int faudes_closesocket(int fd) {
284 return close(fd);
285}
286int faudes_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) {
287 return setsockopt(fd,level,optname,optval,optlen);
288}
289int faudes_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) {
290 return getsockopt(fd,level,optname,optval,optlen);
291}
292int 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}
299int 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
312typedef int socklen_t;
313int faudes_closesocket(int fd) {
314 return closesocket(fd);
315}
316int faudes_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) {
317 return setsockopt(fd,level,optname,(char*) optval,optlen);
318}
319int faudes_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) {
320 return getsockopt(fd,level,optname,(char*) optval,optlen);
321}
322int 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}
329int 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)
347typedef pthread_t faudes_thread_t;
348// Thread functions (plain pthread wrapper)
349int 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}
360faudes_thread_t faudes_thread_current(void) {
361 return pthread_self();
362}
363int faudes_thread_detach(faudes_thread_t thr) {
364 return pthread_detach(thr)==0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
365}
366int faudes_thread_equal(faudes_thread_t thr0, faudes_thread_t thr1) {
367 return pthread_equal(thr0, thr1);
368}
369void faudes_thread_exit(void* res) {
370 pthread_exit(res);
371}
372int 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
383DWORD faudes_thread_tlsidx=TLS_OUT_OF_INDEXES;
384
385// Windows thread function wrapper with faudes_thread_t argument;
386static 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)
403int 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)
423faudes_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)
431int 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)
439int 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)
448void 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)
457int 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
479int faudes_mutex_init(faudes_mutex_t* mtx){
480 return pthread_mutex_init(mtx, NULL)==0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
481}
482void faudes_mutex_destroy(faudes_mutex_t* mtx){
483 pthread_mutex_destroy(mtx);
484}
485int faudes_mutex_lock(faudes_mutex_t *mtx) {
486 return pthread_mutex_lock(mtx) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
487}
488int faudes_mutex_trylock(faudes_mutex_t *mtx){
489 return (pthread_mutex_trylock(mtx) == 0) ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
490}
491int 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
500int faudes_mutex_init(faudes_mutex_t *mtx){
501 InitializeCriticalSection(mtx);
502 return FAUDES_THREAD_SUCCESS;
503}
504void faudes_mutex_destroy(faudes_mutex_t *mtx){
505 DeleteCriticalSection(mtx);
506}
507int faudes_mutex_lock(faudes_mutex_t *mtx) {
508 EnterCriticalSection(mtx);
509 return FAUDES_THREAD_SUCCESS;
510}
511int faudes_mutex_trylock(faudes_mutex_t *mtx){
512 return TryEnterCriticalSection(mtx) ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
513}
514int 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
525int faudes_cond_init(faudes_cond_t* cond) {
526 return pthread_cond_init(cond, NULL) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
527}
528void faudes_cond_destroy(faudes_cond_t* cond) {
529 pthread_cond_destroy(cond);
530}
531int faudes_cond_signal(faudes_cond_t *cond){
532 return pthread_cond_signal(cond) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
533}
534int faudes_cond_broadcast(faudes_cond_t *cond) {
535 return pthread_cond_signal(cond) == 0 ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
536}
537int 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}
540int 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
546int 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)
568int 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)
591void 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)
600int 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)
615int 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)
630int 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)
661int 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)
666int 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
void faudes_usdelay(faudes_mstime_t usecs, faudes_systime_t *end)
int faudes_chdir(const std::string &nwd)
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_pathseps(void)
std::string faudes_extpath(const std::string &rPath)
void faudes_invalid(const std::string &msg)
const char * faudes_strsignal(int sig)
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)
const std::string & faudes_pathsep(void)
std::string faudes_getwd(void)

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