Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

Thread.cc

Go to the documentation of this file.
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 /*! @cond INTERNAL */
00023 //! provides the system-dependent implementation of a thread
00024 struct Threadstorage_t {
00025   //! constructor
00026   Threadstorage_t() : threadInfo(), hasThread(false) {}
00027   
00028   //! the main POSIX reference to the thread
00029   pthread_t threadInfo;
00030   //! Set to true when threadInfo is given to pthread_create (can't rely on 0/NULL being an invalid thread), so it can pthread_detach before overwrite
00031   /*! We'll assume joinability, leave the thread joinable (i.e. not detached) until the main Thread class either starts a new thread, is deleted, or is joined. */
00032   bool hasThread;
00033   
00034   //! storage which will be set up as a thread-specific memory value, so threads can tell themselves apart
00035   static pthread_key_t selfKey;
00036 private:
00037   Threadstorage_t(const Threadstorage_t& r); //!< don't call
00038   Threadstorage_t& operator=(const Threadstorage_t& r); //!< don't call
00039 };
00040 static const pthread_key_t INVALID_THREADKEY=(pthread_key_t)-1;
00041 pthread_key_t Threadstorage_t::selfKey=INVALID_THREADKEY;
00042 /*! @endcond */
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   /*if(pt==NULL) {
00067     std::cerr << "Thread storage already deleted!?!?!" << std::endl;
00068     *(int*)NULL=0xDEADDEAD;
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; // OS X default is 512KB, let's up that to 2MB (portably)
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   // this return is just to satisfy warnings with silly compiler
00132   return returnValue; //never happens -- cancel or max sleep time would exit
00133 }
00134 
00135 Thread& Thread::interrupt() {
00136   if(!isRunning()) //can't interrupt before thread has been launched!
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   // not using pthread_cancel, don't have to wait for launch to complete -- just set flag now
00171   cancelRequested=true;
00172 #endif
00173 #ifdef USE_SIGNAL_TO_CANCEL_THREAD
00174 #  ifndef USE_PTHREAD_CANCEL
00175   // not using pthread_cancel, if launch hasn't completed, don't wait around just to signal it.  Launch will test cancellation after calling launched().
00176   if(!running)
00177     return *this;
00178 #  endif
00179   if(noCancelDepth>0)
00180     return *this;
00181   interrupt(); // break thread out of any long sleep commands
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) // thread exit during send?
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) // already gone?
00223     return cancelRequested ? CANCELLED : returnValue;
00224   void * ans=NULL;
00225   pthread_t cur = pt->threadInfo;
00226   pt->hasThread = false; // one way or another, don't try to detach or join again...
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))) // already gone?
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   //handle_exit(NULL);
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) { // already gave warning in getCurrent
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; // if next line engages cancellation, don't throw again during this throw!
00286   pthread_testcancel();
00287   cur->cancelInProgress=false; // phew, guess we're still running, reset flag
00288 #else
00289   if(cur->cancelRequested) {
00290     cur->cancelInProgress=true; // don't throw again during this throw!
00291     throw cancellation_exception();
00292   }
00293 #endif
00294 }
00295 
00296 void * Thread::launch(void * msg) {
00297   //cout << "Spawn thread " << pthread_self() << " from process " << ProcessID::getID() << endl;
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   //disable cancel while calling launch()
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     //subclass's launch cancelled launch
00318     --(cur->noCancelDepth);
00319     handle_exit(NULL);
00320     return cur->returnValue;
00321   }
00322   --(cur->noCancelDepth);
00323   
00324   // handle_exit calls dereference(), which may delete this; store the return value since 'cur' can't be trusted
00325   // also, if this is not overwritten, indicates cancellation occurred.
00326   cur->returnValue=CANCELLED; 
00327   
00328   //These pthread functions actually define a scope between them (ugh)
00329   //I've added braces of my own to make this explicitly clear
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         //reset cancelability before run
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       // if on a system not using pthread_cancel, we throw this exception from testCancel to trigger stack unwinding so we can exit...
00347       // note returnedValue remains 'CANCELLED' since we excepted instead of returning
00348     }
00349     /* catch(const std::exception& e) {
00350       std::cout << "WTF is this exception? " << e.what() << std::endl;
00351       cancelDetected=true;
00352     } catch(...) {
00353       std::cout << "WTF is this unknown exception?" << std::endl;
00354     }*/
00355     
00356   } pthread_cleanup_pop(true);
00357   return cur->returnValue;
00358 }
00359 
00360 void Thread::handle_launch_signal(int /*sig*/) {
00361   handle_exit(NULL);
00362   pthread_exit(NULL);
00363 }
00364 
00365 void Thread::handle_signal(int /*sig*/) {
00366   pthread_exit(NULL);
00367 }
00368 
00369 void Thread::handle_exit(void * th) {
00370   //cout << "Cull thread " << pthread_self() << endl;
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   { //scope limiting for stop lock, release lock before dereference in case it deletes this
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; // reset in case run again
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     //cerr << "ERROR: Thread::pushNoCancel was given NULL thread by getCurrent, thread=" << pthread_self() << endl;
00403     //not so bad, indicates already canceled -- don't test cancel again, don't want to cancel-recurse
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/*=true*/) {
00420   Thread * cur=getCurrent();
00421   if(cur==NULL) {
00422     //cerr << "ERROR: Thread::popNoCancel was given NULL thread by getCurrent, thread=" << pthread_self() << endl;
00423     //not so bad, indicates already canceled -- don't test cancel again, don't want to cancel-recurse
00424     return; //no point in continuing
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(); // I thought setcancelstate(ENABLE) implied this, but apparently not
00435   }
00436 #ifdef THREADCANCEL_SANITY_CHECKS
00437   else { //still disabled, double check it
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; //no point in continuing
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; //no point in continuing
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 /*signal*/) {
00481   //if(signal(SIGALRM,SIG_DFL)==SIG_ERR)
00482   //  perror("Thread::handleInterrupt(): could not re-enable signal");
00483   Thread * cur=Thread::getCurrent();
00484   if(cur==NULL) {
00485     // implies signal handler was delivered when in the process of shutting down
00486     // just give up on it silently
00487     //std::cerr << "Thread::handleInterrupt called from non-Thread" << endl;
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     //try to recover
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 /*! @cond INTERNAL */
00524 //! This handles the actual lock implementation, which allows Lock to provide an abstract interface
00525 class Thread::Lock::LockStorage : public ReferenceCounter {
00526   friend class Thread::Condition;
00527 public:
00528   //! constructor
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   //! destructor, releases any pending locks (with warning
00536   ~LockStorage() {
00537     pthread_mutexattr_destroy(&attr);
00538     pthread_mutex_destroy(&mutex);
00539     if(locklevel>1) //having one left is ok, perhaps even good (keeping the lock as it is destroyed)
00540       cerr << "WARNING: lockstorage destructed with " << locklevel << " locks still in effect" << endl;
00541     while(locklevel>0) {
00542       locklevel--;
00543       Thread::popNoCancel(false); // no testCancel because we could be in unwind from previous exception, cancellation here is non-portable (causes terminate on OS X)
00544     }
00545   }
00546   //! copy constructor (functional!) -- both locks will wind up referencing the same system resource, so this is more of an alias than a clone
00547   LockStorage(const LockStorage& ls) : ReferenceCounter(ls), locklevel(ls.locklevel), mutex(ls.mutex), attr(ls.attr), threadkey(ls.threadkey) {}
00548   //! assignment (functional!) -- both locks will wind up referencing the same system resource, so this is more of an alias than a clone
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   //! trigger and wait for a mutual exclusion lock, recursively
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   //! attempt to get a lock, but return false if it is not immediately available
00560   bool trylock() {
00561     if(!pthread_mutex_trylock(&mutex)) {
00562       locklevel++;
00563       return true;
00564     } else {
00565       return false;
00566     }
00567   }
00568   //! release a lock (recursively, won't actually release the lock resource until all calls to lock() have been balanced)
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   //! returns the depth of the lock recursion (#locklevel)
00579   unsigned int getLockLevel() { return locklevel; }
00580   
00581 protected:
00582   unsigned int locklevel; //!< depth of lock recursion (i.e. number of calls to lock() minus calls to unlock())
00583   pthread_mutex_t mutex; //!< system lock resource
00584   pthread_mutexattr_t attr; //!< system lock resource attributes (used to specify #mutex is recursive in the system as well)
00585   pthread_key_t threadkey; //!< not making use of the thread specific nature of these, but we are making use of the call to a destructor (emergencyUnlock) on cancel
00586 };
00587 
00588 Thread::Lock::LockStorage* Thread::Lock::glock=NULL;
00589 /*! @endcond */
00590 
00591 Thread::Lock::Lock() : mylock(new LockStorage), locklevel(0) {
00592   if(glock==NULL)
00593     setup();
00594 }
00595 /*Thread::Lock::Lock(const Lock& l)
00596   : mylock(l.mylock), locklevel(0)
00597 {
00598   glock->lock();
00599   mylock->addReference();
00600   glock->unlock();
00601   lock();
00602 }
00603 Thread::Lock::Lock(const Lock& l, bool autolock)
00604   : mylock(l.mylock), locklevel(0)
00605 {
00606   glock->lock();
00607   mylock->addReference();
00608   glock->unlock();
00609   if(autolock)
00610     lock();
00611 }
00612 Thread::Lock& Thread::Lock::operator=(const Lock& l) {
00613   glock->lock();
00614   lock();
00615   if(locklevel>2)
00616     cerr << "WARNING: Thread::Lock overwritten with "<<locklevel<<" locks still in effect" << endl;
00617   if(!mylock->removeReference())
00618     while(locklevel>0)
00619       unlock();
00620   mylock=l.mylock;
00621   locklevel=0;
00622   glock->unlock();
00623   return *this;
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 /*! @cond INTERNAL */
00666 //! Implement system-dependent portion of a thread condition, a signaling mechanism.
00667 /*! This is a very basic wrapper -- just adds a constructor and destructor to the POSIX pthread_cond_t. */
00668 class Thread::Condition::ConditionStorage {
00669 public:
00670   //! constructor
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   //! destructor
00677   ~ConditionStorage() {
00678     if(int err=pthread_cond_destroy(&cond)) {
00679       cerr << "ERROR: Thread::Condition::~ConditionStorage() failed: " << strerror(err) << endl;
00680     }
00681   }
00682   //! system resource storage
00683   pthread_cond_t cond;
00684 };
00685 /*! @endcond */
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/*=false*/) 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     // no-op for common case to shortcut other tests
00707   } else if(locklevel>1) {
00708     if(!noWarn)
00709       displayRecursiveLockWarning("timedwait",locklevel);
00710     while(l.mylock->locklevel>1)
00711       l.mylock->unlock();
00712   } else { // 0
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/*=false*/) 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     // no-op for common case to shortcut other tests
00736   } else if(locklevel>1) {
00737     if(!noWarn)
00738       displayRecursiveLockWarning("wait",locklevel);
00739     while(l.mylock->locklevel>1)
00740       l.mylock->unlock();
00741   } else { // 0
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 /*! @file
00765 * @brief Describes the Thread class and its AutoThread templated subclass
00766 * @author ejt (Creator)
00767 */

Tekkotsu v5.1CVS
Generated Sat May 4 06:33:03 2013 by Doxygen 1.6.3