Tekkotsu Homepage
Dev. Resources


Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_Thread_h_
00003 #define INCLUDED_Thread_h_
00006 #  warning Thread class is not Aperios compatable
00007 #else
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. */
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
00018 #else
00019 /* On other platforms, we'll assume pthread_cancel does an exception-style cancellation like linux does */
00020 #  define USE_PTHREAD_CANCEL
00022 #endif
00025 #include "Shared/Resource.h"
00026 #include <stddef.h>
00028 struct timespec;
00030 namespace stacktrace {
00031   struct StackFrame;
00032 }
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;
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&);
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   };
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
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   };
00101   struct NoCancelScope {
00102     NoCancelScope() { Thread::pushNoCancel(); }
00103     ~NoCancelScope() { Thread::popNoCancel(); }
00104   };
00106   static void* CANCELLED; //!< return value from join() when the thread was cancelled instead of returning a value
00108   Thread(); //!< constructor, does not start thread by itself (although subclasses may)
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; 
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();
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();
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();
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();
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();
00153   //! sends a signal to the thread
00154   virtual void sendSignal(int sig);
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;
00161   //! returns #returnValue, for use with threads which may have intermediate results, or partial results following a cancellation
00162   virtual void * getReturnValue() { return returnValue; }
00164   //! indicates whether start() has been called (but may be some delay before isRunning() is true...)
00165   virtual bool isStarted() const { return started; }
00167   //! indicates whether the thread is currently alive and running, implies isStarted()
00168   virtual bool isRunning() const { return running; }
00170   //! returns the Thread object for the current thread (or NULL for the main thread)
00171   static Thread* getCurrent() ;
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();
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);
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();
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; }
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; }
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();
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() {}
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);
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() {}
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);
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);
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;
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;
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;
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;
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 {};
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 };
00283 #endif //Aperios check
00285 #endif
00287 /*! @file
00288 * @brief Describes the Thread class and its AutoThread templated subclass
00289 * @author ejt (Creator)
00290 */

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:52 2016 by Doxygen 1.6.3