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