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