00001
00025
00026
00027 #ifndef __ETL__THREAD_H_
00028 #define __ETL__THREAD_H_
00029
00030
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
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
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
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
00169
00170
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
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
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,
00370 0,
00371 thread_prefix,
00372 (void*)this,
00373 0,
00374 &thread
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
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
00512
00513
00514
00515 #endif