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 
00006 #include <pthread.h>
00007 #include <string.h>
00008 #include <iostream>
00009 #include <signal.h>
00010 #include <unistd.h>
00011 #include <cassert>
00012 
00013 using namespace std;
00014 
00015 #define THREADCANCEL_SANITY_CHECKS
00016 
00017 struct Threadstorage_t {
00018   Threadstorage_t() : threadInfo(), threadAttr() {
00019     if(int err=pthread_attr_init(&threadAttr))
00020       cerr << "Threadstorage_t constructor, pthread_attr_init: " << strerror(err) << endl;;
00021   }
00022   ~Threadstorage_t() {
00023     if(int err=pthread_attr_destroy(&threadAttr))
00024       cerr << "Threadstorage_t destructor, pthread_attr_destroy: " << strerror(err) << endl;
00025   }
00026   pthread_t threadInfo;
00027   pthread_attr_t threadAttr;
00028   static pthread_key_t selfKey;
00029 private:
00030   Threadstorage_t(const Threadstorage_t& r); //!< don't call
00031   Threadstorage_t& operator=(const Threadstorage_t& r); //!< don't call
00032 };
00033 pthread_key_t Threadstorage_t::selfKey=0;
00034 
00035 Thread::Thread()
00036   : pt(new Threadstorage_t), running(false), returnValue(NULL),
00037   noCancelDepth(0), cancelOrig(PTHREAD_CANCEL_ENABLE)
00038 {}
00039 
00040 Thread::~Thread() {
00041   //can only happen externally
00042   if(running) {
00043     stop();
00044     join();
00045   }
00046   /*if(pt==NULL) {
00047     std::cerr << "Thread storage already deleted!?!?!" << std::endl;
00048     *(int*)NULL=0xDEADDEAD;
00049   }*/
00050   assert(pt!=NULL);
00051   delete pt;
00052   pt=NULL;
00053 }
00054 
00055 void Thread::start() {
00056   if(running) {
00057     std::cerr << "Thread::start() -- thread is already running!" << std::endl;
00058     std::cerr << "   make another instance if you want to run another copy of this thread" << std::endl;
00059     return;
00060   }
00061   running=true;
00062   if(int err=pthread_create(&pt->threadInfo, &pt->threadAttr, launch, this))
00063     cerr << "Thread start(), pthread_create: " << strerror(err) << endl;
00064 }
00065 
00066 void * Thread::run() {
00067   for(;;) {
00068     unsigned int sleeptime=runloop();
00069     if(sleeptime==-1U)
00070       return returnValue;
00071     if(sleeptime>0)
00072       usleep(sleeptime);
00073     testCancel();
00074   }
00075   // this return is just to satisfy warnings with silly compiler
00076   return returnValue; //never happens -- cancel or max sleep time would exit
00077 }
00078 
00079 void Thread::stop() {
00080   if(!running) {
00081     std::cerr << "Thread::stop() -- thread is already stopped!" << std::endl;
00082     return;
00083   }
00084   if(int err=pthread_cancel(pt->threadInfo))
00085     cerr << "Thread cancel(), pthread_cancel("<<pt->threadInfo<<"): " << strerror(err) << endl;
00086 }
00087 
00088 void Thread::kill() {
00089   sendSignal(SIGUSR1);
00090 }
00091 
00092 void Thread::murder() {
00093   if(int err=pthread_detach(pt->threadInfo))
00094     cerr << "Thread kill(), thread_detach: " << strerror(err) << endl;
00095   sendSignal(SIGSTOP);
00096   running=false;
00097 }
00098 
00099 void Thread::sendSignal(int sig) {
00100   if(!isRunning())
00101     return;
00102   if(int err=pthread_kill(pt->threadInfo,sig))
00103     cerr << "Thread kill(), pthread_kill("<<sig<<"): " << strerror(err) << endl;
00104 }
00105 
00106 void * Thread::join() {
00107   void * ans=NULL;
00108   if(int err=pthread_join(pt->threadInfo, &ans))
00109     cerr << "Thread join(), pthread_join: " << strerror(err) << endl;
00110   return ans;
00111 }
00112 
00113 Thread* Thread::getCurrent() {
00114   if(Threadstorage_t::selfKey==0) {
00115     static bool gaveError=false;
00116     if(!gaveError) {
00117       cerr << "ERROR: In Thread::getCurrent(), selfKey uninitialized; Thread::initMainThread was not called." << endl;
00118       cerr << "       (This error will only be displayed once)" << endl;
00119       gaveError=true;
00120     }
00121     return NULL;
00122   }
00123   return static_cast< Thread* >(pthread_getspecific(Threadstorage_t::selfKey));
00124 }
00125 
00126 void Thread::initMainThread() {
00127   if(int err=pthread_key_create(&Threadstorage_t::selfKey,warnSelfUndestructed))
00128     cerr << "WARNING: In Thread::initMainThread(), pthread_key_create(selfKey) returned " << strerror(err) << endl;
00129   if(int err=pthread_setspecific(Threadstorage_t::selfKey,NULL))
00130     cerr << "WARNING: In Thread::initMainThread(), pthread_setspecific(selfKey) returned " << strerror(err) << endl;
00131 }
00132 
00133 void Thread::releaseMainThread() {
00134   //handle_exit(NULL);
00135   if(int err=pthread_key_delete(Threadstorage_t::selfKey))
00136     cerr << "WARNING: In Thread::releaseMainThread, pthread_key_delete(selfKey) returned " << strerror(err) << endl;
00137 }
00138 
00139 void Thread::testCancel() {
00140 #ifdef DEBUG
00141   if(noCancelDepth!=0) {
00142     cerr << "WARNING: Thread::testCancel called with noCancelDepth=="<<noCancelDepth<<" (process="<<ProcessID::getID()<<", thread="<<pthread_self()<<")"<<endl;
00143   }
00144 #endif
00145   pthread_testcancel();
00146 }
00147 
00148 void * Thread::launch(void * msg) {
00149   //cout << "Spawn thread " << pthread_self() << " from process " << ProcessID::getID() << endl;
00150   Thread* cur=static_cast<Thread*>(msg);
00151   if(cur==NULL) {
00152     cerr << "ERROR: Thread::launch with NULL msg" << endl;
00153     return NULL;
00154   }
00155 
00156   if(int err=pthread_setspecific(Threadstorage_t::selfKey,msg))
00157     cerr << "WARNING: In ThreadNS::launch(), pthread_setspecific(selfKey) returned " << strerror(err) << endl;
00158   
00159   //disable cancel while calling launch()
00160   if(int err=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL))
00161     cerr << "Thread launch(), pthread_setcanceltype: " << strerror(err) << endl;
00162   ++(cur->noCancelDepth);
00163   if(signal(SIGUSR1,Thread::handle_launch_signal)==SIG_ERR)
00164     perror("Thread launch(), signal(SIGUSR1,handle_launch_signal)");
00165   if(!cur->launched()) {
00166     //subclass's launch cancelled launch
00167     --(cur->noCancelDepth);
00168     handle_exit(NULL);
00169     return cur->returnValue;
00170   }
00171   --(cur->noCancelDepth);
00172   
00173   //These pthread functions actually define a scope between them (ugh)
00174   //I've added braces of my own to make this explicitly clear
00175   pthread_cleanup_push(Thread::handle_exit,msg); {
00176     
00177     if(signal(SIGUSR1,Thread::handle_signal)==SIG_ERR)
00178       perror("Thread launch(), signal(SIGUSR1,handle_signal)");
00179     
00180     if(cur->noCancelDepth==0) {
00181       //reset cancelability before run
00182       if(int err=pthread_setcancelstate(cur->cancelOrig,NULL))
00183         cerr << "Thread launch(), pthread_setcanceltype: " << strerror(err) << endl;
00184       if(int err=pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL))
00185         cerr << "Thread launch(), pthread_setcanceltype: " << strerror(err) << endl;
00186     }
00187     cur->returnValue=cur->run();
00188     
00189   } pthread_cleanup_pop(true);
00190   return cur->returnValue;
00191 }
00192 
00193 void Thread::handle_launch_signal(int /*sig*/) {
00194   handle_exit(NULL);
00195   pthread_exit(NULL);
00196 }
00197 
00198 void Thread::handle_signal(int /*sig*/) {
00199   pthread_exit(NULL);
00200 }
00201 
00202 void Thread::handle_exit(void * th) {
00203   //cout << "Cull thread " << pthread_self() << endl;
00204   Thread* cur=getCurrent();
00205   if(cur==NULL) {
00206     cerr << "ERROR: handle_exit called for a NULL thread" << endl;
00207     if(th!=NULL) {
00208       static_cast<Thread*>(th)->cancelled();
00209       static_cast<Thread*>(th)->running=false;
00210     }
00211     return;
00212   }
00213   
00214   if(th!=NULL && th!=cur)
00215     cerr << "WARNING: handle_exit argument does not match selfKey" << endl;
00216   if(cur->noCancelDepth!=0) {
00217     cerr << "WARNING: thread " << pthread_self() << " of ProcessID_t " << ProcessID::getID() << " exited while noCancelDepth>0 (was " << cur->noCancelDepth << ")" << endl;
00218     cerr << "         This may indicate a mutex was left locked." << endl;
00219   }
00220   if(int err=pthread_setspecific(Threadstorage_t::selfKey,NULL))
00221     cerr << "WARNING: In Thread::handle_exit(), pthread_setspecific(selfKey) returned " << err << endl;
00222   cur->cancelled();
00223   cur->running=false;
00224 }
00225 
00226 void Thread::pushNoCancel() {
00227   Thread * cur=getCurrent();
00228   if(cur==NULL) {
00229     //cerr << "ERROR: Thread::pushNoCancel was given NULL thread by getCurrent, thread=" << pthread_self() << endl;
00230     //not so bad, indicates already canceled -- don't test cancel again, don't want to cancel-recurse
00231     if(int err=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL))
00232       cerr << "ERROR: Thread pushNoCancel(), pthread_setcanceltype: " << strerror(err) << endl;
00233   } else {
00234     ++(cur->noCancelDepth);
00235     int previous=-1;
00236     if(int err=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&previous))
00237       cerr << "ERROR: Thread pushNoCancel(), pthread_setcanceltype: " << strerror(err) << endl;
00238 #ifdef THREADCANCEL_SANITY_CHECKS
00239     if(cur->noCancelDepth==1 && previous!=cur->cancelOrig)
00240       cerr << "WARNING: In Thread::pushNoCancel, cancel state was wrong (was " << previous << ", expected " << cur->cancelOrig << ")" << endl;
00241     else if(cur->noCancelDepth!=1 && previous!=PTHREAD_CANCEL_DISABLE)
00242       cerr << "WARNING: In Thread::pushNoCancel, cancel state was somehow re-enabled" << endl;
00243 #endif
00244   }
00245 }
00246 void Thread::popNoCancel() {
00247   Thread * cur=getCurrent();
00248   if(cur==NULL) {
00249     //cerr << "ERROR: Thread::popNoCancel was given NULL thread by getCurrent, thread=" << pthread_self() << endl;
00250     //not so bad, indicates already canceled -- don't test cancel again, don't want to cancel-recurse
00251     return; //no point in continuing
00252   } else if(cur->noCancelDepth==0) {
00253     cerr << "ERROR: Thread::popNoCancel underflow" << endl;
00254   } else
00255     --(cur->noCancelDepth);
00256   int previous=-1;
00257   if(cur->noCancelDepth==0) {
00258     if(int err=pthread_setcancelstate(cur->cancelOrig,&previous))
00259       cerr << "ERROR: Thread popNoCancel(), pthread_setcanceltype: " << strerror(err) << endl;
00260   }
00261 #ifdef THREADCANCEL_SANITY_CHECKS
00262   else { //still disabled, double check it
00263     if(int err=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&previous))
00264       cerr << "ERROR: Thread popNoCancel(), pthread_setcanceltype: " << strerror(err) << endl;
00265   }
00266   if(previous!=PTHREAD_CANCEL_DISABLE)
00267     cerr << "WARNING: In Thread::popNoCancel, cancel state was somehow re-enabled" << endl;
00268 #endif
00269 }
00270 void Thread::warnSelfUndestructed(void* msg) {
00271   cerr << "ERROR: Thread local data (selfKey) not deleted by Thread::handle_exit" << endl;
00272   Thread* cur = getCurrent();
00273   if(cur==NULL) {
00274     cerr << "       And the thread is NULL" << endl;
00275   } else if(cur->noCancelDepth==0) {
00276     cerr << "       But at least the depth is 0" << endl;
00277   } else {
00278     cerr << "       The depth indicates there may be " << cur->noCancelDepth << " locks left in place" << endl;
00279   }
00280   if(msg==NULL) {
00281     cerr << "       Message is null, warnCancelDepthUndestructed shouldn't have been called." << endl;
00282   } else {
00283     pthread_setspecific(Threadstorage_t::selfKey,NULL);
00284   }
00285   assert(cur==msg);
00286 }
00287 
00288 
00289 namespace ThreadNS {
00290     
00291   //!This private class handles the actual lock implementation, which allows Lock to provide an abstract interface
00292   class Lock::LockStorage : public ReferenceCounter {
00293   public:
00294     LockStorage() : ReferenceCounter(), locklevel(0), mutex(), attr(), threadkey() {
00295       AddReference();
00296       pthread_mutexattr_init(&attr);
00297       pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
00298       pthread_mutex_init(&mutex,&attr);
00299     }
00300     ~LockStorage() {
00301       pthread_mutexattr_destroy(&attr);
00302       pthread_mutex_destroy(&mutex);
00303       if(locklevel>1) { //having one left is ok, perhaps even good (keeping the lock as it is destroyed)
00304         cerr << "WARNING: lockstorage destructed with " << locklevel << " locks still in effect" << endl;
00305         while(locklevel>0) {
00306           locklevel--;
00307           Thread::popNoCancel();
00308         }
00309       }
00310     }
00311     LockStorage(const LockStorage& ls) : ReferenceCounter(ls), locklevel(ls.locklevel), mutex(ls.mutex), attr(ls.attr), threadkey(ls.threadkey) {}
00312     LockStorage& operator=(const LockStorage& ls) { ReferenceCounter::operator=(ls); locklevel=ls.locklevel; mutex=ls.mutex; attr=ls.attr; threadkey=ls.threadkey; return *this; }
00313     void lock() {
00314       Thread::pushNoCancel();
00315       if(int err=pthread_mutex_lock(&mutex)) {
00316         cerr << "ERROR: ThreadNS::Lock::lock() failed: " << strerror(err) << endl;
00317         Thread::popNoCancel();
00318       } else
00319         locklevel++;
00320     }
00321     bool trylock() {
00322       Thread::pushNoCancel();
00323       if(!pthread_mutex_trylock(&mutex)) {
00324         locklevel++;
00325         return true;
00326       } else {
00327         Thread::popNoCancel();
00328         return false;
00329       }
00330     }
00331     void unlock() {
00332       if(locklevel==0)
00333         cerr << "ERROR: ThreadNS::Lock::unlock() underflow" << endl;
00334       locklevel--;
00335       if(int err=pthread_mutex_unlock(&mutex))
00336         cerr << "ERROR: ThreadNS::Lock::unlock() failed: " << strerror(err) << endl;
00337       Thread::popNoCancel();
00338     }
00339     unsigned int getLockLevel() { return locklevel; }
00340   protected:
00341          
00342     unsigned int locklevel;
00343     pthread_mutex_t mutex;
00344     pthread_mutexattr_t attr;
00345     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
00346   };
00347 
00348   Lock::LockStorage* Lock::glock=NULL;
00349 
00350   Lock::Lock() : mylock(new LockStorage), locklevel(0) {
00351     if(glock==NULL)
00352       setup();
00353   }
00354   /*Lock::Lock(const Lock& l)
00355     : mylock(l.mylock), locklevel(0)
00356   {
00357     glock->lock();
00358     mylock->AddReference();
00359     glock->unlock();
00360     lock();
00361   }
00362   Lock::Lock(const Lock& l, bool autolock)
00363     : mylock(l.mylock), locklevel(0)
00364   {
00365     glock->lock();
00366     mylock->AddReference();
00367     glock->unlock();
00368     if(autolock)
00369       lock();
00370   }
00371   Lock& Lock::operator=(const Lock& l) {
00372     glock->lock();
00373     lock();
00374     if(locklevel>2)
00375       cerr << "WARNING: ThreadNS::Lock overwritten with "<<locklevel<<" locks still in effect" << endl;
00376     if(!mylock->RemoveReference())
00377       while(locklevel>0)
00378         unlock();
00379     mylock=l.mylock;
00380     locklevel=0;
00381     glock->unlock();
00382     return *this;
00383   }*/
00384   Lock::~Lock() {
00385     glock->lock();
00386     if(locklevel>1)
00387       cerr << "WARNING: ThreadNS::Lock destructed with "<<locklevel<<" locks still in effect" << endl;
00388     if(!mylock->RemoveReference())
00389       while(locklevel>0)
00390         unlock();
00391     glock->unlock();
00392   }
00393 
00394   void Lock::lock() {
00395     mylock->lock();
00396     locklevel++;
00397   }
00398   bool Lock::trylock() {
00399     if(mylock->trylock()) {
00400       locklevel++;
00401       return true;
00402     } else {
00403       return false;
00404     }
00405   }
00406   void Lock::unlock() {
00407     locklevel--;
00408     mylock->unlock();
00409   }
00410   unsigned int Lock::getLockLevel() const {
00411     return mylock->getLockLevel();
00412   }
00413   void Lock::setup() {
00414     if(glock==NULL)
00415       glock=new LockStorage;
00416   }
00417 
00418 }
00419 
00420 #endif // PLATFORM check
00421 
00422 /*! @file
00423 * @brief Describes the Thread class and its AutoThread templated subclass
00424 * @author ejt (Creator)
00425 *
00426 * $Author: ejt $
00427 * $Name: tekkotsu-3_0 $
00428 * $Revision: 1.21 $
00429 * $State: Exp $
00430 * $Date: 2006/08/15 21:45:57 $
00431 */

Tekkotsu v3.0
Generated Wed Oct 4 00:03:46 2006 by Doxygen 1.4.7