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