Main Page | Modules | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members

omnithread.h

Go to the documentation of this file.
00001 // -*- Mode: C++; -*-
00002 //                              Package : omnithread
00003 // omnithread.h                 Created : 7/94 tjr
00004 //
00005 //    Copyright (C) 2006 Free Software Foundation, Inc.
00006 //    Copyright (C) 1994,1995,1996, 1997 Olivetti & Oracle Research Laboratory
00007 //
00008 //    This file is part of the omnithread library
00009 //
00010 //    The omnithread library is free software; you can redistribute it and/or
00011 //    modify it under the terms of the GNU Library General Public
00012 //    License as published by the Free Software Foundation; either
00013 //    version 2 of the License, or (at your option) any later version.
00014 //
00015 //    This library is distributed in the hope that it will be useful,
00016 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 //    Library General Public License for more details.
00019 //
00020 //    You should have received a copy of the GNU Library General Public
00021 //    License along with this library; if not, write to the Free
00022 //    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
00023 //    02111-1307, USA
00024 //
00025 
00026 //
00027 // Interface to OMNI thread abstraction.
00028 //
00029 // This file declares classes for threads and synchronisation objects
00030 // (mutexes, condition variables and counting semaphores).
00031 //
00032 // Wherever a seemingly arbitrary choice has had to be made as to the interface
00033 // provided, the intention here has been to be as POSIX-like as possible.  This
00034 // is why there is no semaphore timed wait, for example.
00035 //
00036 
00037 #ifndef __omnithread_h_
00038 #define __omnithread_h_
00039 
00040 #ifndef NULL
00041 #define NULL 0
00042 #endif
00043 
00044 class omni_mutex;
00045 class omni_condition;
00046 class omni_semaphore;
00047 class omni_thread;
00048 
00049 //
00050 // OMNI_THREAD_EXPOSE can be defined as public or protected to expose the
00051 // implementation class - this may be useful for debugging.  Hopefully this
00052 // won't change the underlying structure which the compiler generates so that
00053 // this can work without recompiling the library.
00054 //
00055 
00056 #ifndef OMNI_THREAD_EXPOSE
00057 #define OMNI_THREAD_EXPOSE private
00058 #endif
00059 
00060 //
00061 // Include implementation-specific header file.
00062 //
00063 // This must define 4 CPP macros of the form OMNI_x_IMPLEMENTATION for mutex,
00064 // condition variable, semaphore and thread.  Each should define any
00065 // implementation-specific members of the corresponding classes.
00066 //
00067 
00068 
00069 //
00070 // For now, we assume they've always got a Posix Threads implementation.
00071 // If not, it'll take some configure hacking to sort it out, along with
00072 // the relevant libraries to link with, etc.
00073 //
00074 
00075 #if !defined(OMNITHREAD_POSIX) && !defined(OMNITHREAD_NT) && defined HAVE_CONFIG_H
00076 #include <config.h>
00077 #endif
00078 
00079 #if defined(OMNITHREAD_POSIX)
00080 #include <ot_posix.h>
00081 
00082 #elif defined(OMNITHREAD_NT)
00083 #include <ot_nt.h>
00084 
00085 #ifdef _MSC_VER
00086 
00087 // Using MSVC++ to compile. If compiling library as a DLL,
00088 // define _OMNITHREAD_DLL. If compiling as a statuc library, define
00089 // _WINSTATIC
00090 // If compiling an application that is to be statically linked to omnithread,
00091 // define _WINSTATIC (if the application is  to be dynamically linked, 
00092 // there is no need to define any of these macros).
00093 
00094 #if defined (_OMNITHREAD_DLL) && defined(_WINSTATIC)
00095 #error "Both _OMNITHREAD_DLL and _WINSTATIC are defined."
00096 #elif defined(_OMNITHREAD_DLL)
00097 #define _OMNITHREAD_NTDLL_ __declspec(dllexport)
00098 #elif !defined(_WINSTATIC)
00099 #define _OMNITHREAD_NTDLL_ __declspec(dllimport)
00100 #elif defined(_WINSTATIC)
00101 #define _OMNITHREAD_NTDLL_
00102 #endif
00103  // _OMNITHREAD_DLL && _WINSTATIC
00104 
00105 #else
00106 
00107 // Not using MSVC++ to compile
00108 #define _OMNITHREAD_NTDLL_
00109 
00110 #endif
00111  // _MSC_VER
00112  
00113 #elif defined(__vxWorks__)
00114 #include <ot_VxThread.h>
00115 
00116 #elif defined(__sunos__)
00117 #if __OSVERSION__ != 5
00118 // XXX Workaround for SUN C++ compiler (seen on 4.2) Template.DB code
00119 //     regeneration bug. See omniORB2/CORBA_sysdep.h for details.
00120 #if !defined(__SUNPRO_CC) || __OSVERSION__ != '5'
00121 #error "Only SunOS 5.x or later is supported."
00122 #endif
00123 #endif
00124 #ifdef UseSolarisThreads
00125 #include <ot_solaris.h>
00126 #else
00127 #include <ot_posix.h>
00128 #endif
00129 
00130 #elif defined(__rtems__)
00131 #include <ot_posix.h>
00132 #include <sched.h>
00133 
00134 #elif defined(__macos__)
00135 #include <ot_posix.h>
00136 #include <sched.h>
00137 
00138 #else
00139 #error "No implementation header file"
00140 #endif
00141 
00142 
00143 #if !defined(__WIN32__)
00144 #define _OMNITHREAD_NTDLL_
00145 #endif
00146 
00147 #if (!defined(OMNI_MUTEX_IMPLEMENTATION)        || \
00148      !defined(OMNI_MUTEX_LOCK_IMPLEMENTATION)   || \
00149      !defined(OMNI_MUTEX_TRYLOCK_IMPLEMENTATION)|| \
00150      !defined(OMNI_MUTEX_UNLOCK_IMPLEMENTATION) || \
00151      !defined(OMNI_CONDITION_IMPLEMENTATION)    || \
00152      !defined(OMNI_SEMAPHORE_IMPLEMENTATION)    || \
00153      !defined(OMNI_THREAD_IMPLEMENTATION))
00154 #error "Implementation header file incomplete"
00155 #endif
00156 
00157 
00158 //
00159 // This exception is thrown in the event of a fatal error.
00160 //
00161 
00162 class _OMNITHREAD_NTDLL_ omni_thread_fatal {
00163 public:
00164     int error;
00165     omni_thread_fatal(int e = 0) : error(e) {}
00166 };
00167 
00168 
00169 //
00170 // This exception is thrown when an operation is invoked with invalid
00171 // arguments.
00172 //
00173 
00174 class _OMNITHREAD_NTDLL_ omni_thread_invalid {};
00175 
00176 
00178 //
00179 // Mutex
00180 //
00182 
00183 class _OMNITHREAD_NTDLL_ omni_mutex {
00184 
00185 public:
00186     omni_mutex(void);
00187     ~omni_mutex(void);
00188 
00189     inline void lock(void)    { OMNI_MUTEX_LOCK_IMPLEMENTATION   }
00190     inline void unlock(void)  { OMNI_MUTEX_UNLOCK_IMPLEMENTATION }
00191     inline int trylock(void)  { return OMNI_MUTEX_TRYLOCK_IMPLEMENTATION }
00192         // if mutex is unlocked, lock it and return 1 (true).
00193         // If it's already locked then return 0 (false).
00194 
00195     inline void acquire(void) { lock(); }
00196     inline void release(void) { unlock(); }
00197         // the names lock and unlock are preferred over acquire and release
00198         // since we are attempting to be as POSIX-like as possible.
00199 
00200     friend class omni_condition;
00201 
00202 private:
00203     // dummy copy constructor and operator= to prevent copying
00204     omni_mutex(const omni_mutex&);
00205     omni_mutex& operator=(const omni_mutex&);
00206 
00207 OMNI_THREAD_EXPOSE:
00208     OMNI_MUTEX_IMPLEMENTATION
00209 };
00210 
00211 //
00212 // As an alternative to:
00213 // {
00214 //   mutex.lock();
00215 //   .....
00216 //   mutex.unlock();
00217 // }
00218 //
00219 // you can use a single instance of the omni_mutex_lock class:
00220 //
00221 // {
00222 //   omni_mutex_lock l(mutex);
00223 //   ....
00224 // }
00225 //
00226 // This has the advantage that mutex.unlock() will be called automatically
00227 // when an exception is thrown.
00228 //
00229 
00230 class _OMNITHREAD_NTDLL_ omni_mutex_lock {
00231     omni_mutex& mutex;
00232 public:
00233     omni_mutex_lock(omni_mutex& m) : mutex(m) { mutex.lock(); }
00234     ~omni_mutex_lock(void) { mutex.unlock(); }
00235 private:
00236     // dummy copy constructor and operator= to prevent copying
00237     omni_mutex_lock(const omni_mutex_lock&);
00238     omni_mutex_lock& operator=(const omni_mutex_lock&);
00239 };
00240 
00241 
00243 //
00244 // Condition variable
00245 //
00247 
00248 class _OMNITHREAD_NTDLL_ omni_condition {
00249 
00250     omni_mutex* mutex;
00251 
00252 public:
00253     omni_condition(omni_mutex* m);
00254         // constructor must be given a pointer to an existing mutex. The
00255         // condition variable is then linked to the mutex, so that there is an
00256         // implicit unlock and lock around wait() and timed_wait().
00257 
00258     ~omni_condition(void);
00259 
00260     void wait(void);
00261         // wait for the condition variable to be signalled.  The mutex is
00262         // implicitly released before waiting and locked again after waking up.
00263         // If wait() is called by multiple threads, a signal may wake up more
00264         // than one thread.  See POSIX threads documentation for details.
00265 
00266     int timedwait(unsigned long secs, unsigned long nanosecs = 0);
00267         // timedwait() is given an absolute time to wait until.  To wait for a
00268         // relative time from now, use omni_thread::get_time. See POSIX threads
00269         // documentation for why absolute times are better than relative.
00270         // Returns 1 (true) if successfully signalled, 0 (false) if time
00271         // expired.
00272 
00273     void signal(void);
00274         // if one or more threads have called wait(), signal wakes up at least
00275         // one of them, possibly more.  See POSIX threads documentation for
00276         // details.
00277 
00278     void broadcast(void);
00279         // broadcast is like signal but wakes all threads which have called
00280         // wait().
00281 
00282 private:
00283     // dummy copy constructor and operator= to prevent copying
00284     omni_condition(const omni_condition&);
00285     omni_condition& operator=(const omni_condition&);
00286 
00287 OMNI_THREAD_EXPOSE:
00288     OMNI_CONDITION_IMPLEMENTATION
00289 };
00290 
00291 
00293 //
00294 // Counting (or binary) semaphore
00295 //
00297 
00298 class _OMNITHREAD_NTDLL_ omni_semaphore {
00299 
00300 public:
00301     // if max_count == 1, you've got a binary semaphore.
00302     omni_semaphore(unsigned int initial = 1, unsigned int max_count = 0x7fffffff);
00303     ~omni_semaphore(void);
00304 
00305     void wait(void);
00306         // if semaphore value is > 0 then decrement it and carry on. If it's
00307         // already 0 then block.
00308 
00309     int trywait(void);
00310         // if semaphore value is > 0 then decrement it and return 1 (true).
00311         // If it's already 0 then return 0 (false).
00312 
00313     void post(void);
00314         // if any threads are blocked in wait(), wake one of them up. Otherwise
00315         // increment the value of the semaphore.
00316 
00317 private:
00318     // dummy copy constructor and operator= to prevent copying
00319     omni_semaphore(const omni_semaphore&);
00320     omni_semaphore& operator=(const omni_semaphore&);
00321 
00322 OMNI_THREAD_EXPOSE:
00323     OMNI_SEMAPHORE_IMPLEMENTATION
00324 };
00325 
00326 //
00327 // A helper class for semaphores, similar to omni_mutex_lock above.
00328 //
00329 
00330 class _OMNITHREAD_NTDLL_ omni_semaphore_lock {
00331     omni_semaphore& sem;
00332 public:
00333     omni_semaphore_lock(omni_semaphore& s) : sem(s) { sem.wait(); }
00334     ~omni_semaphore_lock(void) { sem.post(); }
00335 private:
00336     // dummy copy constructor and operator= to prevent copying
00337     omni_semaphore_lock(const omni_semaphore_lock&);
00338     omni_semaphore_lock& operator=(const omni_semaphore_lock&);
00339 };
00340 
00341 
00343 //
00344 // Thread
00345 //
00347 
00348 class _OMNITHREAD_NTDLL_ omni_thread {
00349 
00350 public:
00351 
00352     enum priority_t {
00353         PRIORITY_LOW,
00354         PRIORITY_NORMAL,
00355         PRIORITY_HIGH
00356     };
00357 
00358     enum state_t {
00359         STATE_NEW,              // thread object exists but thread hasn't
00360                                 // started yet.
00361         STATE_RUNNING,          // thread is running.
00362         STATE_TERMINATED        // thread has terminated but storage has not
00363                                 // been reclaimed (i.e. waiting to be joined).
00364     };
00365 
00366     //
00367     // Constructors set up the thread object but the thread won't start until
00368     // start() is called. The create method can be used to construct and start
00369     // a thread in a single call.
00370     //
00371 
00372     omni_thread(void (*fn)(void*), void* arg = NULL,
00373                 priority_t pri = PRIORITY_NORMAL);
00374     omni_thread(void* (*fn)(void*), void* arg = NULL,
00375                 priority_t pri = PRIORITY_NORMAL);
00376         // these constructors create a thread which will run the given function
00377         // when start() is called.  The thread will be detached if given a
00378         // function with void return type, undetached if given a function
00379         // returning void*. If a thread is detached, storage for the thread is
00380         // reclaimed automatically on termination. Only an undetached thread
00381         // can be joined.
00382 
00383     void start(void);
00384         // start() causes a thread created with one of the constructors to
00385         // start executing the appropriate function.
00386 
00387 protected:
00388 
00389     omni_thread(void* arg = NULL, priority_t pri = PRIORITY_NORMAL);
00390         // this constructor is used in a derived class.  The thread will
00391         // execute the run() or run_undetached() member functions depending on
00392         // whether start() or start_undetached() is called respectively.
00393 
00394     void start_undetached(void);
00395         // can be used with the above constructor in a derived class to cause
00396         // the thread to be undetached.  In this case the thread executes the
00397         // run_undetached member function.
00398 
00399     virtual ~omni_thread(void);
00400         // destructor cannot be called by user (except via a derived class).
00401         // Use exit() or cancel() instead. This also means a thread object must
00402         // be allocated with new - it cannot be statically or automatically
00403         // allocated. The destructor of a class that inherits from omni_thread
00404         // shouldn't be public either (otherwise the thread object can be
00405         // destroyed while the underlying thread is still running).
00406 
00407 public:
00408 
00409     void join(void**);
00410         // join causes the calling thread to wait for another's completion,
00411         // putting the return value in the variable of type void* whose address
00412         // is given (unless passed a null pointer). Only undetached threads
00413         // may be joined. Storage for the thread will be reclaimed.
00414 
00415     void set_priority(priority_t);
00416         // set the priority of the thread.
00417 
00418     static omni_thread* create(void (*fn)(void*), void* arg = NULL,
00419                                priority_t pri = PRIORITY_NORMAL);
00420     static omni_thread* create(void* (*fn)(void*), void* arg = NULL,
00421                                priority_t pri = PRIORITY_NORMAL);
00422         // create spawns a new thread executing the given function with the
00423         // given argument at the given priority. Returns a pointer to the
00424         // thread object. It simply constructs a new thread object then calls
00425         // start.
00426 
00427     static void exit(void* return_value = NULL);
00428         // causes the calling thread to terminate.
00429 
00430     static omni_thread* self(void);
00431         // returns the calling thread's omni_thread object.  If the
00432         // calling thread is not the main thread and is not created
00433         // using this library, returns 0. (But see create_dummy()
00434         // below.)
00435 
00436     static void yield(void);
00437         // allows another thread to run.
00438 
00439     static void sleep(unsigned long secs, unsigned long nanosecs = 0);
00440         // sleeps for the given time.
00441 
00442     static void get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
00443                          unsigned long rel_sec = 0, unsigned long rel_nsec=0);
00444         // calculates an absolute time in seconds and nanoseconds, suitable for
00445         // use in timed_waits on condition variables, which is the current time
00446         // plus the given relative offset.
00447 
00448 
00449     static void stacksize(unsigned long sz);
00450     static unsigned long stacksize();
00451         // Use this value as the stack size when spawning a new thread.
00452         // The default value (0) means that the thread library default is
00453         // to be used.
00454 
00455 
00456     // Per-thread data
00457     //
00458     // These functions allow you to attach additional data to an
00459     // omni_thread. First allocate a key for yourself with
00460     // allocate_key(). Then you can store any object whose class is
00461     // derived from value_t. Any values still stored in the
00462     // omni_thread when the thread exits are deleted.
00463     //
00464     // These functions are NOT thread safe, so you should be very
00465     // careful about setting/getting data in a different thread to the
00466     // current thread.
00467 
00468     typedef unsigned int key_t;
00469     static key_t allocate_key();
00470 
00471     class value_t {
00472     public:
00473       virtual ~value_t() {}
00474     };
00475 
00476     value_t* set_value(key_t k, value_t* v);
00477         // Sets a value associated with the given key. The key must
00478         // have been allocated with allocate_key(). If a value has
00479         // already been set with the specified key, the old value_t
00480         // object is deleted and replaced. Returns the value which was
00481         // set, or zero if the key is invalid.
00482 
00483     value_t* get_value(key_t k);
00484         // Returns the value associated with the key. If the key is
00485         // invalid, or there is no value for the key, returns zero.
00486 
00487     value_t* remove_value(key_t k);
00488         // Removes the value associated with the key and returns it.
00489         // If the key is invalid, or there is no value for the key,
00490         // returns zero.
00491 
00492 
00493     // Dummy omni_thread
00494     //
00495     // Sometimes, an application finds itself with threads created
00496     // outside of omnithread which must interact with omnithread
00497     // features such as the per-thread data. In this situation,
00498     // omni_thread::self() would normally return 0. These functions
00499     // allow the application to create a suitable dummy omni_thread
00500     // object.
00501 
00502     static omni_thread* create_dummy(void);
00503         // creates a dummy omni_thread for the calling thread. Future
00504         // calls to self() will return the dummy omni_thread. Throws
00505         // omni_thread_invalid if this thread already has an
00506         // associated omni_thread (real or dummy).
00507 
00508     static void release_dummy();
00509         // release the dummy omni_thread for this thread. This
00510         // function MUST be called before the thread exits. Throws
00511         // omni_thread_invalid if the calling thread does not have a
00512         // dummy omni_thread.
00513 
00514     // class ensure_self should be created on the stack. If created in
00515     // a thread without an associated omni_thread, it creates a dummy
00516     // thread which is released when the ensure_self object is deleted.
00517 
00518     class ensure_self {
00519     public:
00520       inline ensure_self() : _dummy(0)
00521       {
00522         _self = omni_thread::self();
00523         if (!_self) {
00524           _dummy = 1;
00525           _self  = omni_thread::create_dummy();
00526         }
00527       }
00528       inline ~ensure_self()
00529       {
00530         if (_dummy)
00531           omni_thread::release_dummy();
00532       }
00533       inline omni_thread* self() { return _self; }
00534     private:
00535       omni_thread* _self;
00536       int          _dummy;
00537     };
00538 
00539 
00540 private:
00541 
00542     virtual void run(void* /*arg*/) {}
00543     virtual void* run_undetached(void* /*arg*/) { return NULL; }
00544         // can be overridden in a derived class.  When constructed using the
00545         // the constructor omni_thread(void*, priority_t), these functions are
00546         // called by start() and start_undetached() respectively.
00547 
00548     void common_constructor(void* arg, priority_t pri, int det);
00549         // implements the common parts of the constructors.
00550 
00551     omni_mutex mutex;
00552         // used to protect any members which can change after construction,
00553         // i.e. the following 2 members.
00554 
00555     state_t _state;
00556     priority_t _priority;
00557 
00558     static omni_mutex* next_id_mutex;
00559     static int next_id;
00560     int _id;
00561 
00562     void (*fn_void)(void*);
00563     void* (*fn_ret)(void*);
00564     void* thread_arg;
00565     int detached;
00566     int _dummy;
00567     value_t**     _values;
00568     unsigned long _value_alloc;
00569 
00570     omni_thread(const omni_thread&);
00571     omni_thread& operator=(const omni_thread&);
00572     // Not implemented
00573 
00574 public:
00575 
00576     priority_t priority(void) {
00577 
00578         // return this thread's priority.
00579 
00580         omni_mutex_lock l(mutex);
00581         return _priority;
00582     }
00583 
00584     state_t state(void) {
00585 
00586         // return thread state (invalid, new, running or terminated).
00587 
00588         omni_mutex_lock l(mutex);
00589         return _state;
00590     }
00591 
00592     int id(void) { return _id; }
00593         // return unique thread id within the current process.
00594 
00595 
00596     // This class plus the instance of it declared below allows us to execute
00597     // some initialisation code before main() is called.
00598 
00599     class _OMNITHREAD_NTDLL_ init_t {
00600     public:
00601         init_t(void);
00602         ~init_t(void);
00603     };
00604 
00605     friend class init_t;
00606     friend class omni_thread_dummy;
00607 
00608 OMNI_THREAD_EXPOSE:
00609     OMNI_THREAD_IMPLEMENTATION
00610 };
00611 
00612 #ifndef __rtems__
00613 static omni_thread::init_t omni_thread_init;
00614 #else
00615 // RTEMS calls global Ctor/Dtor in a context that is not
00616 // a posix thread. Calls to functions to pthread_self() in
00617 // that context returns NULL. 
00618 // So, for RTEMS we will make the thread initialization at the
00619 // beginning of the Init task that has a posix context.
00620 #endif
00621 
00622 #endif

Generated on Sat Jul 8 17:04:52 2006 for GNU Radio 2.x by  doxygen 1.4.1