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., 51 Franklin Street, Boston, MA  
00023 //    02110-1301, 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>      // No, No, No!  Never include <config.h> from a header
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 public:
00395 
00396     void start_undetached(void);
00397         // can be used with the above constructor in a derived class to cause
00398         // the thread to be undetached.  In this case the thread executes the
00399         // run_undetached member function.
00400 
00401 protected:
00402 
00403     virtual ~omni_thread(void);
00404         // destructor cannot be called by user (except via a derived class).
00405         // Use exit() or cancel() instead. This also means a thread object must
00406         // be allocated with new - it cannot be statically or automatically
00407         // allocated. The destructor of a class that inherits from omni_thread
00408         // shouldn't be public either (otherwise the thread object can be
00409         // destroyed while the underlying thread is still running).
00410 
00411 public:
00412 
00413     void join(void**);
00414         // join causes the calling thread to wait for another's completion,
00415         // putting the return value in the variable of type void* whose address
00416         // is given (unless passed a null pointer). Only undetached threads
00417         // may be joined. Storage for the thread will be reclaimed.
00418 
00419     void set_priority(priority_t);
00420         // set the priority of the thread.
00421 
00422     static omni_thread* create(void (*fn)(void*), void* arg = NULL,
00423                                priority_t pri = PRIORITY_NORMAL);
00424     static omni_thread* create(void* (*fn)(void*), void* arg = NULL,
00425                                priority_t pri = PRIORITY_NORMAL);
00426         // create spawns a new thread executing the given function with the
00427         // given argument at the given priority. Returns a pointer to the
00428         // thread object. It simply constructs a new thread object then calls
00429         // start.
00430 
00431     static void exit(void* return_value = NULL);
00432         // causes the calling thread to terminate.
00433 
00434     static omni_thread* self(void);
00435         // returns the calling thread's omni_thread object.  If the
00436         // calling thread is not the main thread and is not created
00437         // using this library, returns 0. (But see create_dummy()
00438         // below.)
00439 
00440     static void yield(void);
00441         // allows another thread to run.
00442 
00443     static void sleep(unsigned long secs, unsigned long nanosecs = 0);
00444         // sleeps for the given time.
00445 
00446     static void get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
00447                          unsigned long rel_sec = 0, unsigned long rel_nsec=0);
00448         // calculates an absolute time in seconds and nanoseconds, suitable for
00449         // use in timed_waits on condition variables, which is the current time
00450         // plus the given relative offset.
00451 
00452 
00453     static void stacksize(unsigned long sz);
00454     static unsigned long stacksize();
00455         // Use this value as the stack size when spawning a new thread.
00456         // The default value (0) means that the thread library default is
00457         // to be used.
00458 
00459 
00460     // Per-thread data
00461     //
00462     // These functions allow you to attach additional data to an
00463     // omni_thread. First allocate a key for yourself with
00464     // allocate_key(). Then you can store any object whose class is
00465     // derived from value_t. Any values still stored in the
00466     // omni_thread when the thread exits are deleted.
00467     //
00468     // These functions are NOT thread safe, so you should be very
00469     // careful about setting/getting data in a different thread to the
00470     // current thread.
00471 
00472     typedef unsigned int key_t;
00473     static key_t allocate_key();
00474 
00475     class value_t {
00476     public:
00477       virtual ~value_t() {}
00478     };
00479 
00480     value_t* set_value(key_t k, value_t* v);
00481         // Sets a value associated with the given key. The key must
00482         // have been allocated with allocate_key(). If a value has
00483         // already been set with the specified key, the old value_t
00484         // object is deleted and replaced. Returns the value which was
00485         // set, or zero if the key is invalid.
00486 
00487     value_t* get_value(key_t k);
00488         // Returns the value associated with the key. If the key is
00489         // invalid, or there is no value for the key, returns zero.
00490 
00491     value_t* remove_value(key_t k);
00492         // Removes the value associated with the key and returns it.
00493         // If the key is invalid, or there is no value for the key,
00494         // returns zero.
00495 
00496 
00497     // Dummy omni_thread
00498     //
00499     // Sometimes, an application finds itself with threads created
00500     // outside of omnithread which must interact with omnithread
00501     // features such as the per-thread data. In this situation,
00502     // omni_thread::self() would normally return 0. These functions
00503     // allow the application to create a suitable dummy omni_thread
00504     // object.
00505 
00506     static omni_thread* create_dummy(void);
00507         // creates a dummy omni_thread for the calling thread. Future
00508         // calls to self() will return the dummy omni_thread. Throws
00509         // omni_thread_invalid if this thread already has an
00510         // associated omni_thread (real or dummy).
00511 
00512     static void release_dummy();
00513         // release the dummy omni_thread for this thread. This
00514         // function MUST be called before the thread exits. Throws
00515         // omni_thread_invalid if the calling thread does not have a
00516         // dummy omni_thread.
00517 
00518     // class ensure_self should be created on the stack. If created in
00519     // a thread without an associated omni_thread, it creates a dummy
00520     // thread which is released when the ensure_self object is deleted.
00521 
00522     class ensure_self {
00523     public:
00524       inline ensure_self() : _dummy(0)
00525       {
00526         _self = omni_thread::self();
00527         if (!_self) {
00528           _dummy = 1;
00529           _self  = omni_thread::create_dummy();
00530         }
00531       }
00532       inline ~ensure_self()
00533       {
00534         if (_dummy)
00535           omni_thread::release_dummy();
00536       }
00537       inline omni_thread* self() { return _self; }
00538     private:
00539       omni_thread* _self;
00540       int          _dummy;
00541     };
00542 
00543 
00544 private:
00545 
00546     virtual void run(void* /*arg*/) {}
00547     virtual void* run_undetached(void* /*arg*/) { return NULL; }
00548         // can be overridden in a derived class.  When constructed using the
00549         // the constructor omni_thread(void*, priority_t), these functions are
00550         // called by start() and start_undetached() respectively.
00551 
00552     void common_constructor(void* arg, priority_t pri, int det);
00553         // implements the common parts of the constructors.
00554 
00555     omni_mutex mutex;
00556         // used to protect any members which can change after construction,
00557         // i.e. the following 2 members.
00558 
00559     state_t _state;
00560     priority_t _priority;
00561 
00562     static omni_mutex* next_id_mutex;
00563     static int next_id;
00564     int _id;
00565 
00566     void (*fn_void)(void*);
00567     void* (*fn_ret)(void*);
00568     void* thread_arg;
00569     int detached;
00570     int _dummy;
00571     value_t**     _values;
00572     unsigned long _value_alloc;
00573 
00574     omni_thread(const omni_thread&);
00575     omni_thread& operator=(const omni_thread&);
00576     // Not implemented
00577 
00578 public:
00579 
00580     priority_t priority(void) {
00581 
00582         // return this thread's priority.
00583 
00584         omni_mutex_lock l(mutex);
00585         return _priority;
00586     }
00587 
00588     state_t state(void) {
00589 
00590         // return thread state (invalid, new, running or terminated).
00591 
00592         omni_mutex_lock l(mutex);
00593         return _state;
00594     }
00595 
00596     int id(void) { return _id; }
00597         // return unique thread id within the current process.
00598 
00599 
00600     // This class plus the instance of it declared below allows us to execute
00601     // some initialisation code before main() is called.
00602 
00603     class _OMNITHREAD_NTDLL_ init_t {
00604     public:
00605         init_t(void);
00606         ~init_t(void);
00607     };
00608 
00609     friend class init_t;
00610     friend class omni_thread_dummy;
00611 
00612 OMNI_THREAD_EXPOSE:
00613     OMNI_THREAD_IMPLEMENTATION
00614 };
00615 
00616 #ifndef __rtems__
00617 static omni_thread::init_t omni_thread_init;
00618 #else
00619 // RTEMS calls global Ctor/Dtor in a context that is not
00620 // a posix thread. Calls to functions to pthread_self() in
00621 // that context returns NULL. 
00622 // So, for RTEMS we will make the thread initialization at the
00623 // beginning of the Init task that has a posix context.
00624 #endif
00625 
00626 #endif

Generated on Thu Mar 5 09:01:14 2009 for GNU Radio 3.1.3 by  doxygen 1.5.8