- Main Page
- Related Pages
- Classes
- Files

# _thread.h

Go to the documentation of this file.

    00001
    00025 /* === S T A R T =========================================================== */
    00026
    00027 #ifndef __ETL__THREAD_H_
    00028 #define __ETL__THREAD_H_
    00029
    00030 /* === H E A D E R S ======================================================= */
    00031
    00032 #define __USE_GNU
    00033
    00034 #ifdef HAVE_PTHREAD_H
    00035 # include <pthread.h>
    00036 #endif
    00037
    00038 #ifdef HAVE_SCHED_H
    00039 # include <sched.h>
    00040 #endif
    00041
    00042 #ifdef HAVE_CREATETHREAD
    00043 # include <windows.h>
    00044 #endif
    00045
    00046 /* === M A C R O S ========================================================= */
    00047
    00048 #if ( defined (HAVE_PTHREAD_CREATE) || defined (HAVE_CLONE) || defined (HAVE_CREATETHREAD) ) && !defined (NO_THREADS)
    00049 # define CALLISTO_THREADS
    00050 #endif
    00051
    00052 #define THREAD_ENTRYPOINT
    00053
    00054 /* === C L A S S E S & S T R U C T S ======================================= */
    00055
    00056 #if defined(CALLISTO_THREADS) && defined(HAVE_PTHREAD_CREATE)
    00057 static inline void Yield(void)
    00058 {
    00059     sched_yield();
    00060     pthread_testcancel();
    00061 }
    00062 #else
    00063 #ifdef Yield
    00064     #undef Yield
    00065 #endif
    00066 inline void Yield(void) { }
    00067 #endif
    00068
    00069 #ifdef CALLISTO_THREADS
    00070
    00071 #ifdef HAVE_PTHREAD_CREATE
    00072
    00073 class Thread
    00074 {
    00075 public:
    00076     typedef void* entrypoint_return;
    00077 private:
    00078
    00079     pthread_t thread;
    00080     int *references;
    00081     entrypoint_return (*entrypoint)(void *);
    00082     void *context;
    00083 public:
    00084     Thread(void *(*ep)(void *)=NULL,void *context=NULL):
    00085         references(NULL),entrypoint(ep),context(context) { }
    00086     Thread(const Thread &t)
    00087     {
    00088         thread=t.thread;
    00089         references=t.references;
    00090         entrypoint=t.entrypoint;
    00091         context=t.context;
    00092         if(references)
    00093             (*references)++;
    00094     }
    00095     const Thread &operator=(const Thread &rhs)
    00096     {
    00097         if(references)
    00098         {
    00099             (*references)--;
    00100             if(*references==0)
    00101                 stop();
    00102         }
    00103         thread=rhs.thread;
    00104         references=rhs.references;
    00105         entrypoint=rhs.entrypoint;
    00106         context=rhs.context;
    00107         if(references)
    00108             (*references)++;
    00109         return *this;
    00110     }
    00111
    00112     void start(void)
    00113     {
    00114         references = new int;
    00115         *references = 1;
    00116         pthread_create(&thread,NULL,entrypoint,context);
    00117 //      pthread_detach(thread);
    00118     }
    00119
    00120     void stop(void)
    00121     {
    00122         delete references;
    00123         references=NULL;
    00124         void *exit_status;
    00125         pthread_cancel(thread);
    00126         pthread_join(thread,&exit_status);
    00127     }
    00128
    00129     static void TestStop()
    00130     {
    00131         pthread_testcancel();
    00132     }
    00133
    00134     static void SyncStop()
    00135     {
    00136         int i;
    00137         pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,&i);
    00138     }
    00139
    00140     static void AsyncStop()
    00141     {
    00142         int i;
    00143         pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,&i);
    00144     }
    00145
    00146     ~Thread()
    00147     {
    00148         if(references)
    00149         {
    00150             (*references)--;
    00151             if(*references==0)
    00152                 stop();
    00153         }
    00154     }
    00155 };
    00156
    00157 class Mutex
    00158 {
    00159     pthread_mutex_t mutex;
    00160     pthread_t locker;
    00161     int depth;
    00162 public:
    00163
    00164     Mutex()
    00165     {
    00166         pthread_mutexattr_t attr;
    00167         pthread_mutexattr_init(&attr);
    00168         //#ifdef PTHREAD_PRIO_INHERIT
    00169         //pthread_mutexattr_setprioceiling(&attr,PTHREAD_PRIO_INHERIT);
    00170         //#endif
    00171         #ifdef PTHREAD_MUTEX_RECURSIVE
    00172         pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
    00173         #endif
    00174         pthread_mutex_init(&mutex,&attr);
    00175         pthread_mutexattr_destroy(&attr);
    00176         locker=0;
    00177         depth=0;
    00178     }
    00179
    00180     ~Mutex()
    00181     { pthread_mutex_destroy(&mutex); }
    00182
    00183     void Lock(void)
    00184     {
    00185         if(!locker || locker!=pthread_self())
    00186         {
    00187             pthread_mutex_lock(&mutex);
    00188             locker=pthread_self();
    00189             depth=0;
    00190             return;
    00191         }
    00192         depth++;
    00193     }
    00194
    00195     bool TryLock(void)
    00196     { return !(bool) pthread_mutex_trylock(&mutex); }
    00197
    00198     void UnLock(void)
    00199     {
    00200         if(depth)
    00201         {
    00202             depth--;
    00203             return;
    00204         }
    00205         pthread_mutex_unlock(&mutex);
    00206         locker=0;
    00207     }
    00208 };
    00209
    00210 #ifdef HAVE_PTHREAD_RW_LOCK_INIT
    00211 class ReadWriteLock
    00212 {
    00213     pthread_rwlock_t rwlock;
    00214 public:
    00215
    00216     ReadWriteLock()
    00217     { pthread_rwlock_init(&rwlock,NULL); }
    00218
    00219     ~ReadWriteLock()
    00220     { pthread_rwlock_destroy(&rwlock); }
    00221
    00222     void LockRead(void)
    00223     { pthread_rwlock_rdlock(&rwlock); }
    00224
    00225     void LockWrite(void)
    00226     { pthread_rwlock_wrlock(&rwlock); }
    00227
    00228     bool TryLockRead(void)
    00229     { return !(bool)pthread_rwlock_tryrdlock(&rwlock); }
    00230
    00231     bool TryLockWrite(void)
    00232     { return !(bool)pthread_rwlock_trywrlock(&rwlock); }
    00233
    00234     void UnLockWrite(void)
    00235     { pthread_rwlock_unlock(&rwlock); }
    00236
    00237     void UnLockRead(void)
    00238     { pthread_rwlock_unlock(&rwlock); }
    00239 };
    00240 #else
    00241 //*
    00242 class ReadWriteLock : public Mutex
    00243 {
    00244 public:
    00245
    00246     ReadWriteLock()
    00247     {  }
    00248
    00249     ~ReadWriteLock()
    00250     {  }
    00251
    00252     void LockRead(void)
    00253     { Lock(); }
    00254
    00255     void LockWrite(void)
    00256     { Lock(); }
    00257
    00258     bool TryLockRead(void)
    00259     { return TryLock(); }
    00260
    00261     bool TryLockWrite(void)
    00262     { return TryLock(); }
    00263
    00264     void UnLockWrite(void)
    00265     { UnLock(); }
    00266
    00267     void UnLockRead(void)
    00268     { UnLock(); }
    00269 };
    00270 #endif
    00271
    00272 /*
    00273 class Condition
    00274 {
    00275     pthread_cond_t cond;
    00276     pthread_mutex_t mutex;
    00277 public:
    00278     Condition()
    00279     { pthread_cond_init(&cond,NULL); pthread_mutex_init(&mutex,NULL); }
    00280     ~Condition()
    00281     { pthread_cond_destroy(&cond); pthread_mutex_destroy(&mutex);}
    00282     void operator()(void)
    00283     { pthread_cond_signal(&cond); }
    00284     void Wait(void)
    00285     {
    00286         pthread_mutex_lock(&mutex);
    00287         pthread_cond_wait(&cond,&mutex);
    00288         pthread_mutex_unlock(&mutex);
    00289     }
    00290 };
    00291 */
    00292
    00293 #else // if defined HAVE_PTHREAD
    00294 #ifdef HAVE_CREATETHREAD
    00295
    00296
    00297 #ifdef THREAD_ENTRYPOINT
    00298 #undef THREAD_ENTRYPOINT
    00299 #endif
    00300 #define THREAD_ENTRYPOINT   __stdcall
    00301 class Thread
    00302 {
    00303 public:
    00304     typedef unsigned long entrypoint_return;
    00305 private:
    00306
    00307     unsigned long thread;
    00308     HANDLE handle;
    00309     int *references;
    00310
    00311     entrypoint_return  (THREAD_ENTRYPOINT *entrypoint)(void *);
    00312
    00313     void *context;
    00314
    00315     HDC hdc;
    00316     HGLRC hglrc;
    00317
    00318     static entrypoint_return THREAD_ENTRYPOINT thread_prefix(void*data)
    00319     {
    00320         Thread *thread=(Thread *)data;
    00321
    00322         if(thread->hglrc)
    00323             wglMakeCurrent(thread->hdc, thread->hglrc);
    00324
    00325         return thread->entrypoint(thread->context);
    00326     }
    00327
    00328 public:
    00329     Thread(entrypoint_return  (THREAD_ENTRYPOINT *ep)(void *)=NULL,void *context=NULL):
    00330         references(NULL),entrypoint(ep),context(context) { }
    00331     Thread(const Thread &t)
    00332     {
    00333         thread=t.thread;
    00334         handle=t.handle;
    00335         references=t.references;
    00336         entrypoint=t.entrypoint;
    00337         context=t.context;
    00338         handle=NULL;
    00339         if(references)
    00340             (*references)++;
    00341     }
    00342     const Thread &operator=(const Thread &rhs)
    00343     {
    00344         if(references)
    00345         {
    00346             (*references)--;
    00347             if(*references==0)
    00348                 stop();
    00349         }
    00350         thread=rhs.thread;
    00351         handle=rhs.handle;
    00352         references=rhs.references;
    00353         entrypoint=rhs.entrypoint;
    00354         context=rhs.context;
    00355         if(references)
    00356             (*references)++;
    00357         return *this;
    00358     }
    00359
    00360     void start(void)
    00361     {
    00362         references = new int;
    00363         *references = 1;
    00364
    00365         hglrc=wglGetCurrentContext();
    00366         hdc=wglGetCurrentDC();
    00367
    00368         handle=CreateThread(
    00369             NULL,       // Security stuff
    00370             0,  // STACK
    00371             thread_prefix,    // thread function
    00372             (void*)this,                       // thread argument
    00373             0,                    // creation option
    00374             &thread                        // thread identifier
    00375         );
    00376     }
    00377
    00378     void stop(void)
    00379     {
    00380         delete references;
    00381         references=NULL;
    00382
    00383         TerminateThread(handle, FALSE);
    00384     }
    00385
    00386     int wait(void)
    00387     {
    00388         if(handle)
    00389         {
    00390             WaitForSingleObject(handle, INFINITE);
    00391             CloseHandle(handle);
    00392         }
    00393         return 0;
    00394     }
    00395
    00396     static void TestStop()
    00397     {
    00398     }
    00399
    00400     static void SyncStop()
    00401     {
    00402     }
    00403
    00404     static void AsyncStop()
    00405     {
    00406     }
    00407
    00408     ~Thread()
    00409     {
    00410         if(references)
    00411         {
    00412             (*references)--;
    00413             if(*references==0)
    00414                 stop();
    00415         }
    00416     }
    00417 };
    00418
    00419 class Mutex
    00420 {
    00421     HANDLE handle;
    00422 public:
    00423
    00424     Mutex()
    00425     {
    00426         handle = CreateMutex(NULL, FALSE, NULL);
    00427     }
    00428
    00429     ~Mutex()
    00430     {
    00431         CloseHandle(handle);
    00432     }
    00433
    00434     void Lock(void)
    00435     {
    00436         WaitForSingleObject(handle, INFINITE);
    00437     }
    00438
    00439     bool TryLock(void)
    00440     {
    00441         return WaitForSingleObject(handle, INFINITE)==WAIT_FAILED;
    00442     }
    00443
    00444     void UnLock(void)
    00445     {
    00446         ReleaseMutex(handle);
    00447     }
    00448 };
    00449
    00450
    00451 #endif // if defined HAVE_CREATETHREAD
    00452 #endif // if defined HAVE_PTHREAD_CREATE
    00453 #endif // if defined CALLISTO_THREADS
    00454
    00455
    00456 #if !defined(CALLISTO_THREADS)
    00457 // Dummy object used when not threading
    00458 class ReadWriteLock
    00459 {
    00460 public:
    00461
    00462     ReadWriteLock() {}
    00463     ~ReadWriteLock() {}
    00464     void LockRead(void) {}
    00465     void LockWrite(void) {}
    00466     bool TryLockRead(void) {return true;}
    00467     bool TryLockWrite(void) {return true;}
    00468     void UnLockRead(void) {}
    00469     void UnLockWrite(void) {}
    00470 };
    00471
    00472 class Mutex
    00473 {
    00474 public:
    00475
    00476     Mutex(){}
    00477     ~Mutex(){}
    00478     void Lock(void){}
    00479     bool TryLock(void){return true;}
    00480     void UnLock(void){}
    00481 };
    00482
    00483 #endif
    00484
    00485 class Condition : private Mutex
    00486 {
    00487     bool flag;
    00488 public:
    00489     Condition()
    00490     { flag=false; }
    00491     ~Condition()
    00492     { }
    00493     void operator()(void)
    00494     { flag=true; }
    00495     void Wait(void)
    00496     {
    00497         Lock();
    00498         while(!flag)Yield();
    00499         flag=false;
    00500         UnLock();
    00501     }
    00502     void WaitNext(void)
    00503     {
    00504         Lock();
    00505         flag=false;
    00506         while(!flag)Yield();
    00507         UnLock();
    00508     }
    00509 };
    00510
    00511 /* === E X T E R N S ======================================================= */
    00512
    00513 /* === E N D =============================================================== */
    00514
    00515 #endif