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