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 dereference();
00156
00157 return *this;
00158 }
00159 #ifdef USE_PTHREAD_CANCEL
00160 if(started && !running)
00161 usleep(50000);
00162 if(started && !running)
00163 std::cerr << "Thread::stop(): Waiting for thread launch to complete (stillborn thread?)" << std::endl;
00164 while(started && !running)
00165 usleep(100000);
00166 if(!running)
00167 return *this;
00168 if(int err=pthread_cancel(pt->threadInfo))
00169 cerr << "Thread cancel(), pthread_cancel("<<pt->threadInfo<<"): " << strerror(err) << endl;
00170 #else
00171
00172 cancelRequested=true;
00173 #endif
00174 #ifdef USE_SIGNAL_TO_CANCEL_THREAD
00175 # ifndef USE_PTHREAD_CANCEL
00176
00177 if(!running)
00178 return *this;
00179 # endif
00180 if(noCancelDepth>0)
00181 return *this;
00182 interrupt();
00183 #else
00184 if(reqIntrDepth>0)
00185 interrupt();
00186 #endif
00187 return *this;
00188 }
00189
00190 Thread& Thread::kill() {
00191 sendSignal(SIGUSR1);
00192 return *this;
00193 }
00194
00195 Thread& Thread::murder() {
00196 if(pt->hasThread) {
00197 if(int err=pthread_detach(pt->threadInfo))
00198 cerr << "Thread kill(), thread_detach: " << strerror(err) << endl;
00199 pt->hasThread=false;
00200 }
00201 sendSignal(SIGSTOP);
00202 started=running=false;
00203 exited=true;
00204 return *this;
00205 }
00206
00207 void Thread::sendSignal(int sig) {
00208 if(started && !running)
00209 usleep(50000);
00210 if(started && !running)
00211 std::cerr << "Thread::stop(): Waiting for thread launch to complete (stillborn thread?)" << std::endl;
00212 while(started && !running)
00213 usleep(100000);
00214 if(!isRunning())
00215 return;
00216 if(int err=pthread_kill(pt->threadInfo,sig))
00217 if(err!=ESRCH)
00218 cerr << "Thread sendSignal(), pthread_kill("<<sig<<"): " << strerror(err) << endl;
00219 }
00220
00221 void * Thread::join() const {
00222 MarkScope l(startLock);
00223 if(!started || !pt->hasThread)
00224 return cancelRequested ? CANCELLED : returnValue;
00225 void * ans=NULL;
00226 pthread_t cur = pt->threadInfo;
00227 pt->hasThread = false;
00228 if(int err=pthread_join(cur, &ans)) {
00229 cerr << "thread join() returned " << err << " " << strerror(err) << endl;
00230 if((err==EINVAL || err==ESRCH) && (!started || !pthread_equal(cur, pt->threadInfo)))
00231 return cancelRequested ? CANCELLED : returnValue;
00232 cerr << "Thread join() " << err << " (" << EINVAL << ',' << ESRCH << "), pthread_join: " << strerror(err) << endl;
00233 stacktrace::displayCurrentStackTrace();
00234 }
00235 return ans;
00236 }
00237
00238 Thread* Thread::getCurrent() {
00239 if(Threadstorage_t::selfKey==INVALID_THREADKEY) {
00240 static bool gaveError=false;
00241 if(!gaveError) {
00242 cerr << "ERROR: In Thread::getCurrent(), selfKey uninitialized; Thread::initMainThread was not called." << endl;
00243 cerr << " (This error will only be displayed once)" << endl;
00244 gaveError=true;
00245 }
00246 return NULL;
00247 }
00248 return static_cast< Thread* >(pthread_getspecific(Threadstorage_t::selfKey));
00249 }
00250
00251 void Thread::initMainThread() {
00252 if(int err=pthread_key_create(&Threadstorage_t::selfKey,warnSelfUndestructed))
00253 cerr << "WARNING: In Thread::initMainThread(), pthread_key_create(selfKey) returned " << strerror(err) << endl;
00254 if(int err=pthread_setspecific(Threadstorage_t::selfKey,NULL))
00255 cerr << "WARNING: In Thread::initMainThread(), pthread_setspecific(selfKey) returned " << strerror(err) << endl;
00256 }
00257
00258 void Thread::releaseMainThread() {
00259
00260 if(Threadstorage_t::selfKey==INVALID_THREADKEY)
00261 return;
00262 if(int err=pthread_key_delete(Threadstorage_t::selfKey))
00263 cerr << "WARNING: In Thread::releaseMainThread, pthread_key_delete(selfKey) returned " << strerror(err) << endl;
00264 }
00265
00266 void Thread::testCurrentCancel() {
00267 Thread * cur = getCurrent();
00268 if(cur==NULL) {
00269 #ifdef USE_PTHREAD_CANCEL
00270 pthread_testcancel();
00271 #endif
00272 return;
00273 }
00274 #ifdef DEBUG
00275 if(cur->noCancelDepth!=0) {
00276 cerr << "WARNING: Thread::testCancel called with noCancelDepth=="<<cur->noCancelDepth<<" (process="<<ProcessID::getID()<<", thread="<<pthread_self()<<")"<<endl;
00277 cerr << "The thread was started at:" << endl;
00278 stacktrace::displayStackTrace(cur->startTrace);
00279 cerr << "The testCancel call is from:" << endl;
00280 stacktrace::displayCurrentStackTrace();
00281 }
00282 #endif
00283 if(cur->noCancelDepth!=0 || cur->cancelInProgress)
00284 return;
00285 #ifdef USE_PTHREAD_CANCEL
00286 cur->cancelInProgress=true;
00287 pthread_testcancel();
00288 cur->cancelInProgress=false;
00289 #else
00290 if(cur->cancelRequested) {
00291 cur->cancelInProgress=true;
00292 throw cancellation_exception();
00293 }
00294 #endif
00295 }
00296
00297 void * Thread::launch(void * msg) {
00298
00299 Thread* cur=static_cast<Thread*>(msg);
00300 if(cur==NULL) {
00301 cerr << "ERROR: Thread::launch with NULL msg" << endl;
00302 return NULL;
00303 }
00304
00305 if(int err=pthread_setspecific(Threadstorage_t::selfKey,msg))
00306 cerr << "WARNING: In Thread::launch(), pthread_setspecific(selfKey) returned " << strerror(err) << endl;
00307
00308 cur->cancelInProgress=false;
00309
00310
00311 if(int err=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL))
00312 cerr << "Thread launch(), pthread_setcanceltype: " << strerror(err) << endl;
00313 ++(cur->noCancelDepth);
00314 if(signal(SIGUSR1,Thread::handle_launch_signal)==SIG_ERR)
00315 perror("Thread launch(), signal(SIGUSR1,handle_launch_signal)");
00316 cur->running=true;
00317 if(!cur->launched()) {
00318
00319 --(cur->noCancelDepth);
00320 handle_exit(NULL);
00321 return cur->returnValue;
00322 }
00323 --(cur->noCancelDepth);
00324
00325
00326
00327 cur->returnValue=CANCELLED;
00328
00329
00330
00331 pthread_cleanup_push(Thread::handle_exit,msg); {
00332
00333 if(signal(SIGUSR1,Thread::handle_signal)==SIG_ERR)
00334 perror("Thread launch(), signal(SIGUSR1,handle_signal)");
00335
00336 try {
00337 if(cur->noCancelDepth==0) {
00338
00339 if(int err=pthread_setcancelstate(cur->cancelOrig,NULL))
00340 cerr << "Thread launch(), pthread_setcancelstate: " << strerror(err) << endl;
00341 if(int err=pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL))
00342 cerr << "Thread launch(), pthread_setcanceltype: " << strerror(err) << endl;
00343 cur->testCancel();
00344 }
00345 cur->returnValue=cur->run();
00346 } catch(const Thread::cancellation_exception&) {
00347
00348
00349 }
00350
00351
00352
00353
00354
00355
00356
00357 } pthread_cleanup_pop(true);
00358 return cur->returnValue;
00359 }
00360
00361 void Thread::handle_launch_signal(int ) {
00362 handle_exit(NULL);
00363 pthread_exit(NULL);
00364 }
00365
00366 void Thread::handle_signal(int ) {
00367 pthread_exit(NULL);
00368 }
00369
00370 void Thread::handle_exit(void * th) {
00371
00372 Thread* cur=getCurrent();
00373 if(cur==NULL) {
00374 cerr << "ERROR: handle_exit called for a NULL thread" << endl;
00375 if(th!=NULL) {
00376 static_cast<Thread*>(th)->cancelled();
00377 static_cast<Thread*>(th)->started=static_cast<Thread*>(th)->running=false;
00378 }
00379 return;
00380 }
00381
00382 {
00383 MarkScope l(cur->stopLock);
00384 if(th!=NULL && th!=cur)
00385 cerr << "WARNING: handle_exit argument does not match selfKey" << endl;
00386 if(cur->noCancelDepth!=0) {
00387 cerr << "WARNING: thread " << pthread_self() << " of ProcessID_t " << ProcessID::getID() << " exited while noCancelDepth>0 (was " << cur->noCancelDepth << ")" << endl;
00388 cerr << " This may indicate a mutex was left locked." << endl;
00389 cur->noCancelDepth=0;
00390 }
00391 if(int err=pthread_setspecific(Threadstorage_t::selfKey,NULL))
00392 cerr << "WARNING: In Thread::handle_exit(), pthread_setspecific(selfKey) returned " << err << endl;
00393 cur->cancelled();
00394 cur->started=cur->running=false;
00395 cur->exited=true;
00396 }
00397 cur->dereference();
00398 }
00399
00400 void Thread::pushNoCancel() {
00401 Thread * cur=getCurrent();
00402 if(cur==NULL) {
00403
00404
00405 if(int err=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL))
00406 cerr << "ERROR: Thread pushNoCancel(), pthread_setcanceltype: " << strerror(err) << endl;
00407 } else {
00408 ++(cur->noCancelDepth);
00409 int previous=-1;
00410 if(int err=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&previous))
00411 cerr << "ERROR: Thread pushNoCancel(), pthread_setcanceltype: " << strerror(err) << endl;
00412 #ifdef THREADCANCEL_SANITY_CHECKS
00413 if(cur->noCancelDepth==1 && previous!=cur->cancelOrig)
00414 cerr << "WARNING: In Thread::pushNoCancel, cancel state was wrong (was " << previous << ", expected " << cur->cancelOrig << ")" << endl;
00415 else if(cur->noCancelDepth!=1 && previous!=PTHREAD_CANCEL_DISABLE)
00416 cerr << "WARNING: In Thread::pushNoCancel, cancel state was somehow re-enabled" << endl;
00417 #endif
00418 }
00419 }
00420 void Thread::popNoCancel(bool doTestCancel) {
00421 Thread * cur=getCurrent();
00422 if(cur==NULL) {
00423
00424
00425 return;
00426 } else if(cur->noCancelDepth==0) {
00427 cerr << "ERROR: Thread::popNoCancel underflow" << endl;
00428 } else
00429 --(cur->noCancelDepth);
00430 int previous=-1;
00431 if(cur->noCancelDepth==0) {
00432 if(int err=pthread_setcancelstate(cur->cancelOrig,&previous))
00433 cerr << "ERROR: Thread popNoCancel(), pthread_setcanceltype: " << strerror(err) << endl;
00434 if(cur->cancelOrig==PTHREAD_CANCEL_ENABLE && doTestCancel)
00435 cur->testCancel();
00436 }
00437 #ifdef THREADCANCEL_SANITY_CHECKS
00438 else {
00439 if(int err=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&previous))
00440 cerr << "ERROR: Thread popNoCancel(), pthread_setcanceltype: " << strerror(err) << endl;
00441 }
00442 if(previous!=PTHREAD_CANCEL_DISABLE)
00443 cerr << "WARNING: In Thread::popNoCancel, cancel state was somehow re-enabled" << endl;
00444 #endif
00445 }
00446
00447 void Thread::requestInterruptOnCancel() {
00448 #ifndef USE_SIGNAL_TO_CANCEL_THREAD
00449 Thread * cur=getCurrent();
00450 if(cur==NULL)
00451 return;
00452 pushNoCancel();
00453 ++(cur->reqIntrDepth);
00454 #ifdef DEBUG
00455 if(cur->reqIntrDepth!=1)
00456 std::cerr << "WARNING: recursive Thread::requestInterruptOnCancel() " << cur->reqIntrDepth << std::endl;
00457 #endif
00458 #endif
00459 }
00460
00461 void Thread::unrequestInterruptOnCancel() {
00462 #if !defined(USE_SIGNAL_TO_CANCEL_THREAD) || !defined(USE_TESTCANCEL_IN_INTERRUPT)
00463 Thread * cur=getCurrent();
00464 if(cur==NULL)
00465 return;
00466 #endif
00467 #ifndef USE_SIGNAL_TO_CANCEL_THREAD
00468 if(cur->reqIntrDepth==0) {
00469 cerr << "ERROR: Thread::unrequestInterruptOnCancel underflow" << endl;
00470 } else {
00471 --(cur->reqIntrDepth);
00472 }
00473 popNoCancel();
00474 #endif
00475 #ifndef USE_TESTCANCEL_IN_INTERRUPT
00476 if(cur->noCancelDepth==0)
00477 cur->testCancel();
00478 #endif
00479 }
00480
00481 void Thread::handleInterrupt(int ) {
00482
00483
00484 Thread * cur=Thread::getCurrent();
00485 if(cur==NULL) {
00486
00487
00488
00489 return;
00490 }
00491 #ifdef USE_TESTCANCEL_IN_INTERRUPT
00492 if(cur->noCancelDepth==0)
00493 cur->testCancel();
00494 #endif
00495 cur->interrupted();
00496 }
00497
00498 void Thread::warnSelfUndestructed(void* msg) {
00499 cerr << "ERROR: Thread local data (selfKey) not deleted by Thread::handle_exit" << endl;
00500 Thread* cur = getCurrent();
00501 if(cur!=NULL)
00502 cerr << " Weird, key wasn't cleared... (" << cur << ") " << cur->noCancelDepth << " locks on stack? " << endl;;
00503 if(msg==NULL) {
00504 cerr << " Message is null, warnCancelDepthUndestructed shouldn't have been called." << endl;
00505 } else {
00506 if(cur!=NULL && cur!=msg)
00507 cerr << " and current thread does not match msg (" << cur << " vs " << msg << ")" << endl;
00508 cur = static_cast<Thread*>(msg);
00509 }
00510 if(cur!=NULL) {
00511
00512 if(cur->noCancelDepth==0) {
00513 cerr << " But at least the depth is 0" << endl;
00514 } else {
00515 cerr << " The depth indicates there may be " << cur->noCancelDepth << " locks left in place" << endl;
00516 }
00517 cur->cancelled();
00518 cur->started=cur->running=false;
00519 pthread_setspecific(Threadstorage_t::selfKey,NULL);
00520 }
00521 }
00522
00523
00524
00525
00526 class Thread::Lock::LockStorage : public ReferenceCounter {
00527 friend class Thread::Condition;
00528 public:
00529
00530 LockStorage() : ReferenceCounter(), locklevel(0), mutex(), attr(), threadkey() {
00531 addReference();
00532 pthread_mutexattr_init(&attr);
00533 pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
00534 pthread_mutex_init(&mutex,&attr);
00535 }
00536
00537 ~LockStorage() {
00538 pthread_mutexattr_destroy(&attr);
00539 pthread_mutex_destroy(&mutex);
00540 if(locklevel>1)
00541 cerr << "WARNING: lockstorage destructed with " << locklevel << " locks still in effect" << endl;
00542 while(locklevel>0) {
00543 locklevel--;
00544 Thread::popNoCancel(false);
00545 }
00546 }
00547
00548 LockStorage(const LockStorage& ls) : ReferenceCounter(ls), locklevel(ls.locklevel), mutex(ls.mutex), attr(ls.attr), threadkey(ls.threadkey) {}
00549
00550 LockStorage& operator=(const LockStorage& ls) { ReferenceCounter::operator=(ls); locklevel=ls.locklevel; mutex=ls.mutex; attr=ls.attr; threadkey=ls.threadkey; return *this; }
00551
00552
00553 void lock() {
00554 if(int err=pthread_mutex_lock(&mutex)) {
00555 cerr << "ERROR: Thread::Lock::lock() failed: " << strerror(err) << endl;
00556 } else {
00557 locklevel++;
00558 }
00559 }
00560
00561 bool trylock() {
00562 if(!pthread_mutex_trylock(&mutex)) {
00563 locklevel++;
00564 return true;
00565 } else {
00566 return false;
00567 }
00568 }
00569
00570 void unlock() {
00571 if(locklevel==0) {
00572 cerr << "ERROR: Thread::Lock::unlock() underflow" << endl;
00573 stacktrace::displayCurrentStackTrace();
00574 }
00575 locklevel--;
00576 if(int err=pthread_mutex_unlock(&mutex))
00577 cerr << "ERROR: Thread::Lock::unlock() failed: " << strerror(err) << endl;
00578 }
00579
00580 unsigned int getLockLevel() { return locklevel; }
00581
00582 protected:
00583 unsigned int locklevel;
00584 pthread_mutex_t mutex;
00585 pthread_mutexattr_t attr;
00586 pthread_key_t threadkey;
00587 };
00588
00589 Thread::Lock::LockStorage* Thread::Lock::glock=NULL;
00590
00591
00592 Thread::Lock::Lock() : mylock(new LockStorage), locklevel(0) {
00593 if(glock==NULL)
00594 setup();
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
00626 Thread::Lock::~Lock() {
00627 glock->lock();
00628 if(locklevel>1)
00629 cerr << "WARNING: Thread::Lock destructed with "<<locklevel<<" locks still in effect" << endl;
00630 if(!mylock->removeReference()) {
00631 std::cerr << "Lock was deleted with external reference?" << std::endl;
00632 stacktrace::displayCurrentStackTrace();
00633 while(locklevel>0)
00634 unlock();
00635 }
00636 mylock=NULL;
00637 glock->unlock();
00638 }
00639
00640 void Thread::Lock::useResource(Resource::Data&) {
00641 mylock->lock();
00642 locklevel++;
00643 }
00644 bool Thread::Lock::trylock() {
00645 Thread::pushNoCancel();
00646 if(mylock->trylock()) {
00647 locklevel++;
00648 return true;
00649 } else {
00650 Thread::popNoCancel();
00651 return false;
00652 }
00653 }
00654 void Thread::Lock::releaseResource(Resource::Data&) {
00655 locklevel--;
00656 mylock->unlock();
00657 }
00658 unsigned int Thread::Lock::getLockLevel() const {
00659 return mylock->getLockLevel();
00660 }
00661 void Thread::Lock::setup() {
00662 if(glock==NULL)
00663 glock=new LockStorage;
00664 }
00665
00666
00667
00668
00669 class Thread::Condition::ConditionStorage {
00670 public:
00671
00672 ConditionStorage() : cond() {
00673 if(int err=pthread_cond_init(&cond,NULL)) {
00674 cerr << "ERROR: Thread::Condition::ConditionStorage() failed: " << strerror(err) << endl;
00675 }
00676 }
00677
00678 ~ConditionStorage() {
00679 if(int err=pthread_cond_destroy(&cond)) {
00680 cerr << "ERROR: Thread::Condition::~ConditionStorage() failed: " << strerror(err) << endl;
00681 }
00682 }
00683
00684 pthread_cond_t cond;
00685 };
00686
00687
00688 Thread::Condition::Condition() : mycond(new ConditionStorage) {}
00689 Thread::Condition::~Condition() { delete mycond; mycond=NULL; }
00690
00691 void Thread::Condition::broadcast() const {
00692 if(int err=pthread_cond_broadcast(&mycond->cond)) {
00693 cerr << "ERROR: Thread::Condition::broadcast() failed: " << strerror(err) << endl;
00694 }
00695 }
00696 void Thread::Condition::signal() const {
00697 if(int err=pthread_cond_signal(&mycond->cond)) {
00698 cerr << "ERROR: Thread::Condition::signal() failed: " << strerror(err) << endl;
00699 }
00700 }
00701 bool Thread::Condition::timedwait(Lock& l, const timespec* abstime, bool noWarn) const {
00702 #ifdef USE_SIGNAL_TO_CANCEL_THREAD
00703 Thread::testCurrentCancel();
00704 #endif
00705 unsigned int locklevel=l.mylock->locklevel;
00706 if(locklevel==1) {
00707
00708 } else if(locklevel>1) {
00709 if(!noWarn)
00710 displayRecursiveLockWarning("timedwait",locklevel);
00711 while(l.mylock->locklevel>1)
00712 l.mylock->unlock();
00713 } else {
00714 throw std::logic_error("Thread::Condition::timedwait() called without holding lock");
00715 }
00716 if(int err=pthread_cond_timedwait(&mycond->cond,&l.mylock->mutex,abstime)) {
00717 if(err!=ETIMEDOUT)
00718 cerr << "ERROR: Thread::Condition::timedwait() failed: " << strerror(err) << endl;
00719 while(l.mylock->locklevel<locklevel)
00720 l.mylock->lock();
00721 return false;
00722 }
00723 while(l.getLockLevel()<locklevel)
00724 l.mylock->lock();
00725 #ifdef USE_SIGNAL_TO_CANCEL_THREAD
00726 Thread::testCurrentCancel();
00727 #endif
00728 return true;
00729 }
00730 void Thread::Condition::wait(Lock& l, bool noWarn) const {
00731 #ifdef USE_SIGNAL_TO_CANCEL_THREAD
00732 Thread::testCurrentCancel();
00733 #endif
00734 unsigned int locklevel=l.mylock->locklevel;
00735 if(locklevel==1) {
00736
00737 } else if(locklevel>1) {
00738 if(!noWarn)
00739 displayRecursiveLockWarning("wait",locklevel);
00740 while(l.mylock->locklevel>1)
00741 l.mylock->unlock();
00742 } else {
00743 throw std::logic_error("Thread::Condition::wait() called without holding lock");
00744 }
00745 if(int err=pthread_cond_wait(&mycond->cond,&l.mylock->mutex)) {
00746 cerr << "ERROR: Thread::Condition::wait() failed: " << strerror(err) << endl;
00747 }
00748 while(l.getLockLevel()<locklevel)
00749 l.mylock->lock();
00750 #ifdef USE_SIGNAL_TO_CANCEL_THREAD
00751 Thread::testCurrentCancel();
00752 #endif
00753 }
00754
00755 void Thread::Condition::displayRecursiveLockWarning(const char * fn, unsigned int locklevel) {
00756 std::cerr << "WARNING: Thread::Condition::"<<fn<<"() called holding a recursive lock. (depth " << locklevel << ")\n"
00757 " You should verify outer lock scopes are safe to temporarily free during wait,\n"
00758 " then pass 'true' for the noWarn argument to timedwait() to disable this message." << std::endl;
00759 stacktrace::displayCurrentStackTrace();
00760 }
00761
00762
00763 #endif // PLATFORM check
00764
00765
00766
00767
00768