cfl_platform.cppGo to the documentation of this file.00001 /** @file cfl_platform.cpp Platform dependant wrappers */ 00002 00003 /* FAU Discrete Event Systems Library (libfaudes) 00004 00005 Copyright (C) 2013 Thomas Moor 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Lesser General Public 00009 License as published by the Free Software Foundation; either 00010 version 2.1 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU 00015 Lesser General Public License for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public 00018 License along with this library; if not, write to the Free Software 00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 00023 00024 // My header 00025 #include "cfl_definitions.h" 00026 #include "cfl_platform.h" 00027 00028 // Extra header 00029 #include <signal.h> 00030 00031 00032 // Path separator (statics, see faudes_pathsep) 00033 #ifdef FAUDES_POSIX 00034 const std::string faudes_pathseps_str = "/"; 00035 const std::string faudes_pathsep_str = "/"; 00036 #endif 00037 #ifdef FAUDES_WINDOWS 00038 const std::string faudes_pathseps_str = "\\:/"; 00039 const std::string faudes_pathsep_str = "\\"; 00040 #endif 00041 00042 00043 // Uniform signalhandler on termination 00044 void faudes_termsignal(void (*sighandler)(int)) { 00045 #ifdef SIGTERM 00046 signal(SIGTERM, sighandler); 00047 #endif 00048 #ifdef SIGINT 00049 signal(SIGINT, sighandler); 00050 #endif 00051 #ifdef SIGQUIT 00052 signal(SIGQUIT, sighandler); 00053 #endif 00054 #ifdef SIGHUP 00055 signal(SIGHUP, sighandler); 00056 #endif 00057 #ifdef SIGABRT 00058 signal(SIGABRT, sighandler); 00059 #endif 00060 } 00061 00062 // Uniform signal names for POSIX / Windows/MinGW (see e.g. simfaudes.cpp) 00063 const char* faudes_strsignal(int sig) { 00064 #ifdef FAUDES_POSIX 00065 return strsignal(sig); 00066 #endif 00067 #ifdef FAUDES_WINDOWS 00068 return "unknown"; 00069 #endif 00070 } 00071 00072 00073 #ifdef FAUDES_SYSTIME 00074 00075 // static debugging timer 00076 faudes_systime_t gPerfTimer1; 00077 00078 // Uniform system time (using pthread timespec semantics, trust MinGW to provide) 00079 #if defined(FAUDES_POSIX) || defined(FAUDES_WINDOWS) 00080 void faudes_gettimeofday(faudes_systime_t* now) { 00081 timeval nowval; 00082 gettimeofday(&nowval,0); 00083 now->tv_sec=nowval.tv_sec; 00084 now->tv_nsec=nowval.tv_usec * 1000; 00085 } 00086 #endif 00087 00088 // Uniform system time (supporting functions) 00089 void faudes_diffsystime(const faudes_systime_t& end, const faudes_systime_t& begin, faudes_systime_t* res) { 00090 res->tv_sec = end.tv_sec-begin.tv_sec; 00091 res->tv_nsec = end.tv_nsec-begin.tv_nsec; 00092 if(res->tv_nsec <= 0){ 00093 res->tv_sec--; 00094 res->tv_nsec += 1000000000; 00095 } 00096 } 00097 00098 // Uniform system time (supporting functions) 00099 void faudes_diffsystime(const faudes_systime_t& end, const faudes_systime_t& begin, faudes_mstime_t* res) { 00100 *res = 1000*( end.tv_sec-begin.tv_sec); 00101 *res += (end.tv_nsec-begin.tv_nsec) / 1000000; 00102 } 00103 00104 // Uniform system time (supporting functions) 00105 void faudes_sumsystime(const faudes_systime_t& begin, const faudes_systime_t& duration, faudes_systime_t* res) { 00106 res->tv_sec = begin.tv_sec + duration.tv_sec; 00107 res->tv_nsec = begin.tv_nsec + duration.tv_nsec; 00108 if(res->tv_nsec >= 1000000000) { 00109 res->tv_sec++; 00110 res->tv_nsec-=1000000000; 00111 } 00112 } 00113 00114 // Uniform system time (supporting functions) 00115 void faudes_msdelay(faudes_mstime_t msecs,faudes_systime_t* end) { 00116 faudes_systime_t now; 00117 faudes_gettimeofday(&now); 00118 faudes_systime_t delta; 00119 delta.tv_sec = msecs/1000; 00120 delta.tv_nsec = (msecs % 1000) *1000000; 00121 faudes_sumsystime(now,delta,end); 00122 } 00123 00124 // Uniform system time (supporting functions) 00125 void faudes_usdelay(faudes_mstime_t usecs,faudes_systime_t* end) { 00126 faudes_systime_t now; 00127 faudes_gettimeofday(&now); 00128 faudes_systime_t delta; 00129 delta.tv_sec = usecs/1000000; 00130 delta.tv_nsec = (usecs % 1000000) * 1000; 00131 faudes_sumsystime(now,delta,end); 00132 } 00133 00134 00135 #endif // systime 00136 00137 00138 #ifdef FAUDES_NETWORK 00139 00140 00141 // Uniform socketoption: test for error 00142 int faudes_getsocket_error(int fd) { 00143 #ifdef FAUDES_POSIX 00144 int opt=0; 00145 socklen_t len = sizeof(opt); 00146 int res = getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &len) < 0 ? -1 : 0; 00147 if(opt!=0) res=-1; 00148 return res; 00149 #endif 00150 #ifdef FAUDES_WINDOWS 00151 int opt=0; 00152 socklen_t len = sizeof(opt); 00153 int res = getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0 ? -1 : 0; 00154 if(opt!=0) res=-1; 00155 return res; 00156 #endif 00157 } 00158 00159 // Uniform socketoption: set nonblocking 00160 int faudes_setsocket_nonblocking(int fd, bool noblo) { 00161 #ifdef FAUDES_POSIX 00162 int sopt=fcntl(fd, F_GETFL, NULL); 00163 if(sopt<0) return -1; // error 00164 if(noblo) { 00165 int rc=fcntl(fd, F_SETFL, sopt|O_NONBLOCK); 00166 return rc < 0 ? -1 : 0; 00167 } else { 00168 int rc=fcntl(fd, F_SETFL, sopt& (~O_NONBLOCK)); 00169 return rc < 0 ? -1 : 0; 00170 } 00171 #endif 00172 #ifdef FAUDES_WINDOWS 00173 unsigned long onoff=0; 00174 if(noblo) onoff=1; 00175 return ioctlsocket(fd, FIONBIO, &onoff) == SOCKET_ERROR ? -1 : 0; 00176 #endif 00177 } 00178 00179 00180 00181 00182 00183 00184 #endif // network 00185 00186 00187 #ifdef FAUDES_THREADS 00188 00189 00190 // Use Windows thread local storage to implement pointer-typed return values 00191 #ifdef FAUDES_WINDOWS 00192 DWORD faudes_thread_tlsidx=TLS_OUT_OF_INDEXES; 00193 #endif 00194 00195 // Windows thread function wrapper with faudes_thread_t argument; 00196 #ifdef FAUDES_WINDOWS 00197 static unsigned WINAPI faudes_thread_wrapper(void *argfth) { 00198 // access my thread struct 00199 faudes_thread_t fthread = (faudes_thread_t) argfth; 00200 // record my thread struct as tls 00201 TlsSetValue(faudes_thread_tlsidx,fthread); 00202 // extract actual function an arguments 00203 void *(*fnct)(void*) = fthread->mFnct; 00204 void *arg = fthread->mArg; 00205 // call function 00206 void* res = fnct(arg); 00207 // uniform exit to retrieve return value 00208 faudes_thread_exit(res); 00209 // return dummy 00210 return 0; 00211 } 00212 #endif 00213 00214 // Thread functions (Windows to mimic pthreads) 00215 #ifdef FAUDES_WINDOWS 00216 int faudes_thread_create(faudes_thread_t *thr, void *(*fnct)(void *), void *arg){ 00217 // initialize thread local storage block 00218 if(faudes_thread_tlsidx==TLS_OUT_OF_INDEXES) 00219 faudes_thread_tlsidx=TlsAlloc(); 00220 if(faudes_thread_tlsidx==TLS_OUT_OF_INDEXES) 00221 return FAUDES_THREAD_ERROR; 00222 // malloc my thread structure 00223 *thr = (faudes_thread_t) malloc(sizeof(faudes_thread_record_t)); 00224 if(!*thr) return FAUDES_THREAD_ERROR; 00225 // initialze my thread structure with function and argument 00226 (*thr)->mFnct = fnct; 00227 (*thr)->mArg = arg; 00228 (*thr)->mRes = NULL; 00229 // start the thread 00230 (*thr)->mHandle = (HANDLE) _beginthreadex(NULL, 0, faudes_thread_wrapper, (void*) (*thr), 0, NULL); 00231 // done 00232 return (*thr)->mHandle ? FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR; 00233 } 00234 #endif 00235 00236 #ifdef FAUDES_WINDOWS 00237 // Thread functions (Windows to mimic pthreads) 00238 faudes_thread_t faudes_thread_current(void) { 00239 // retrieve my thread struct from tls 00240 faudes_thread_t fthread = (faudes_thread_t) TlsGetValue(faudes_thread_tlsidx); 00241 // note: returns NULL for parent thread 00242 return fthread; 00243 } 00244 #endif 00245 00246 #ifdef FAUDES_WINDOWS 00247 // Thread functions (Windows to mimic pthreads) 00248 int faudes_thread_detach(faudes_thread_t thr) { 00249 CloseHandle(thr->mHandle); 00250 // free my mem 00251 free(thr); 00252 return FAUDES_THREAD_SUCCESS; 00253 } 00254 #endif 00255 00256 #ifdef FAUDES_WINDOWS 00257 // Thread functions (Windows to mimic pthreads) 00258 int faudes_thread_equal(faudes_thread_t thr0, faudes_thread_t thr1) { 00259 // the parent thread has no tls record and thus reports NULL 00260 if( (thr0==NULL) && (thr1=NULL) ) return true; 00261 if( (thr0==NULL) || (thr1=NULL) ) return false; 00262 // std case, compare by handle 00263 return thr0->mHandle == thr1->mHandle; 00264 } 00265 #endif 00266 00267 #ifdef FAUDES_WINDOWS 00268 // Thread functions (Windows to mimic pthreads) 00269 void faudes_thread_exit(void *res) { 00270 // retrieve thread structure from tls to pass on result 00271 faudes_thread_t fthread = (faudes_thread_t) TlsGetValue(faudes_thread_tlsidx); 00272 if(fthread) fthread->mRes=res; 00273 // call winapi 00274 ExitThread(0); 00275 } 00276 #endif 00277 00278 #ifdef FAUDES_WINDOWS 00279 // Thread functions (Windows to mimic pthreads) 00280 int faudes_thread_join(faudes_thread_t thr, void **res) { 00281 // default result 00282 if(res) *res = 0; 00283 // do the join 00284 DWORD rc = WaitForSingleObject(thr->mHandle, INFINITE); 00285 // retrieve result from thread structure 00286 if( (rc!=WAIT_FAILED) && (res)) *res = thr->mRes; 00287 // free mem 00288 free(thr); 00289 // done 00290 if(rc == WAIT_FAILED) return FAUDES_THREAD_ERROR; 00291 return FAUDES_THREAD_SUCCESS; 00292 } 00293 #endif 00294 00295 // The approach to condition variables on Windows is taken from 00296 // "Strategies for Implementing POSIX Condition Variables on Win32" 00297 // by Douglas C. Schmidt and Irfan Pyarali, Department of Computer 00298 // Science, Washington University. 00299 00300 // Convenience access my two condition events 00301 #ifdef FAUDES_WINDOWS 00302 #define EVENT_SIGNAL 0 00303 #define EVENT_BROADCAST 1 00304 #endif 00305 00306 // Condition functions (Windows to mimic plain pthread) 00307 #ifdef FAUDES_WINDOWS 00308 int faudes_cond_init(faudes_cond_t* cond) { 00309 // #waiters=0, with mutexed access 00310 cond->mWaitersCount = 0; 00311 InitializeCriticalSection(&cond->mWaitersCountMutex); 00312 // auto-reset event to signal the condition 00313 cond->mEvents[EVENT_SIGNAL]=CreateEvent(NULL, FALSE, FALSE, NULL); 00314 // manual-reset event to broadcast the condition 00315 cond->mEvents[EVENT_BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL); 00316 // initialisation succeeded 00317 if(cond->mEvents[EVENT_SIGNAL] != NULL) 00318 if(cond->mEvents[EVENT_BROADCAST] != NULL) 00319 return FAUDES_THREAD_SUCCESS; 00320 // allow for destroy even on failed initialisation 00321 if(cond->mEvents[EVENT_SIGNAL] != NULL) 00322 CloseHandle(cond->mEvents[EVENT_SIGNAL]); 00323 if(cond->mEvents[EVENT_BROADCAST] != NULL) 00324 CloseHandle(cond->mEvents[EVENT_BROADCAST]); 00325 cond->mEvents[EVENT_BROADCAST] = NULL; 00326 cond->mEvents[EVENT_SIGNAL]=NULL; 00327 return FAUDES_THREAD_ERROR; 00328 } 00329 #endif 00330 00331 #ifdef FAUDES_WINDOWS 00332 // Condition functions (Windows to mimic plain pthread) 00333 void faudes_cond_destroy(faudes_cond_t* cond) { 00334 if(cond->mEvents[EVENT_SIGNAL] != NULL) 00335 CloseHandle(cond->mEvents[EVENT_SIGNAL]); 00336 if(cond->mEvents[EVENT_BROADCAST] != NULL) 00337 CloseHandle(cond->mEvents[EVENT_BROADCAST]); 00338 DeleteCriticalSection(&cond->mWaitersCountMutex); 00339 } 00340 #endif 00341 00342 #ifdef FAUDES_WINDOWS 00343 // Condition functions (Windows to mimic plain pthread) 00344 int faudes_cond_signal(faudes_cond_t *cond){ 00345 int waiters; 00346 // any waiters ? 00347 EnterCriticalSection(&cond->mWaitersCountMutex); 00348 waiters = (cond->mWaitersCount > 0); 00349 LeaveCriticalSection(&cond->mWaitersCountMutex); 00350 // set event (one waiter will see the auto-reset event) 00351 if(waiters){ 00352 if(SetEvent(cond->mEvents[EVENT_SIGNAL]) == 0) 00353 return FAUDES_THREAD_ERROR; 00354 } 00355 return FAUDES_THREAD_SUCCESS; 00356 } 00357 #endif 00358 00359 #ifdef FAUDES_WINDOWS 00360 // Condition functions (Windows to mimic plain pthread) 00361 int faudes_cond_broadcast(faudes_cond_t *cond) { 00362 int waiters; 00363 // any waiters ? 00364 EnterCriticalSection(&cond->mWaitersCountMutex); 00365 waiters = (cond->mWaitersCount > 0); 00366 LeaveCriticalSection(&cond->mWaitersCountMutex); 00367 // set event (all waiters will see, last waiter does the manual-reset) 00368 if(waiters) { 00369 if(SetEvent(cond->mEvents[EVENT_BROADCAST]) == 0) 00370 return FAUDES_THREAD_ERROR; 00371 } 00372 return FAUDES_THREAD_SUCCESS; 00373 } 00374 #endif 00375 00376 #ifdef FAUDES_WINDOWS 00377 // Condition functions (Windows to mimic plain pthread) 00378 int faudes_cond_reltimedwait(faudes_cond_t *cond, faudes_mutex_t *mtx, faudes_mstime_t duration) { 00379 // increment #waiters 00380 EnterCriticalSection(&cond->mWaitersCountMutex); 00381 ++ cond->mWaitersCount; 00382 LeaveCriticalSection(&cond->mWaitersCountMutex); 00383 // release mutex while waiting 00384 LeaveCriticalSection(mtx); 00385 // wait for either event to be set 00386 int res = WaitForMultipleObjects(2, cond->mEvents, FALSE, (DWORD) duration); 00387 // maintane my data ... 00388 EnterCriticalSection(&cond->mWaitersCountMutex); 00389 // ... a) decrement #waiters 00390 -- cond->mWaitersCount; 00391 // ... b) test if this was a broadcast and we were the last waiter ... 00392 int last = 00393 (res == (WAIT_OBJECT_0 + EVENT_BROADCAST)) && 00394 (cond->mWaitersCount == 0); 00395 LeaveCriticalSection(&cond->mWaitersCountMutex); 00396 // ... c) if so, do a manual-reset of the event 00397 if(last) ResetEvent(cond->mEvents[EVENT_BROADCAST]); 00398 // reaquire mutex 00399 EnterCriticalSection(mtx); 00400 // uniform return value 00401 if(res == (int) WAIT_TIMEOUT) 00402 return FAUDES_THREAD_TIMEOUT; 00403 if(res == (int) WAIT_FAILED) 00404 return FAUDES_THREAD_ERROR; 00405 return FAUDES_THREAD_SUCCESS; 00406 } 00407 #endif 00408 00409 #ifdef FAUDES_WINDOWS 00410 // Condition functions (Windows to mimic plain pthread) 00411 int faudes_cond_wait(faudes_cond_t *cond, faudes_mutex_t *mtx) { 00412 return faudes_cond_reltimedwait(cond, mtx, INFINITE); 00413 } 00414 #endif 00415 00416 #ifdef FAUDES_WINDOWS 00417 // Condition functions (Windows to mimic plain pthread) 00418 int faudes_cond_timedwait(faudes_cond_t *cond, faudes_mutex_t *mtx, const faudes_systime_t *abstime) { 00419 // get absolute time 00420 faudes_systime_t now; 00421 faudes_gettimeofday(&now); 00422 // convert to rel. time in secs 00423 DWORD rels = abstime->tv_sec - now.tv_sec; 00424 // saturation on overflow 00425 if(rels > (4294967295u/1000)-1) rels = 4294967295u/1000-1; 00426 // convert to rel. time in msecs 00427 DWORD relms = rels*1000 + (abstime->tv_nsec - now.tv_nsec + 500000) / 1000000; 00428 // pass on to reltimedwait 00429 return faudes_cond_reltimedwait(cond, mtx, relms); 00430 } 00431 #endif 00432 00433 00434 #endif // threads 00435 00436 00437 00438 libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen |