libFAUDES

Sections

Index

cfl_platform.cpp

Go 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 
00076 // Uniform system time (using pthread timespec semantics, trust MinGW to provide)
00077 #if defined(FAUDES_POSIX) || defined(FAUDES_WINDOWS)
00078 void faudes_gettimeofday(faudes_systime_t* now) {
00079   timeval nowval;
00080   gettimeofday(&nowval,0);
00081   now->tv_sec=nowval.tv_sec;
00082   now->tv_nsec=nowval.tv_usec * 1000;
00083 }
00084 #endif
00085 
00086 // Uniform system time (supporting functions)
00087 void faudes_diffsystime(const faudes_systime_t& end, const faudes_systime_t& begin, faudes_systime_t* res) {
00088   res->tv_sec = end.tv_sec-begin.tv_sec;
00089   res->tv_nsec = end.tv_nsec-begin.tv_nsec;
00090   if(res->tv_nsec <= 0){
00091     res->tv_sec--;
00092     res->tv_nsec += 1000000000;
00093   }
00094 }
00095 
00096 // Uniform system time (supporting functions)
00097 void faudes_sumsystime(const faudes_systime_t& begin, const faudes_systime_t& duration, faudes_systime_t* res) {
00098   res->tv_sec = begin.tv_sec + duration.tv_sec;
00099   res->tv_nsec = begin.tv_nsec + duration.tv_nsec;
00100   if(res->tv_nsec >= 1000000000) {
00101     res->tv_sec++;
00102     res->tv_nsec-=1000000000;
00103   }
00104 }
00105 
00106 // Uniform system time (supporting functions)
00107 void faudes_msdelay(faudes_mstime_t msecs,faudes_systime_t* end) {
00108   faudes_systime_t now;
00109   faudes_gettimeofday(&now);
00110   faudes_systime_t delta;
00111   delta.tv_sec = msecs/1000;
00112   delta.tv_nsec = (msecs % 1000) *1000000;
00113   faudes_sumsystime(now,delta,end);
00114 }
00115 
00116 // Uniform system time (supporting functions)
00117 void faudes_usdelay(faudes_mstime_t usecs,faudes_systime_t* end) {
00118   faudes_systime_t now;
00119   faudes_gettimeofday(&now);
00120   faudes_systime_t delta;
00121   delta.tv_sec = usecs/1000000;
00122   delta.tv_nsec = (usecs % 1000000) * 1000;
00123   faudes_sumsystime(now,delta,end);
00124 }
00125 
00126 
00127 #endif // systime
00128 
00129 
00130 #ifdef FAUDES_NETWORK
00131 
00132 
00133 // Uniform socketoption: test for error
00134 int faudes_getsocket_error(int fd) {
00135 #ifdef FAUDES_POSIX 
00136   int opt=0;
00137   socklen_t len = sizeof(opt);
00138   int res = getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &len) < 0 ? -1 : 0;
00139   if(opt!=0) res=-1;
00140   return res;
00141 #endif
00142 #ifdef FAUDES_WINDOWS 
00143   int opt=0;
00144   socklen_t len = sizeof(opt);
00145   int res = getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0 ? -1 : 0;
00146   if(opt!=0) res=-1;
00147   return res;
00148 #endif
00149 }
00150 
00151 // Uniform socketoption: set nonblocking
00152 int faudes_setsocket_nonblocking(int fd, bool noblo) {
00153 #ifdef FAUDES_POSIX 
00154   int sopt=fcntl(fd, F_GETFL, NULL);
00155   if(sopt<0) return -1; // error 
00156   if(noblo) {
00157     int rc=fcntl(fd, F_SETFL, sopt|O_NONBLOCK);
00158     return rc < 0 ? -1 : 0;
00159   } else {
00160     int rc=fcntl(fd, F_SETFL, sopt& (~O_NONBLOCK));
00161     return rc < 0 ? -1 : 0;
00162   }
00163 #endif
00164 #ifdef FAUDES_WINDOWS 
00165   unsigned long onoff=0;
00166   if(noblo) onoff=1;
00167   return ioctlsocket(fd, FIONBIO, &onoff) == SOCKET_ERROR ? -1 : 0;
00168 #endif
00169 }
00170 
00171 
00172 
00173 
00174 
00175 
00176 #endif // network
00177 
00178 
00179 #ifdef FAUDES_THREADS
00180 
00181 
00182 // Use Windows thread local storage to implement pointer-typed return values
00183 #ifdef FAUDES_WINDOWS
00184 DWORD faudes_thread_tlsidx=TLS_OUT_OF_INDEXES;
00185 #endif
00186 
00187 // Windows thread function wrapper with faudes_thread_t argument;
00188 #ifdef FAUDES_WINDOWS
00189 static unsigned WINAPI faudes_thread_wrapper(void *argfth) {
00190   // access my thread struct
00191   faudes_thread_t fthread = (faudes_thread_t) argfth;
00192   // record my thread struct as tls
00193   TlsSetValue(faudes_thread_tlsidx,fthread);
00194   // extract actual function an arguments
00195   void *(*fnct)(void*) =  fthread->mFnct;
00196   void *arg = fthread->mArg;
00197   // call function
00198   void* res = fnct(arg);
00199   // uniform exit to retrieve return value
00200   faudes_thread_exit(res);
00201   // return dummy
00202   return 0;
00203 }
00204 #endif
00205 
00206 // Thread functions (Windows to mimic pthreads)
00207 #ifdef FAUDES_WINDOWS
00208 int faudes_thread_create(faudes_thread_t *thr, void *(*fnct)(void *), void *arg){
00209   // initialize thread local storage block
00210   if(faudes_thread_tlsidx==TLS_OUT_OF_INDEXES) 
00211     faudes_thread_tlsidx=TlsAlloc();
00212   if(faudes_thread_tlsidx==TLS_OUT_OF_INDEXES) 
00213     return FAUDES_THREAD_ERROR;
00214   // malloc my thread structure
00215   *thr = (faudes_thread_t) malloc(sizeof(faudes_thread_record_t));
00216   if(!*thr) return FAUDES_THREAD_ERROR;
00217   // initialze my thread structure with function and argument
00218   (*thr)->mFnct = fnct;
00219   (*thr)->mArg = arg;
00220   (*thr)->mRes = NULL;
00221   // start the thread
00222   (*thr)->mHandle = (HANDLE) _beginthreadex(NULL, 0, faudes_thread_wrapper, (void*) (*thr), 0, NULL);
00223   // done
00224   return  (*thr)->mHandle ?  FAUDES_THREAD_SUCCESS : FAUDES_THREAD_ERROR;
00225 }
00226 #endif
00227 
00228 #ifdef FAUDES_WINDOWS
00229 // Thread functions (Windows to mimic pthreads)
00230 faudes_thread_t faudes_thread_current(void) {
00231   // retrieve my thread struct from tls
00232   faudes_thread_t fthread = (faudes_thread_t) TlsGetValue(faudes_thread_tlsidx);
00233   // note: returns NULL for parent thread
00234   return fthread;
00235 }
00236 #endif
00237 
00238 #ifdef FAUDES_WINDOWS
00239 // Thread functions (Windows to mimic pthreads)
00240 int faudes_thread_detach(faudes_thread_t thr) {
00241   CloseHandle(thr->mHandle);
00242   // free my mem
00243   free(thr);
00244   return FAUDES_THREAD_SUCCESS;
00245 }
00246 #endif
00247 
00248 #ifdef FAUDES_WINDOWS
00249 // Thread functions (Windows to mimic pthreads)
00250 int faudes_thread_equal(faudes_thread_t thr0, faudes_thread_t thr1) {
00251   // the parent thread has no tls record and thus reports NULL
00252   if( (thr0==NULL) && (thr1=NULL) ) return true;
00253   if( (thr0==NULL) || (thr1=NULL) ) return false;
00254   // std case, compare by handle
00255   return thr0->mHandle == thr1->mHandle;
00256 }
00257 #endif
00258 
00259 #ifdef FAUDES_WINDOWS
00260 // Thread functions (Windows to mimic pthreads)
00261 void faudes_thread_exit(void *res) {
00262   // retrieve thread structure from tls to pass on result
00263   faudes_thread_t fthread = (faudes_thread_t) TlsGetValue(faudes_thread_tlsidx);
00264   if(fthread) fthread->mRes=res;
00265   // call winapi
00266   ExitThread(0);
00267 }
00268 #endif
00269 
00270 #ifdef FAUDES_WINDOWS
00271 // Thread functions (Windows to mimic pthreads)
00272 int faudes_thread_join(faudes_thread_t thr, void **res) {
00273   // default result
00274   if(res) *res = 0;
00275   // do the join
00276   DWORD rc = WaitForSingleObject(thr->mHandle, INFINITE);
00277   // retrieve result from thread structure
00278   if( (rc!=WAIT_FAILED) && (res))  *res = thr->mRes;  
00279   // free mem
00280   free(thr);
00281   // done
00282   if(rc == WAIT_FAILED) return FAUDES_THREAD_ERROR;
00283   return FAUDES_THREAD_SUCCESS;
00284 }
00285 #endif
00286 
00287 // The approach to condition variables on Windows is taken from 
00288 // "Strategies for Implementing POSIX Condition Variables on Win32" 
00289 // by Douglas C. Schmidt and Irfan Pyarali, Department of Computer 
00290 // Science, Washington University. 
00291 
00292 // Convenience access my two condition events
00293 #ifdef FAUDES_WINDOWS
00294 #define EVENT_SIGNAL 0
00295 #define EVENT_BROADCAST 1
00296 #endif
00297 
00298 // Condition functions (Windows to mimic plain pthread)
00299 #ifdef FAUDES_WINDOWS
00300 int faudes_cond_init(faudes_cond_t* cond) {
00301   // #waiters=0, with mutexed access
00302   cond->mWaitersCount = 0;
00303   InitializeCriticalSection(&cond->mWaitersCountMutex);
00304   // auto-reset event to signal the condition
00305   cond->mEvents[EVENT_SIGNAL]=CreateEvent(NULL, FALSE, FALSE, NULL);
00306   // manual-reset event to broadcast the condition
00307   cond->mEvents[EVENT_BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
00308   // initialisation succeeded
00309   if(cond->mEvents[EVENT_SIGNAL] != NULL) 
00310   if(cond->mEvents[EVENT_BROADCAST] != NULL) 
00311     return FAUDES_THREAD_SUCCESS;
00312   // allow for destroy even on failed initialisation
00313   if(cond->mEvents[EVENT_SIGNAL] != NULL) 
00314     CloseHandle(cond->mEvents[EVENT_SIGNAL]);
00315   if(cond->mEvents[EVENT_BROADCAST] != NULL) 
00316     CloseHandle(cond->mEvents[EVENT_BROADCAST]);
00317   cond->mEvents[EVENT_BROADCAST] = NULL;
00318   cond->mEvents[EVENT_SIGNAL]=NULL;  
00319   return FAUDES_THREAD_ERROR;
00320 }
00321 #endif
00322 
00323 #ifdef FAUDES_WINDOWS
00324 // Condition functions (Windows to mimic plain pthread)
00325 void faudes_cond_destroy(faudes_cond_t* cond) {
00326   if(cond->mEvents[EVENT_SIGNAL] != NULL) 
00327     CloseHandle(cond->mEvents[EVENT_SIGNAL]);
00328   if(cond->mEvents[EVENT_BROADCAST] != NULL) 
00329     CloseHandle(cond->mEvents[EVENT_BROADCAST]);
00330   DeleteCriticalSection(&cond->mWaitersCountMutex);
00331 }
00332 #endif
00333 
00334 #ifdef FAUDES_WINDOWS
00335 // Condition functions (Windows to mimic plain pthread)
00336 int faudes_cond_signal(faudes_cond_t *cond){
00337   int waiters;
00338   // any waiters ?
00339   EnterCriticalSection(&cond->mWaitersCountMutex);
00340   waiters = (cond->mWaitersCount > 0);
00341   LeaveCriticalSection(&cond->mWaitersCountMutex);
00342   // set event (one waiter will see the auto-reset event)
00343   if(waiters){
00344     if(SetEvent(cond->mEvents[EVENT_SIGNAL]) == 0) 
00345       return FAUDES_THREAD_ERROR;
00346   }
00347   return FAUDES_THREAD_SUCCESS;
00348 }
00349 #endif
00350 
00351 #ifdef FAUDES_WINDOWS
00352 // Condition functions (Windows to mimic plain pthread)
00353 int faudes_cond_broadcast(faudes_cond_t *cond) {
00354   int waiters;
00355   // any waiters ?
00356   EnterCriticalSection(&cond->mWaitersCountMutex);
00357   waiters = (cond->mWaitersCount > 0);
00358   LeaveCriticalSection(&cond->mWaitersCountMutex);
00359   // set event (all waiters will see, last waiter does the manual-reset)
00360   if(waiters) {
00361     if(SetEvent(cond->mEvents[EVENT_BROADCAST]) == 0)
00362       return FAUDES_THREAD_ERROR;
00363   }
00364   return FAUDES_THREAD_SUCCESS;
00365 }
00366 #endif
00367 
00368 #ifdef FAUDES_WINDOWS
00369 // Condition functions (Windows to mimic plain pthread)
00370 int faudes_cond_reltimedwait(faudes_cond_t *cond, faudes_mutex_t *mtx, faudes_mstime_t duration) {
00371   // increment #waiters
00372   EnterCriticalSection(&cond->mWaitersCountMutex);
00373   ++ cond->mWaitersCount;
00374   LeaveCriticalSection(&cond->mWaitersCountMutex);
00375   // release mutex while waiting 
00376   LeaveCriticalSection(mtx);
00377   // wait for either event to be set 
00378   int res = WaitForMultipleObjects(2, cond->mEvents, FALSE, (DWORD) duration);
00379   // maintane my data ...
00380   EnterCriticalSection(&cond->mWaitersCountMutex);
00381   // ... a) decrement #waiters 
00382   -- cond->mWaitersCount;
00383   // ... b) test if this was a broadcast and we were the last waiter ...
00384   int last = 
00385     (res == (WAIT_OBJECT_0 + EVENT_BROADCAST)) &&
00386     (cond->mWaitersCount == 0);
00387   LeaveCriticalSection(&cond->mWaitersCountMutex);
00388   // ... c) if so, do a manual-reset of the event
00389   if(last) ResetEvent(cond->mEvents[EVENT_BROADCAST]);
00390   // reaquire mutex 
00391   EnterCriticalSection(mtx);
00392   // uniform return value
00393   if(res == (int) WAIT_TIMEOUT) 
00394     return FAUDES_THREAD_TIMEOUT;
00395   if(res == (int) WAIT_FAILED) 
00396     return FAUDES_THREAD_ERROR;
00397   return FAUDES_THREAD_SUCCESS;
00398 }
00399 #endif
00400 
00401 #ifdef FAUDES_WINDOWS
00402 // Condition functions (Windows to mimic plain pthread)
00403 int faudes_cond_wait(faudes_cond_t *cond, faudes_mutex_t *mtx) {
00404   return faudes_cond_reltimedwait(cond, mtx, INFINITE);
00405 }
00406 #endif
00407 
00408 #ifdef FAUDES_WINDOWS
00409 // Condition functions (Windows to mimic plain pthread)
00410 int faudes_cond_timedwait(faudes_cond_t *cond, faudes_mutex_t *mtx, const faudes_systime_t *abstime) {
00411   // get absolute time
00412   faudes_systime_t now;
00413   faudes_gettimeofday(&now);
00414   // convert to rel. time in secs
00415   DWORD rels = abstime->tv_sec - now.tv_sec;
00416   // saturation on overflow 
00417   if(rels > (4294967295u/1000)-1) rels = 4294967295u/1000-1;
00418   // convert to rel. time in msecs
00419   DWORD relms = rels*1000 + (abstime->tv_nsec - now.tv_nsec + 500000) / 1000000;
00420   // pass on to reltimedwait
00421   return faudes_cond_reltimedwait(cond, mtx, relms);
00422 }
00423 #endif 
00424 
00425 
00426 #endif // threads
00427 
00428 
00429 
00430 

libFAUDES 2.22s --- 2013.10.07 --- c++ source docu by doxygen