Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
Thread.hGo to the documentation of this file.00001 //-*-c++-*- 00002 #ifndef INCLUDED_Thread_h_ 00003 #define INCLUDED_Thread_h_ 00004 00005 #ifdef PLATFORM_APERIOS 00006 # warning Thread class is not Aperios compatable 00007 #else 00008 00009 #ifdef __APPLE__ 00010 /* Mac OS X doesn't handle pthread_cancel in (most) system calls, (read, listen, etc.) so we need to send a signal to wake it up. */ 00011 # define USE_SIGNAL_TO_CANCEL_THREAD 00012 /* Further, OS X doesn't currently (10.6 and prior) correctly unwind the stack, so destructors 00013 * aren't called — ideally, catch(...) blocks should also be triggered. So we don't use pthread_cancel() 00014 * at all! Instead, stop() will interrupt() and then expect the thread to call testCancel to generate our 00015 * own exception. */ 00016 # undef USE_PTHREAD_CANCEL 00017 # undef USE_TESTCANCEL_IN_INTERRUPT 00018 #else 00019 /* On other platforms, we'll assume pthread_cancel does an exception-style cancellation like linux does */ 00020 # define USE_PTHREAD_CANCEL 00021 # define USE_TESTCANCEL_IN_INTERRUPT 00022 #endif 00023 00024 00025 #include "Shared/Resource.h" 00026 #include <stddef.h> 00027 00028 struct timespec; 00029 00030 namespace stacktrace { 00031 struct StackFrame; 00032 } 00033 00034 //! Provides a nice wrapping of pthreads library 00035 /*! If you need to provide cleanup functions on stop(), cancelled(), etc., you 00036 * should override the destructor to stop and join so that you can be assured 00037 * that your cleanup will be called if the thread is auto-destructed by going out of scope */ 00038 class Thread { 00039 public: 00040 class Condition; 00041 00042 //! an inter-thread lock -- doesn't work across processes, only threads within a process. (see MutexLock for inter-process locks) 00043 class Lock : public Resource { 00044 public: 00045 Lock(); //!< constructor 00046 //explicit Lock(const Lock& l); //!< copy constructor -- shallow copy, share a lock, is handy for locking over a scope!!! (lock is automatically obtained on copy -- to avoid autolock, pass false to the two-argument constructor: Lock(const Lock& l, bool autolock) ) 00047 //Lock(const Lock& l, bool autolock); //!< copy constructor -- shallow copy, share a lock, is handy for locking over a scope!!! 00048 //Lock& operator=(const Lock& l); //!< assignment -- dereference (and release) any previous lock, take on the new storage (shallow copy!) 00049 ~Lock(); //!< destructor -- dereference and release (if any references remain) 00050 void lock() { Thread::pushNoCancel(); useResource(emptyData); } //!< block until lock is obtained 00051 bool trylock(); //!< see if lock is available 00052 void unlock() { releaseResource(emptyData); Thread::popNoCancel(); } //!< release lock, if held 00053 unsigned int getInstanceLockLevel() const { return locklevel; } //!< returns the lock level of the local instance of Lock (as opposed to the lock storage structure, which might be shared with other Lock instances) 00054 unsigned int getLockLevel() const; //!< returns the lock level of the lock storage itself, the sum of all instance's lock levels 00055 protected: 00056 friend class MarkScope; 00057 friend class Condition; 00058 virtual void useResource(Resource::Data&); 00059 virtual void releaseResource(Resource::Data&); 00060 00061 class LockStorage; //!< this internal class will hold the system-dependent lock information 00062 static LockStorage* glock; //!< The global lock to protect Locks sharing #mylock's 00063 LockStorage* mylock; //!< This lock's implementation 00064 static void setup(); //!< creates a new #glock if it is currently NULL (should be called by the Lock() constructor) 00065 unsigned int locklevel; //!< the current lock level from this Lock, may differ from #mylock's lock level if several Locks are sharing a storage! 00066 private: 00067 Lock(const Lock& l); //!< don't call 00068 Lock& operator=(const Lock& l); //!< don't call 00069 }; 00070 00071 //! Provides an inter-thread signaling and synchronization mechanism 00072 /*! When waiting (either wait() or timedwait()), the lock argument must initially 00073 * be passed in locked state. During the wait, the lock is released, and then reaquired 00074 * before returning, regardless of return status (i.e. timeout). This seems to be enforced at a 00075 * priority that precludes thread cancellation (tested on Linux and Mac OS X), so 00076 * although a Thread::stop() call will cancel the conditional wait, it won't cancel 00077 * the subsequent lock acquisition (even with additional Thread::stop() calls!) 00078 * 00079 * On USE_SIGNAL_TO_CANCEL_THREAD platforms (i.e. Mac OS X), wait() and 00080 * timedwait() imply a call to Thread::testCurrentCancel in order to handle 00081 * cancellation, so you can assume if they return 'naturally' that the condition 00082 * was detected, not cancellation. */ 00083 class Condition { 00084 public: 00085 Condition(); //!< constructor 00086 ~Condition(); //!< destructor 00087 00088 void broadcast() const; //!< wake up all threads waiting on the condition 00089 void signal() const; //!< wake up a single thread waiting on the condition (which thread is unspecified) 00090 bool timedwait(Lock& l, const timespec* abstime, bool noWarn=false) const; //!< wait for at most @a abstime for the condition before giving up (return true if condition found), @a l must be locked, will be released and re-aquired (regardless of signal vs. timeout, see class overview docs) 00091 void wait(Lock& l, bool noWarn=false) const; //!< wait for condition, @a l must be locked, will be released and re-aquired (see class overview docs) 00092 protected: 00093 static void displayRecursiveLockWarning(const char * fn, unsigned int locklevel); 00094 class ConditionStorage; //!< internal class to hold system-dependent information 00095 ConditionStorage* mycond; //!< the condition's implementation storage 00096 private: 00097 Condition(const Condition& l); //!< don't call 00098 Condition& operator=(const Condition& l); //!< don't call 00099 }; 00100 00101 struct NoCancelScope { 00102 NoCancelScope() { Thread::pushNoCancel(); } 00103 ~NoCancelScope() { Thread::popNoCancel(); } 00104 }; 00105 00106 static void* CANCELLED; //!< return value from join() when the thread was cancelled instead of returning a value 00107 00108 Thread(); //!< constructor, does not start thread by itself (although subclasses may) 00109 00110 //! destructor, will stop and join the thread, but you should override it to do the same if you provide any cleanup functions 00111 /*! Note that this destructor will send a stop() signal... if you want your subclass 00112 * to let the thread run to its "natural" completion on destruction, you can 00113 * either pushNoCancel() within the thread, or override the destructor to join() without stop() */ 00114 virtual ~Thread()=0; 00115 00116 //! requests that the thread be started, if not already running (you need to create separate instances if you want to run multiple copies) 00117 virtual void start(); 00118 00119 //! sends a signal (SIGALRM) to the thread which will interrupt any sleep/read/etc. calls (and trigger interrupted() to be called within the thread) 00120 /*! This may be called to request a cancellation on systems which don't directly support 00121 * pthread_cancel they way we would like. See stop(). */ 00122 virtual Thread& interrupt(); 00123 00124 //! requests that the thread be stopped gracefully, if running. 00125 /*! A cancel flag is sent, and the thread will be stopped at next cancel point, defined 00126 * by whenever testCancel(), or a set of other system functions, are called. 00127 * See your system's pthread_testcancel() manual page for a list of cancel points. 00128 * 00129 * This function may imply a call to interrupt() on systems which have extremely limited 00130 * system cancel points or don't handle thread cancellation as a C++ exception (currently 00131 * this consists of Mac OS X and possibly other BSD-based systems). 00132 * 00133 * This means that you should be able to rely on using try/catch(...) to handle both 00134 * exceptions as well as thread cancellation, but interruptable system calls 00135 * should test errno for EINTR and call testCancel() when it is encountered to ensure 00136 * portability. 00137 * 00138 * Returns *this, for convenience of chaining a call to join() 00139 * 00140 * @see pushNoCancel(), popNoCancel() */ 00141 virtual Thread& stop(); 00142 00143 //! sends a SIGUSR1 to the thread, breaking its execution, but still allowing handle_exit (and thus cancelled()) to be called. 00144 /*! Beware if your thread uses mutual exclusion locks, this can cause the thread to terminate while still holding locks 00145 * Returns *this, for convenience of chaining a call to join() */ 00146 virtual Thread& kill(); 00147 00148 //! detaches thread and sends SIGSTOP, which immediately halts the thread without any chance for cleanup 00149 /*! Beware if your thread uses mutual exclusion locks, this @b will cause the thread to terminate while still holding locks. 00150 * Returns *this, for convenience of chaining a call to join() */ 00151 virtual Thread& murder(); 00152 00153 //! sends a signal to the thread 00154 virtual void sendSignal(int sig); 00155 00156 //! blocks calling thread until this Thread has terminated, either via run() returning of its own accord, or a stop() cancelling the thread 00157 /*! return value is the response from run(), or #CANCELLED if stop() was called. 00158 * See getReturnValue() as a possible way to get results from a cancelled thread. */ 00159 virtual void * join() const; 00160 00161 //! returns #returnValue, for use with threads which may have intermediate results, or partial results following a cancellation 00162 virtual void * getReturnValue() { return returnValue; } 00163 00164 //! indicates whether start() has been called (but may be some delay before isRunning() is true...) 00165 virtual bool isStarted() const { return started; } 00166 00167 //! indicates whether the thread is currently alive and running, implies isStarted() 00168 virtual bool isRunning() const { return running; } 00169 00170 //! returns the Thread object for the current thread (or NULL for the main thread) 00171 static Thread* getCurrent() ; 00172 00173 //! should be called before any threads are created to allow some global thread-specific data to be set up 00174 static void initMainThread(); 00175 //! should be called if you no longer expect to have any threads in use 00176 static void releaseMainThread(); 00177 00178 //! should be called whenever a critical section has been entered (i.e. mutex obtained) -- prevents cancel from occurring until popNoCancel() is called 00179 static void pushNoCancel(); 00180 //! should be called whenever a critical section is left (i.e. mutex released) -- if it was the last one, tests cancellability as well if @a doTestCancel (generally should, except in destructors, may already be unwinding from exception, would cause terminate) 00181 static void popNoCancel(bool doTestCancel=true); 00182 00183 //! Should be called before system calls which are not cancellation points, but support interruption by signal. 00184 /*! On OS X, @e everything is done this way, so no need to call this function. Only needed for calls on systems 00185 * where we actually use pthread_cancel (Linux), but at system calls which are not cancellation points. 00186 * At the moment, semop() is the only known case. */ 00187 static void requestInterruptOnCancel(); 00188 //! Should be called after system calls which are not cancellation points, but support interruption by signal. 00189 /*! On OS X, @e everything is done this way, so no need to call this function. Only needed for calls on systems 00190 * where we actually use pthread_cancel (Linux), but at system calls which are not cancellation points. 00191 * At the moment, semop() is the only known case. */ 00192 static void unrequestInterruptOnCancel(); 00193 00194 //! Acquiring this lock allows you to atomically test whether the thread is already running and (re)start it or stop/join it 00195 Lock& getStartLock() { return startLock; } 00196 00197 //! returns #group 00198 void* getGroup() const { return group; } 00199 //! assigns #group, which will then be inherited by any threads instantiated by this one (the constructor call queries the current thread, no the start() or launch()) 00200 void setGroup(void* g) { group=g; } 00201 00202 //! checks to see if stop() has been called for the current thread, and if so, will exit (passing through handle_exit() first) 00203 static void testCurrentCancel(); 00204 00205 protected: 00206 //! called by launch() when thread is first entered, return false to cancel launch (set #returnValue as well if you care) 00207 virtual bool launched() { return true; } 00208 //! called by launch() once the thread has been set up; when this returns, the thread ends, see runloop() 00209 /*! Default implementation repeatedly calls runloop(), usleep(), and testCancel(). 00210 * If you override, you should also be sure to call testCancel occasionally in order to support stop() 00211 * If function returns a value, that value overrides #returnValue. If cancel occurs, #returnValue is used. */ 00212 virtual void * run(); 00213 //! override this as a convenient way to define your thread -- return the number of *micro*seconds to sleep before the next call; return -1U to indicate end of processing 00214 virtual unsigned int runloop() { return -1U; } 00215 //! called when handle_exit() is triggered, either by the thread being cancelled, or when run() has returned voluntarily 00216 virtual void cancelled() {} 00217 //! called as last instruction of handle_exit(), following cancelled() and all other cleanup. A self-deleting thread should do so here. 00218 virtual void dereference() {} 00219 00220 //! checks to see if stop() has been called for the currently executing thread, and if so, will exit (passing through handle_exit() first) 00221 static void testCancel() { testCurrentCancel(); } 00222 //! thread entry point -- calls launched() on the thread (as indicated by @a msg), and then run() 00223 static void * launch(void * msg); 00224 //! indicates kill() has been called (or SIGUSR1 was sent from some other source) while launch() was still running 00225 static void handle_launch_signal(int sig); 00226 //! indicates kill() has been called (or SIGUSR1 was sent from some other source) 00227 static void handle_signal(int sig); 00228 //! indicates the thread is exiting, either voluntary (run() returned), stop(), or kill() -- calls cancelled() for the thread as indicated by @a th 00229 static void handle_exit(void * th); 00230 00231 //! called by handleInterrupt() in target thread following call to interrupt(), assuming thread has not been cancelled (which can intercept the interrupt) 00232 virtual void interrupted() {} 00233 00234 //! called by SIGALRM signal handler installed by interrupt() just before it posts the corresponding SIGALRM 00235 /*! tests for thread cancel condition before calling on to interrupted() */ 00236 static void handleInterrupt(int signal); 00237 00238 //! emit a warning that the last thread exited while the self-pointer thread-specific key still exists (need to call releaseMainThread() or handle_exit()) 00239 static void warnSelfUndestructed(void* msg); 00240 00241 //! stores the actual pthread data fields 00242 struct Threadstorage_t * pt; 00243 //! set to true once start() has been called, set back to false by handle_exit(), or by murder() itself 00244 bool started; 00245 //! set to true once launch() has been called, set back to false by handle_exit(), or by murder() itself 00246 bool running; 00247 //! set to true once handle_exit() or murder() has been called, set back to false by start() (and initially by constructor) 00248 bool exited; 00249 //! indicates the value to be returned by the thread entry point (and thus passed back to join()) -- set this in runloop() or launched(), overridden by run()'s return value 00250 void * returnValue; 00251 //! depth of the pushNoCancel() stack 00252 unsigned int noCancelDepth; 00253 #ifndef USE_SIGNAL_TO_CANCEL_THREAD 00254 //! depth of the requestInterruptOnCancel() stack 00255 unsigned int reqIntrDepth; 00256 #endif 00257 //! cancel status at root of no-cancel stack (may be no-cancel through and through) 00258 int cancelOrig; 00259 //! set to true if using signal-based thread cancellation instead of pthread_cancel 00260 bool cancelRequested; 00261 //! set to true if the cancellation has been triggered and stack unwind is in progress (don't throw anything!) 00262 bool cancelInProgress; 00263 00264 //! indicates a common group of threads, inherited from the thread which created this one, default NULL if created from main thread 00265 void* group; 00266 00267 //! stores a stack trace of the call to start(), for error reporting and debugging 00268 stacktrace::StackFrame * startTrace; 00269 //! prevents concurrent starts 00270 mutable Lock startLock; 00271 //! prevents concurrent stops 00272 mutable Lock stopLock; 00273 00274 private: 00275 //! this is thrown by testCancel() on systems where pthread_testcancel() doesn't do what we want 00276 /*! This isn't thrown on other platforms, use a catch(...) to get this for portability */ 00277 struct cancellation_exception {}; 00278 00279 Thread(const Thread& r); //!< don't call, not a well defined operation 00280 Thread& operator=(const Thread& r); //!< don't call, not a well defined operation 00281 }; 00282 00283 #endif //Aperios check 00284 00285 #endif 00286 00287 /*! @file 00288 * @brief Describes the Thread class and its AutoThread templated subclass 00289 * @author ejt (Creator) 00290 */ 00291 |
Tekkotsu v5.1CVS |
Generated Mon May 9 04:58:52 2016 by Doxygen 1.6.3 |