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