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);
00031 Threadstorage_t& operator=(const Threadstorage_t& r);
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
00042 if(running) {
00043 stop();
00044 join();
00045 }
00046
00047
00048
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
00076 return returnValue;
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
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
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
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
00167 --(cur->noCancelDepth);
00168 handle_exit(NULL);
00169 return cur->returnValue;
00170 }
00171 --(cur->noCancelDepth);
00172
00173
00174
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
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 ) {
00194 handle_exit(NULL);
00195 pthread_exit(NULL);
00196 }
00197
00198 void Thread::handle_signal(int ) {
00199 pthread_exit(NULL);
00200 }
00201
00202 void Thread::handle_exit(void * th) {
00203
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
00230
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
00250
00251 return;
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 {
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
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) {
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;
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
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
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
00423
00424
00425
00426
00427
00428
00429
00430
00431