00001 #ifndef PLATFORM_APERIOS
00002 #include "Thread.h"
00003 #include "Shared/ReferenceCounter.h"
00004 #include "ProcessID.h"
00005 #include "Shared/StackTrace.h"
00006 #include "Shared/MarkScope.h"
00007
00008 #include <pthread.h>
00009 #include <string.h>
00010 #include <iostream>
00011 #include <signal.h>
00012 #include <unistd.h>
00013 #include <cassert>
00014 #include <cstdio>
00015 #include <errno.h>
00016 #include <stdexcept>
00017
00018 using namespace std;
00019
00020 #define THREADCANCEL_SANITY_CHECKS
00021
00022
00023
00024 struct Threadstorage_t {
00025
00026 Threadstorage_t() : threadInfo(), hasThread(false) {}
00027
00028
00029 pthread_t threadInfo;
00030
00031
00032 bool hasThread;
00033
00034
00035 static pthread_key_t selfKey;
00036 private:
00037 Threadstorage_t(const Threadstorage_t& r);
00038 Threadstorage_t& operator=(const Threadstorage_t& r);
00039 };
00040 static const pthread_key_t INVALID_THREADKEY=(pthread_key_t)-1;
00041 pthread_key_t Threadstorage_t::selfKey=INVALID_THREADKEY;
00042
00043
00044 void* Thread::CANCELLED = PTHREAD_CANCELED;
00045
00046 Thread::Thread()
00047 : pt(new Threadstorage_t), started(false), running(false), exited(false), returnValue(NULL),
00048 noCancelDepth(0),
00049 #ifndef USE_SIGNAL_TO_CANCEL_THREAD
00050 reqIntrDepth(0),
00051 #endif
00052 cancelOrig(PTHREAD_CANCEL_ENABLE), cancelRequested(false), cancelInProgress(false),
00053 group(NULL), startTrace(NULL), startLock(), stopLock()
00054 {
00055 Thread* cur=getCurrent();
00056 if(cur!=NULL)
00057 group=cur->getGroup();
00058 }
00059
00060 Thread::~Thread() {
00061 startLock.lock();
00062 if(started && this!=getCurrent()) {
00063 stop();
00064 join();
00065 }
00066
00067
00068
00069
00070 assert(pt!=NULL);
00071 if(pt->hasThread) {
00072 if(int err=pthread_detach(pt->threadInfo)) {
00073 cerr << "~Thread(), thread_detach: " << strerror(err) << endl;
00074 stacktrace::displayStackTrace(startTrace);
00075 }
00076 pt->hasThread=false;
00077 }
00078 delete pt;
00079 pt=NULL;
00080 if(startTrace!=NULL)
00081 stacktrace::freeStackTrace(startTrace);
00082 }
00083
00084 void Thread::start() {
00085 MarkScope sl(startLock);
00086 if(started) {
00087 std::cerr << "Thread::start() -- thread is already started!\n"
00088 " Make another instance if you want to run another copy of this thread\n"
00089 " ** Original start:" << std::endl;
00090 stacktrace::displayStackTrace(startTrace);
00091 std::cerr << " ** Duplicate start:" << std::endl;
00092 stacktrace::displayCurrentStackTrace();
00093 return;
00094 }
00095 if(startTrace!=NULL)
00096 stacktrace::freeStackTrace(startTrace);
00097 startTrace = stacktrace::recordStackTrace();
00098 exited=cancelRequested=false;
00099 started=true;
00100 pthread_attr_t threadAttributes;
00101 if(int err = pthread_attr_init(&threadAttributes))
00102 cerr << "Thread start(), could not init stack attributes: " << strerror(err) << endl;
00103 const size_t REQ_STACK = 2*1024*1024;
00104 size_t stackSize=0;
00105 if(int err = pthread_attr_getstacksize(&threadAttributes, &stackSize))
00106 cerr << "Thread start(), get stack size: " << strerror(err) << endl;
00107 if(stackSize < REQ_STACK) {
00108 if(int err = pthread_attr_setstacksize(&threadAttributes, REQ_STACK))
00109 cerr << "Thread start(), set stack size: " << strerror(err) << endl;
00110 }
00111 if(pt->hasThread) {
00112 if(int err=pthread_detach(pt->threadInfo))
00113 cerr << "Thread start(), thread_detach of previous thread: " << strerror(err) << endl;
00114 pt->hasThread=false;
00115 }
00116 if(int err=pthread_create(&pt->threadInfo, &threadAttributes, launch, this))
00117 cerr << "Thread start(), pthread_create: " << strerror(err) << endl;
00118 else
00119 pt->hasThread=true;
00120 }
00121
00122 void * Thread::run() {
00123 for(;;) {
00124 unsigned int sleeptime=runloop();
00125 if(sleeptime==-1U)
00126 return returnValue;
00127 if(sleeptime>0)
00128 usleep(sleeptime);
00129 testCancel();
00130 }
00131
00132 return returnValue;
00133 }
00134
00135 Thread& Thread::interrupt() {
00136 if(!isRunning())
00137 return *this;
00138 struct sigaction sa;
00139 sa.sa_handler = handleInterrupt;
00140 if(sigemptyset(&sa.sa_mask)!=0)
00141 perror("Thread::interrupt(): clearing signal set via sigemptyset()");
00142 sa.sa_flags = 0;
00143 if(sigaction(SIGALRM,&sa,NULL)!=0)
00144 perror("Thread::interrupt(): installing interrupt handler via sigaction()");
00145 sendSignal(SIGALRM);
00146 return *this;
00147 }
00148
00149 Thread& Thread::stop() {
00150 MarkScope l(stopLock);
00151 if(exited)
00152 return *this;
00153 if(!started && !running) {
00154 std::cerr << "Thread::stop() -- thread has not been started!" << std::endl;
00155 stacktrace::displayCurrentStackTrace();
00156 return *this;
00157 }
00158 #ifdef USE_PTHREAD_CANCEL
00159 if(started && !running)
00160 usleep(50000);
00161 if(started && !running)
00162 std::cerr << "Thread::stop(): Waiting for thread launch to complete (stillborn thread?)" << std::endl;
00163 while(started && !running)
00164 usleep(100000);
00165 if(!running)
00166 return *this;
00167 if(int err=pthread_cancel(pt->threadInfo))
00168 cerr << "Thread cancel(), pthread_cancel("<<pt->threadInfo<<"): " << strerror(err) << endl;
00169 #else
00170
00171 cancelRequested=true;
00172 #endif
00173 #ifdef USE_SIGNAL_TO_CANCEL_THREAD
00174 # ifndef USE_PTHREAD_CANCEL
00175
00176 if(!running)
00177 return *this;
00178 # endif
00179 if(noCancelDepth>0)
00180 return *this;
00181 interrupt();
00182 #else
00183 if(reqIntrDepth>0)
00184 interrupt();
00185 #endif
00186 return *this;
00187 }
00188
00189 Thread& Thread::kill() {
00190 sendSignal(SIGUSR1);
00191 return *this;
00192 }
00193
00194 Thread& Thread::murder() {
00195 if(pt->hasThread) {
00196 if(int err=pthread_detach(pt->threadInfo))
00197 cerr << "Thread kill(), thread_detach: " << strerror(err) << endl;
00198 pt->hasThread=false;
00199 }
00200 sendSignal(SIGSTOP);
00201 started=running=false;
00202 exited=true;
00203 return *this;
00204 }
00205
00206 void Thread::sendSignal(int sig) {
00207 if(started && !running)
00208 usleep(50000);
00209 if(started && !running)
00210 std::cerr << "Thread::stop(): Waiting for thread launch to complete (stillborn thread?)" << std::endl;
00211 while(started && !running)
00212 usleep(100000);
00213 if(!isRunning())
00214 return;
00215 if(int err=pthread_kill(pt->threadInfo,sig))
00216 if(err!=ESRCH)
00217 cerr << "Thread sendSignal(), pthread_kill("<<sig<<"): " << strerror(err) << endl;
00218 }
00219
00220 void * Thread::join() const {
00221 MarkScope l(startLock);
00222 if(!started || !pt->hasThread)
00223 return cancelRequested ? CANCELLED : returnValue;
00224 void * ans=NULL;
00225 pthread_t cur = pt->threadInfo;
00226 pt->hasThread = false;
00227 if(int err=pthread_join(cur, &ans)) {
00228 cerr << "thread join() returned " << err << " " << strerror(err) << endl;
00229 if((err==EINVAL || err==ESRCH) && (!started || !pthread_equal(cur, pt->threadInfo)))
00230 return cancelRequested ? CANCELLED : returnValue;
00231 cerr << "Thread join() " << err << " (" << EINVAL << ',' << ESRCH << "), pthread_join: " << strerror(err) << endl;
00232 stacktrace::displayCurrentStackTrace();
00233 }
00234 return ans;
00235 }
00236
00237 Thread* Thread::getCurrent() {
00238 if(Threadstorage_t::selfKey==INVALID_THREADKEY) {
00239 static bool gaveError=false;
00240 if(!gaveError) {
00241 cerr << "ERROR: In Thread::getCurrent(), selfKey uninitialized; Thread::initMainThread was not called." << endl;
00242 cerr << " (This error will only be displayed once)" << endl;
00243 gaveError=true;
00244 }
00245 return NULL;
00246 }
00247 return static_cast< Thread* >(pthread_getspecific(Threadstorage_t::selfKey));
00248 }
00249
00250 void Thread::initMainThread() {
00251 if(int err=pthread_key_create(&Threadstorage_t::selfKey,warnSelfUndestructed))
00252 cerr << "WARNING: In Thread::initMainThread(), pthread_key_create(selfKey) returned " << strerror(err) << endl;
00253 if(int err=pthread_setspecific(Threadstorage_t::selfKey,NULL))
00254 cerr << "WARNING: In Thread::initMainThread(), pthread_setspecific(selfKey) returned " << strerror(err) << endl;
00255 }
00256
00257 void Thread::releaseMainThread() {
00258
00259 if(Threadstorage_t::selfKey==INVALID_THREADKEY)
00260 return;
00261 if(int err=pthread_key_delete(Threadstorage_t::selfKey))
00262 cerr << "WARNING: In Thread::releaseMainThread, pthread_key_delete(selfKey) returned " << strerror(err) << endl;
00263 }
00264
00265 void Thread::testCurrentCancel() {
00266 Thread * cur = getCurrent();
00267 if(cur==NULL) {
00268 #ifdef USE_PTHREAD_CANCEL
00269 pthread_testcancel();
00270 #endif
00271 return;
00272 }
00273 #ifdef DEBUG
00274 if(cur->noCancelDepth!=0) {
00275 cerr << "WARNING: Thread::testCancel called with noCancelDepth=="<<cur->noCancelDepth<<" (process="<<ProcessID::getID()<<", thread="<<pthread_self()<<")"<<endl;
00276 cerr << "The thread was started at:" << endl;
00277 stacktrace::displayStackTrace(cur->startTrace);
00278 cerr << "The testCancel call is from:" << endl;
00279 stacktrace::displayCurrentStackTrace();
00280 }
00281 #endif
00282 if(cur->noCancelDepth!=0 || cur->cancelInProgress)
00283 return;
00284 #ifdef USE_PTHREAD_CANCEL
00285 cur->cancelInProgress=true;
00286 pthread_testcancel();
00287 cur->cancelInProgress=false;
00288 #else
00289 if(cur->cancelRequested) {
00290 cur->cancelInProgress=true;
00291 throw cancellation_exception();
00292 }
00293 #endif
00294 }
00295
00296 void * Thread::launch(void * msg) {
00297
00298 Thread* cur=static_cast<Thread*>(msg);
00299 if(cur==NULL) {
00300 cerr << "ERROR: Thread::launch with NULL msg" << endl;
00301 return NULL;
00302 }
00303
00304 if(int err=pthread_setspecific(Threadstorage_t::selfKey,msg))
00305 cerr << "WARNING: In Thread::launch(), pthread_setspecific(selfKey) returned " << strerror(err) << endl;
00306
00307 cur->cancelInProgress=false;
00308
00309
00310 if(int err=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL))
00311 cerr << "Thread launch(), pthread_setcanceltype: " << strerror(err) << endl;
00312 ++(cur->noCancelDepth);
00313 if(signal(SIGUSR1,Thread::handle_launch_signal)==SIG_ERR)
00314 perror("Thread launch(), signal(SIGUSR1,handle_launch_signal)");
00315 cur->running=true;
00316 if(!cur->launched()) {
00317
00318 --(cur->noCancelDepth);
00319 handle_exit(NULL);
00320 return cur->returnValue;
00321 }
00322 --(cur->noCancelDepth);
00323
00324
00325
00326 cur->returnValue=CANCELLED;
00327
00328
00329
00330 pthread_cleanup_push(Thread::handle_exit,msg); {
00331
00332 if(signal(SIGUSR1,Thread::handle_signal)==SIG_ERR)
00333 perror("Thread launch(), signal(SIGUSR1,handle_signal)");
00334
00335 try {
00336 if(cur->noCancelDepth==0) {
00337
00338 if(int err=pthread_setcancelstate(cur->cancelOrig,NULL))
00339 cerr << "Thread launch(), pthread_setcancelstate: " << strerror(err) << endl;
00340 if(int err=pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL))
00341 cerr << "Thread launch(), pthread_setcanceltype: " << strerror(err) << endl;
00342 cur->testCancel();
00343 }
00344 cur->returnValue=cur->run();
00345 } catch(const Thread::cancellation_exception&) {
00346
00347
00348 }
00349
00350
00351
00352
00353
00354
00355
00356 } pthread_cleanup_pop(true);
00357 return cur->returnValue;
00358 }
00359
00360 void Thread::handle_launch_signal(int ) {
00361 handle_exit(NULL);
00362 pthread_exit(NULL);
00363 }
00364
00365 void Thread::handle_signal(int ) {
00366 pthread_exit(NULL);
00367 }
00368
00369 void Thread::handle_exit(void * th) {
00370
00371 Thread* cur=getCurrent();
00372 if(cur==NULL) {
00373 cerr << "ERROR: handle_exit called for a NULL thread" << endl;
00374 if(th!=NULL) {
00375 static_cast<Thread*>(th)->cancelled();
00376 static_cast<Thread*>(th)->started=static_cast<Thread*>(th)->running=false;
00377 }
00378 return;
00379 }
00380
00381 {
00382 MarkScope l(cur->stopLock);
00383 if(th!=NULL && th!=cur)
00384 cerr << "WARNING: handle_exit argument does not match selfKey" << endl;
00385 if(cur->noCancelDepth!=0) {
00386 cerr << "WARNING: thread " << pthread_self() << " of ProcessID_t " << ProcessID::getID() << " exited while noCancelDepth>0 (was " << cur->noCancelDepth << ")" << endl;
00387 cerr << " This may indicate a mutex was left locked." << endl;
00388 cur->noCancelDepth=0;
00389 }
00390 if(int err=pthread_setspecific(Threadstorage_t::selfKey,NULL))
00391 cerr << "WARNING: In Thread::handle_exit(), pthread_setspecific(selfKey) returned " << err << endl;
00392 cur->cancelled();
00393 cur->started=cur->running=false;
00394 cur->exited=true;
00395 }
00396 cur->dereference();
00397 }
00398
00399 void Thread::pushNoCancel() {
00400 Thread * cur=getCurrent();
00401 if(cur==NULL) {
00402
00403
00404 if(int err=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL))
00405 cerr << "ERROR: Thread pushNoCancel(), pthread_setcanceltype: " << strerror(err) << endl;
00406 } else {
00407 ++(cur->noCancelDepth);
00408 int previous=-1;
00409 if(int err=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&previous))
00410 cerr << "ERROR: Thread pushNoCancel(), pthread_setcanceltype: " << strerror(err) << endl;
00411 #ifdef THREADCANCEL_SANITY_CHECKS
00412 if(cur->noCancelDepth==1 && previous!=cur->cancelOrig)
00413 cerr << "WARNING: In Thread::pushNoCancel, cancel state was wrong (was " << previous << ", expected " << cur->cancelOrig << ")" << endl;
00414 else if(cur->noCancelDepth!=1 && previous!=PTHREAD_CANCEL_DISABLE)
00415 cerr << "WARNING: In Thread::pushNoCancel, cancel state was somehow re-enabled" << endl;
00416 #endif
00417 }
00418 }
00419 void Thread::popNoCancel(bool doTestCancel) {
00420 Thread * cur=getCurrent();
00421 if(cur==NULL) {
00422
00423
00424 return;
00425 } else if(cur->noCancelDepth==0) {
00426 cerr << "ERROR: Thread::popNoCancel underflow" << endl;
00427 } else
00428 --(cur->noCancelDepth);
00429 int previous=-1;
00430 if(cur->noCancelDepth==0) {
00431 if(int err=pthread_setcancelstate(cur->cancelOrig,&previous))
00432 cerr << "ERROR: Thread popNoCancel(), pthread_setcanceltype: " << strerror(err) << endl;
00433 if(cur->cancelOrig==PTHREAD_CANCEL_ENABLE && doTestCancel)
00434 cur->testCancel();
00435 }
00436 #ifdef THREADCANCEL_SANITY_CHECKS
00437 else {
00438 if(int err=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&previous))
00439 cerr << "ERROR: Thread popNoCancel(), pthread_setcanceltype: " << strerror(err) << endl;
00440 }
00441 if(previous!=PTHREAD_CANCEL_DISABLE)
00442 cerr << "WARNING: In Thread::popNoCancel, cancel state was somehow re-enabled" << endl;
00443 #endif
00444 }
00445
00446 void Thread::requestInterruptOnCancel() {
00447 #ifndef USE_SIGNAL_TO_CANCEL_THREAD
00448 Thread * cur=getCurrent();
00449 if(cur==NULL)
00450 return;
00451 pushNoCancel();
00452 ++(cur->reqIntrDepth);
00453 #ifdef DEBUG
00454 if(cur->reqIntrDepth!=1)
00455 std::cerr << "WARNING: recursive Thread::requestInterruptOnCancel() " << cur->reqIntrDepth << std::endl;
00456 #endif
00457 #endif
00458 }
00459
00460 void Thread::unrequestInterruptOnCancel() {
00461 #if !defined(USE_SIGNAL_TO_CANCEL_THREAD) || !defined(USE_TESTCANCEL_IN_INTERRUPT)
00462 Thread * cur=getCurrent();
00463 if(cur==NULL)
00464 return;
00465 #endif
00466 #ifndef USE_SIGNAL_TO_CANCEL_THREAD
00467 if(cur->reqIntrDepth==0) {
00468 cerr << "ERROR: Thread::unrequestInterruptOnCancel underflow" << endl;
00469 } else {
00470 --(cur->reqIntrDepth);
00471 }
00472 popNoCancel();
00473 #endif
00474 #ifndef USE_TESTCANCEL_IN_INTERRUPT
00475 if(cur->noCancelDepth==0)
00476 cur->testCancel();
00477 #endif
00478 }
00479
00480 void Thread::handleInterrupt(int ) {
00481
00482
00483 Thread * cur=Thread::getCurrent();
00484 if(cur==NULL) {
00485
00486
00487
00488 return;
00489 }
00490 #ifdef USE_TESTCANCEL_IN_INTERRUPT
00491 if(cur->noCancelDepth==0)
00492 cur->testCancel();
00493 #endif
00494 cur->interrupted();
00495 }
00496
00497 void Thread::warnSelfUndestructed(void* msg) {
00498 cerr << "ERROR: Thread local data (selfKey) not deleted by Thread::handle_exit" << endl;
00499 Thread* cur = getCurrent();
00500 if(cur!=NULL)
00501 cerr << " Weird, key wasn't cleared... (" << cur << ") " << cur->noCancelDepth << " locks on stack? " << endl;;
00502 if(msg==NULL) {
00503 cerr << " Message is null, warnCancelDepthUndestructed shouldn't have been called." << endl;
00504 } else {
00505 if(cur!=NULL && cur!=msg)
00506 cerr << " and current thread does not match msg (" << cur << " vs " << msg << ")" << endl;
00507 cur = static_cast<Thread*>(msg);
00508 }
00509 if(cur!=NULL) {
00510
00511 if(cur->noCancelDepth==0) {
00512 cerr << " But at least the depth is 0" << endl;
00513 } else {
00514 cerr << " The depth indicates there may be " << cur->noCancelDepth << " locks left in place" << endl;
00515 }
00516 cur->cancelled();
00517 cur->started=cur->running=false;
00518 pthread_setspecific(Threadstorage_t::selfKey,NULL);
00519 }
00520 }
00521
00522
00523
00524
00525 class Thread::Lock::LockStorage : public ReferenceCounter {
00526 friend class Thread::Condition;
00527 public:
00528
00529 LockStorage() : ReferenceCounter(), locklevel(0), mutex(), attr(), threadkey() {
00530 addReference();
00531 pthread_mutexattr_init(&attr);
00532 pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
00533 pthread_mutex_init(&mutex,&attr);
00534 }
00535
00536 ~LockStorage() {
00537 pthread_mutexattr_destroy(&attr);
00538 pthread_mutex_destroy(&mutex);
00539 if(locklevel>1)
00540 cerr << "WARNING: lockstorage destructed with " << locklevel << " locks still in effect" << endl;
00541 while(locklevel>0) {
00542 locklevel--;
00543 Thread::popNoCancel(false);
00544 }
00545 }
00546
00547 LockStorage(const LockStorage& ls) : ReferenceCounter(ls), locklevel(ls.locklevel), mutex(ls.mutex), attr(ls.attr), threadkey(ls.threadkey) {}
00548
00549 LockStorage& operator=(const LockStorage& ls) { ReferenceCounter::operator=(ls); locklevel=ls.locklevel; mutex=ls.mutex; attr=ls.attr; threadkey=ls.threadkey; return *this; }
00550
00551
00552 void lock() {
00553 if(int err=pthread_mutex_lock(&mutex)) {
00554 cerr << "ERROR: Thread::Lock::lock() failed: " << strerror(err) << endl;
00555 } else {
00556 locklevel++;
00557 }
00558 }
00559
00560 bool trylock() {
00561 if(!pthread_mutex_trylock(&mutex)) {
00562 locklevel++;
00563 return true;
00564 } else {
00565 return false;
00566 }
00567 }
00568
00569 void unlock() {
00570 if(locklevel==0) {
00571 cerr << "ERROR: Thread::Lock::unlock() underflow" << endl;
00572 stacktrace::displayCurrentStackTrace();
00573 }
00574 locklevel--;
00575 if(int err=pthread_mutex_unlock(&mutex))
00576 cerr << "ERROR: Thread::Lock::unlock() failed: " << strerror(err) << endl;
00577 }
00578
00579 unsigned int getLockLevel() { return locklevel; }
00580
00581 protected:
00582 unsigned int locklevel;
00583 pthread_mutex_t mutex;
00584 pthread_mutexattr_t attr;
00585 pthread_key_t threadkey;
00586 };
00587
00588 Thread::Lock::LockStorage* Thread::Lock::glock=NULL;
00589
00590
00591 Thread::Lock::Lock() : mylock(new LockStorage), locklevel(0) {
00592 if(glock==NULL)
00593 setup();
00594 }
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625 Thread::Lock::~Lock() {
00626 glock->lock();
00627 if(locklevel>1)
00628 cerr << "WARNING: Thread::Lock destructed with "<<locklevel<<" locks still in effect" << endl;
00629 if(!mylock->removeReference()) {
00630 std::cerr << "Lock was deleted with external reference?" << std::endl;
00631 stacktrace::displayCurrentStackTrace();
00632 while(locklevel>0)
00633 unlock();
00634 }
00635 mylock=NULL;
00636 glock->unlock();
00637 }
00638
00639 void Thread::Lock::useResource(Resource::Data&) {
00640 mylock->lock();
00641 locklevel++;
00642 }
00643 bool Thread::Lock::trylock() {
00644 Thread::pushNoCancel();
00645 if(mylock->trylock()) {
00646 locklevel++;
00647 return true;
00648 } else {
00649 Thread::popNoCancel();
00650 return false;
00651 }
00652 }
00653 void Thread::Lock::releaseResource(Resource::Data&) {
00654 locklevel--;
00655 mylock->unlock();
00656 }
00657 unsigned int Thread::Lock::getLockLevel() const {
00658 return mylock->getLockLevel();
00659 }
00660 void Thread::Lock::setup() {
00661 if(glock==NULL)
00662 glock=new LockStorage;
00663 }
00664
00665
00666
00667
00668 class Thread::Condition::ConditionStorage {
00669 public:
00670
00671 ConditionStorage() : cond() {
00672 if(int err=pthread_cond_init(&cond,NULL)) {
00673 cerr << "ERROR: Thread::Condition::ConditionStorage() failed: " << strerror(err) << endl;
00674 }
00675 }
00676
00677 ~ConditionStorage() {
00678 if(int err=pthread_cond_destroy(&cond)) {
00679 cerr << "ERROR: Thread::Condition::~ConditionStorage() failed: " << strerror(err) << endl;
00680 }
00681 }
00682
00683 pthread_cond_t cond;
00684 };
00685
00686
00687 Thread::Condition::Condition() : mycond(new ConditionStorage) {}
00688 Thread::Condition::~Condition() { delete mycond; mycond=NULL; }
00689
00690 void Thread::Condition::broadcast() const {
00691 if(int err=pthread_cond_broadcast(&mycond->cond)) {
00692 cerr << "ERROR: Thread::Condition::broadcast() failed: " << strerror(err) << endl;
00693 }
00694 }
00695 void Thread::Condition::signal() const {
00696 if(int err=pthread_cond_signal(&mycond->cond)) {
00697 cerr << "ERROR: Thread::Condition::signal() failed: " << strerror(err) << endl;
00698 }
00699 }
00700 bool Thread::Condition::timedwait(Lock& l, const timespec* abstime, bool noWarn) const {
00701 #ifdef USE_SIGNAL_TO_CANCEL_THREAD
00702 Thread::testCurrentCancel();
00703 #endif
00704 unsigned int locklevel=l.mylock->locklevel;
00705 if(locklevel==1) {
00706
00707 } else if(locklevel>1) {
00708 if(!noWarn)
00709 displayRecursiveLockWarning("timedwait",locklevel);
00710 while(l.mylock->locklevel>1)
00711 l.mylock->unlock();
00712 } else {
00713 throw std::logic_error("Thread::Condition::timedwait() called without holding lock");
00714 }
00715 if(int err=pthread_cond_timedwait(&mycond->cond,&l.mylock->mutex,abstime)) {
00716 if(err!=ETIMEDOUT)
00717 cerr << "ERROR: Thread::Condition::timedwait() failed: " << strerror(err) << endl;
00718 while(l.mylock->locklevel<locklevel)
00719 l.mylock->lock();
00720 return false;
00721 }
00722 while(l.getLockLevel()<locklevel)
00723 l.mylock->lock();
00724 #ifdef USE_SIGNAL_TO_CANCEL_THREAD
00725 Thread::testCurrentCancel();
00726 #endif
00727 return true;
00728 }
00729 void Thread::Condition::wait(Lock& l, bool noWarn) const {
00730 #ifdef USE_SIGNAL_TO_CANCEL_THREAD
00731 Thread::testCurrentCancel();
00732 #endif
00733 unsigned int locklevel=l.mylock->locklevel;
00734 if(locklevel==1) {
00735
00736 } else if(locklevel>1) {
00737 if(!noWarn)
00738 displayRecursiveLockWarning("wait",locklevel);
00739 while(l.mylock->locklevel>1)
00740 l.mylock->unlock();
00741 } else {
00742 throw std::logic_error("Thread::Condition::wait() called without holding lock");
00743 }
00744 if(int err=pthread_cond_wait(&mycond->cond,&l.mylock->mutex)) {
00745 cerr << "ERROR: Thread::Condition::wait() failed: " << strerror(err) << endl;
00746 }
00747 while(l.getLockLevel()<locklevel)
00748 l.mylock->lock();
00749 #ifdef USE_SIGNAL_TO_CANCEL_THREAD
00750 Thread::testCurrentCancel();
00751 #endif
00752 }
00753
00754 void Thread::Condition::displayRecursiveLockWarning(const char * fn, unsigned int locklevel) {
00755 std::cerr << "WARNING: Thread::Condition::"<<fn<<"() called holding a recursive lock. (depth " << locklevel << ")\n"
00756 " You should verify outer lock scopes are safe to temporarily free during wait,\n"
00757 " then pass 'true' for the noWarn argument to timedwait() to disable this message." << std::endl;
00758 stacktrace::displayCurrentStackTrace();
00759 }
00760
00761
00762 #endif // PLATFORM check
00763
00764
00765
00766
00767