Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

Thread.h

Go 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 #include "Shared/Resource.h"
00010 #include <stddef.h>
00011 
00012 struct timespec;
00013 
00014 //! provides Thread related data structures
00015 namespace ThreadNS {
00016   //! an inter-thread lock -- doesn't work across processes, only threads within a process.  (see MutexLock for inter-process locks)
00017   class Lock : public Resource {
00018   public:
00019     Lock(); //!< constructor
00020     //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) )
00021     //Lock(const Lock& l, bool autolock); //!< copy constructor -- shallow copy, share a lock, is handy for locking over a scope!!!
00022     //Lock& operator=(const Lock& l); //!< assignment -- dereference (and release) any previous lock, take on the new storage (shallow copy!)
00023     ~Lock(); //!< destructor -- dereference and release (if any references remain)
00024     void lock(); //!< block until lock is obtained
00025     bool trylock(); //!< see if lock is available
00026     void unlock(); //!< release lock, if held
00027     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)
00028     unsigned int getLockLevel() const; //!< returns the lock level of the lock storage itself, the sum of all instance's lock levels
00029   protected:
00030     friend class MarkScope;
00031     friend class Condition;
00032     virtual void useResource(Resource::Data&) { lock(); }
00033     virtual void releaseResource(Resource::Data&) { unlock(); }
00034     
00035     class LockStorage; //!< this internal class will hold the system-dependent lock information
00036     static LockStorage* glock; //!< The global lock to protect Locks sharing #mylock's
00037     LockStorage* mylock; //!< This lock's implementation
00038     static void setup(); //!< creates a new #glock if it is currently NULL (should be called by the Lock() constructor)
00039     unsigned int locklevel; //!< the current lock level from this Lock, may differ from #mylock's lock level if several Locks are sharing a storage!
00040   private:
00041     Lock(const Lock& l); //!< don't call
00042     Lock& operator=(const Lock& l); //!< don't call
00043   };
00044   
00045   //! Provides an inter-thread signaling and synchronization mechanism
00046   class Condition {
00047   public:
00048     Condition(); //!< constructor
00049     ~Condition(); //!< destructor
00050     
00051     void broadcast() const; //!< wake up all threads waiting on the condition
00052     void signal() const; //!< wake up a single thread waiting on the condition (which thread is unspecified)
00053     bool timedwait(Lock& l, const timespec* abstime) const; //!< wait for at most @a abstime for the condition before giving up (return true if condition found)
00054     void wait(Lock& l) const; //!< wait for condition
00055   protected:
00056     class ConditionStorage; //!< internal class to hold system-dependent information
00057     ConditionStorage* mycond; //!< the condition's implementation storage
00058   private:
00059     Condition(const Condition& l); //!< don't call
00060     Condition& operator=(const Condition& l); //!< don't call
00061   };
00062 } 
00063 
00064 //! Provides a nice wrapping of pthreads library
00065 /*! If you need to provide cleanup functions on stop(), cancelled(), etc., you
00066  *  should override the destructor to stop and join so that you can be assured
00067  *  that your cleanup will be called if the thread is auto-destructed by going out of scope */
00068 class Thread {
00069 public:
00070   typedef ThreadNS::Lock Lock; //!< shorthand for pthread lock wrapper
00071 
00072   Thread(); //!< constructor, does not start thread by itself (although subclasses may)
00073   virtual ~Thread()=0; //!< destructor, will stop and join the thread, but you should override it to do the same if you provide any cleanup functions
00074   
00075   //! requests that the thread be started, if not already running (you need to create a separate instances if you want to run multiple copies)
00076   virtual void start();
00077   
00078   //! sends a signal to the thread which will interrupt any sleep calls (and trigger interrupted() to be called within the thread)
00079   virtual void interrupt();
00080   
00081   //! requests that the thread be stopped gracefully, if running.
00082   /*! A cancel flag is sent, and the thread will be stopped at next cancel point, defined
00083    *  by whenever testCancel(), or a set of other system functions, are called.
00084    *  See your system's pthread_testcancel() manual page for a list of cancel points.
00085    *
00086    *  This function may imply a call to interrupt() on systems which have extremely limited
00087    *  system cancel points.  Currently, this consists of only Mac OS X.  There is hope that
00088    *  additional cancellation points will be enabled on this system:
00089    *  http://lists.apple.com/archives/darwin-kernel/2004/Jan/msg00032.html
00090    *
00091    *  @see pushNoCancel(), popNoCancel() */
00092   virtual void stop();
00093   
00094   //! sends a SIGUSR1 to the thread, breaking its execution, but still allowing handle_exit (and thus cancelled()) to be called.
00095   /*! Beware if your thread uses mutual exclusion locks, this can cause the thread to terminate while still holding locks */
00096   virtual void kill();
00097   
00098   //! detaches thread and sends SIGSTOP, which immediately halts the thread without any chance for cleanup
00099   /*! Beware if your thread uses mutual exclusion locks, this @b will cause the thread to terminate while still holding locks. */
00100   virtual void murder();
00101   
00102   //! sends a signal to the thread
00103   virtual void sendSignal(int sig);
00104   
00105   //! blocks calling thread until this Thread has terminated, via one means or another; return value is final return value by the thread
00106   virtual void * join();
00107   
00108   //! indicates whether start() has been called (but may be some delay before isRunning() is true...)
00109   virtual bool isStarted() const { return started; }
00110   
00111   //! indicates whether the thread is currently alive and running, implies isStarted()
00112   virtual bool isRunning() const { return running; }
00113   
00114   //! returns the Thread object for the current thread (or NULL for the main thread)
00115   static Thread* getCurrent() ;
00116   
00117   //! should be called before any threads are created to allow some global thread-specific data to be set up
00118   static void initMainThread();
00119   //! should be called if you no longer expect to have any threads in use
00120   static void releaseMainThread();
00121 
00122   //! should be called whenever a critical section has been entered (i.e. mutex obtained) -- prevents cancel from occurring until popNoCancel() is called
00123   static void pushNoCancel();
00124   //! should be called whenever a critical section is left (i.e. mutex released) -- if it was the last one, tests cancellability as well
00125   static void popNoCancel();
00126   
00127   //! returns #group
00128   void* getGroup() const { return group; }
00129   //! 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())
00130   void setGroup(void* g) { group=g; }
00131   
00132 protected:
00133   //! called by launch() when thread is first entered, return false to cancel launch (set #returnValue as well if you care)
00134   virtual bool launched() { return true; }
00135   //! called by launch() once the thread has been set up; when this returns, the thread ends, see runloop()
00136   /*! Default implementation repeatedly calls runloop(), usleep(), and testCancel().
00137    *  If you override, you should also be sure to call testCancel occasionally in order to support stop()
00138    *  If function returns a value, that value overrides #returnValue.  If cancel occurs, #returnValue is used. */
00139   virtual void * run();
00140   //! 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
00141   virtual unsigned int runloop() { return -1U; }
00142   //! called when handle_exit() is triggered, either by the thread being cancelled, or when run() has returned voluntarily
00143   virtual void cancelled() {}
00144   
00145   //! checks to see if stop() has been called, and if so, will exit the thread (passing through handle_exit() first)
00146   virtual void testCancel();
00147   //! thread entry point -- calls launched() on the thread (as indicated by @a msg), and then run()
00148   static void * launch(void * msg);
00149   //! indicates kill() has been called (or SIGUSR1 was sent from some other source) while launch() was still running
00150   static void handle_launch_signal(int sig);
00151   //! indicates kill() has been called (or SIGUSR1 was sent from some other source)
00152   static void handle_signal(int sig);
00153   //! indicates the thread is exiting, either voluntary (run() returned), stop(), or kill() -- calls cancelled() for the thread as indicated by @a th
00154   static void handle_exit(void * th);
00155 
00156   //! called by handleInterrupt() in target thread following call to interrupt(), assuming thread has not been cancelled (which can intercept the interrupt)
00157   virtual void interrupted() {}
00158   
00159   //! called by SIGALRM signal handler installed by interrupt() just before it posts the corresponding SIGALRM
00160   /*! tests for thread cancel condition before calling on to interrupted() */
00161   static void handleInterrupt(int signal);
00162   
00163   //! emit a warning that the last thread exited while the self-pointer thread-specific key still exists (need to call releaseMainThread() or handle_exit())
00164   static void warnSelfUndestructed(void* msg);
00165 
00166   //! stores the actual pthread data fields
00167   struct Threadstorage_t * pt;
00168   //! set to true once start() has been called, set back to false by handle_exit(), or by murder() itself
00169   bool started;
00170   //! set to true once launch() has been called, set back to false by handle_exit(), or by murder() itself
00171   bool running;
00172   //! 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
00173   void * returnValue;
00174   //! depth of the pushNoCancel() stack
00175   unsigned int noCancelDepth;
00176   //! cancel status at root of no-cancel stack (may be no-cancel through and through)
00177   int cancelOrig;
00178   
00179   //! indicates a common group of threads, inherited from the thread which created this one, default NULL if created from main thread
00180   void* group;
00181 
00182 private:
00183   Thread(const Thread& r); //!< don't call, not a well defined operation
00184   Thread& operator=(const Thread& r); //!< don't call, not a well defined operation
00185 };
00186 
00187 #endif //Aperios check
00188 
00189 #endif
00190 
00191 /*! @file
00192 * @brief Describes the Thread class and its AutoThread templated subclass
00193 * @author ejt (Creator)
00194 *
00195 * $Author: ejt $
00196 * $Name: tekkotsu-4_0 $
00197 * $Revision: 1.15 $
00198 * $State: Exp $
00199 * $Date: 2007/10/12 16:55:04 $
00200 */
00201 

Tekkotsu v4.0
Generated Thu Nov 22 00:54:56 2007 by Doxygen 1.5.4