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 // 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