2 // Package : omnithread
3 // omnithread.h Created : 7/94 tjr
5 // Copyright (C) 2006 Free Software Foundation, Inc.
6 // Copyright (C) 1994,1995,1996, 1997 Olivetti & Oracle Research Laboratory
8 // This file is part of the omnithread library
10 // The omnithread library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Library General Public
12 // License as published by the Free Software Foundation; either
13 // version 2 of the License, or (at your option) any later version.
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Library General Public License for more details.
20 // You should have received a copy of the GNU Library General Public
21 // License along with this library; if not, write to the Free
22 // Software Foundation, Inc., 51 Franklin Street, Boston, MA
27 // Interface to OMNI thread abstraction.
29 // This file declares classes for threads and synchronisation objects
30 // (mutexes, condition variables and counting semaphores).
32 // Wherever a seemingly arbitrary choice has had to be made as to the interface
33 // provided, the intention here has been to be as POSIX-like as possible. This
34 // is why there is no semaphore timed wait, for example.
37 #ifndef __omnithread_h_
38 #define __omnithread_h_
50 // OMNI_THREAD_EXPOSE can be defined as public or protected to expose the
51 // implementation class - this may be useful for debugging. Hopefully this
52 // won't change the underlying structure which the compiler generates so that
53 // this can work without recompiling the library.
56 #ifndef OMNI_THREAD_EXPOSE
57 #define OMNI_THREAD_EXPOSE private
61 // Include implementation-specific header file.
63 // This must define 4 CPP macros of the form OMNI_x_IMPLEMENTATION for mutex,
64 // condition variable, semaphore and thread. Each should define any
65 // implementation-specific members of the corresponding classes.
70 // For now, we assume they've always got a Posix Threads implementation.
71 // If not, it'll take some configure hacking to sort it out, along with
72 // the relevant libraries to link with, etc.
75 #if !defined(OMNITHREAD_POSIX) && !defined(OMNITHREAD_NT) && defined HAVE_CONFIG_H
79 #if defined(OMNITHREAD_POSIX)
82 #elif defined(OMNITHREAD_NT)
87 // Using MSVC++ to compile. If compiling library as a DLL,
88 // define _OMNITHREAD_DLL. If compiling as a statuc library, define
90 // If compiling an application that is to be statically linked to omnithread,
91 // define _WINSTATIC (if the application is to be dynamically linked,
92 // there is no need to define any of these macros).
94 #if defined (_OMNITHREAD_DLL) && defined(_WINSTATIC)
95 #error "Both _OMNITHREAD_DLL and _WINSTATIC are defined."
96 #elif defined(_OMNITHREAD_DLL)
97 #define _OMNITHREAD_NTDLL_ __declspec(dllexport)
98 #elif !defined(_WINSTATIC)
99 #define _OMNITHREAD_NTDLL_ __declspec(dllimport)
100 #elif defined(_WINSTATIC)
101 #define _OMNITHREAD_NTDLL_
103 // _OMNITHREAD_DLL && _WINSTATIC
107 // Not using MSVC++ to compile
108 #define _OMNITHREAD_NTDLL_
113 #elif defined(__vxWorks__)
114 #include <ot_VxThread.h>
116 #elif defined(__sunos__)
117 #if __OSVERSION__ != 5
118 // XXX Workaround for SUN C++ compiler (seen on 4.2) Template.DB code
119 // regeneration bug. See omniORB2/CORBA_sysdep.h for details.
120 #if !defined(__SUNPRO_CC) || __OSVERSION__ != '5'
121 #error "Only SunOS 5.x or later is supported."
124 #ifdef UseSolarisThreads
125 #include <ot_solaris.h>
127 #include <ot_posix.h>
130 #elif defined(__rtems__)
131 #include <ot_posix.h>
134 #elif defined(__macos__)
135 #include <ot_posix.h>
139 #error "No implementation header file"
143 #if !defined(__WIN32__)
144 #define _OMNITHREAD_NTDLL_
147 #if (!defined(OMNI_MUTEX_IMPLEMENTATION) || \
148 !defined(OMNI_MUTEX_LOCK_IMPLEMENTATION) || \
149 !defined(OMNI_MUTEX_TRYLOCK_IMPLEMENTATION)|| \
150 !defined(OMNI_MUTEX_UNLOCK_IMPLEMENTATION) || \
151 !defined(OMNI_CONDITION_IMPLEMENTATION) || \
152 !defined(OMNI_SEMAPHORE_IMPLEMENTATION) || \
153 !defined(OMNI_THREAD_IMPLEMENTATION))
154 #error "Implementation header file incomplete"
159 // This exception is thrown in the event of a fatal error.
162 class _OMNITHREAD_NTDLL_ omni_thread_fatal {
165 omni_thread_fatal(int e = 0) : error(e) {}
170 // This exception is thrown when an operation is invoked with invalid
174 class _OMNITHREAD_NTDLL_ omni_thread_invalid {};
177 ///////////////////////////////////////////////////////////////////////////
181 ///////////////////////////////////////////////////////////////////////////
183 class _OMNITHREAD_NTDLL_ omni_mutex {
189 inline void lock(void) { OMNI_MUTEX_LOCK_IMPLEMENTATION }
190 inline void unlock(void) { OMNI_MUTEX_UNLOCK_IMPLEMENTATION }
191 inline int trylock(void) { return OMNI_MUTEX_TRYLOCK_IMPLEMENTATION }
192 // if mutex is unlocked, lock it and return 1 (true).
193 // If it's already locked then return 0 (false).
195 inline void acquire(void) { lock(); }
196 inline void release(void) { unlock(); }
197 // the names lock and unlock are preferred over acquire and release
198 // since we are attempting to be as POSIX-like as possible.
200 friend class omni_condition;
203 // dummy copy constructor and operator= to prevent copying
204 omni_mutex(const omni_mutex&);
205 omni_mutex& operator=(const omni_mutex&);
208 OMNI_MUTEX_IMPLEMENTATION
212 // As an alternative to:
219 // you can use a single instance of the omni_mutex_lock class:
222 // omni_mutex_lock l(mutex);
226 // This has the advantage that mutex.unlock() will be called automatically
227 // when an exception is thrown.
230 class _OMNITHREAD_NTDLL_ omni_mutex_lock {
233 omni_mutex_lock(omni_mutex& m) : mutex(m) { mutex.lock(); }
234 ~omni_mutex_lock(void) { mutex.unlock(); }
236 // dummy copy constructor and operator= to prevent copying
237 omni_mutex_lock(const omni_mutex_lock&);
238 omni_mutex_lock& operator=(const omni_mutex_lock&);
242 ///////////////////////////////////////////////////////////////////////////
244 // Condition variable
246 ///////////////////////////////////////////////////////////////////////////
248 class _OMNITHREAD_NTDLL_ omni_condition {
253 omni_condition(omni_mutex* m);
254 // constructor must be given a pointer to an existing mutex. The
255 // condition variable is then linked to the mutex, so that there is an
256 // implicit unlock and lock around wait() and timed_wait().
258 ~omni_condition(void);
261 // wait for the condition variable to be signalled. The mutex is
262 // implicitly released before waiting and locked again after waking up.
263 // If wait() is called by multiple threads, a signal may wake up more
264 // than one thread. See POSIX threads documentation for details.
266 int timedwait(unsigned long secs, unsigned long nanosecs = 0);
267 // timedwait() is given an absolute time to wait until. To wait for a
268 // relative time from now, use omni_thread::get_time. See POSIX threads
269 // documentation for why absolute times are better than relative.
270 // Returns 1 (true) if successfully signalled, 0 (false) if time
274 // if one or more threads have called wait(), signal wakes up at least
275 // one of them, possibly more. See POSIX threads documentation for
278 void broadcast(void);
279 // broadcast is like signal but wakes all threads which have called
283 // dummy copy constructor and operator= to prevent copying
284 omni_condition(const omni_condition&);
285 omni_condition& operator=(const omni_condition&);
288 OMNI_CONDITION_IMPLEMENTATION
292 ///////////////////////////////////////////////////////////////////////////
294 // Counting (or binary) semaphore
296 ///////////////////////////////////////////////////////////////////////////
298 class _OMNITHREAD_NTDLL_ omni_semaphore {
301 // if max_count == 1, you've got a binary semaphore.
302 omni_semaphore(unsigned int initial = 1, unsigned int max_count = 0x7fffffff);
303 ~omni_semaphore(void);
306 // if semaphore value is > 0 then decrement it and carry on. If it's
307 // already 0 then block.
310 // if semaphore value is > 0 then decrement it and return 1 (true).
311 // If it's already 0 then return 0 (false).
314 // if any threads are blocked in wait(), wake one of them up. Otherwise
315 // increment the value of the semaphore.
318 // dummy copy constructor and operator= to prevent copying
319 omni_semaphore(const omni_semaphore&);
320 omni_semaphore& operator=(const omni_semaphore&);
323 OMNI_SEMAPHORE_IMPLEMENTATION
327 // A helper class for semaphores, similar to omni_mutex_lock above.
330 class _OMNITHREAD_NTDLL_ omni_semaphore_lock {
333 omni_semaphore_lock(omni_semaphore& s) : sem(s) { sem.wait(); }
334 ~omni_semaphore_lock(void) { sem.post(); }
336 // dummy copy constructor and operator= to prevent copying
337 omni_semaphore_lock(const omni_semaphore_lock&);
338 omni_semaphore_lock& operator=(const omni_semaphore_lock&);
342 ///////////////////////////////////////////////////////////////////////////
346 ///////////////////////////////////////////////////////////////////////////
348 class _OMNITHREAD_NTDLL_ omni_thread {
359 STATE_NEW, // thread object exists but thread hasn't
361 STATE_RUNNING, // thread is running.
362 STATE_TERMINATED // thread has terminated but storage has not
363 // been reclaimed (i.e. waiting to be joined).
367 // Constructors set up the thread object but the thread won't start until
368 // start() is called. The create method can be used to construct and start
369 // a thread in a single call.
372 omni_thread(void (*fn)(void*), void* arg = NULL,
373 priority_t pri = PRIORITY_NORMAL);
374 omni_thread(void* (*fn)(void*), void* arg = NULL,
375 priority_t pri = PRIORITY_NORMAL);
376 // these constructors create a thread which will run the given function
377 // when start() is called. The thread will be detached if given a
378 // function with void return type, undetached if given a function
379 // returning void*. If a thread is detached, storage for the thread is
380 // reclaimed automatically on termination. Only an undetached thread
384 // start() causes a thread created with one of the constructors to
385 // start executing the appropriate function.
389 omni_thread(void* arg = NULL, priority_t pri = PRIORITY_NORMAL);
390 // this constructor is used in a derived class. The thread will
391 // execute the run() or run_undetached() member functions depending on
392 // whether start() or start_undetached() is called respectively.
394 void start_undetached(void);
395 // can be used with the above constructor in a derived class to cause
396 // the thread to be undetached. In this case the thread executes the
397 // run_undetached member function.
399 virtual ~omni_thread(void);
400 // destructor cannot be called by user (except via a derived class).
401 // Use exit() or cancel() instead. This also means a thread object must
402 // be allocated with new - it cannot be statically or automatically
403 // allocated. The destructor of a class that inherits from omni_thread
404 // shouldn't be public either (otherwise the thread object can be
405 // destroyed while the underlying thread is still running).
410 // join causes the calling thread to wait for another's completion,
411 // putting the return value in the variable of type void* whose address
412 // is given (unless passed a null pointer). Only undetached threads
413 // may be joined. Storage for the thread will be reclaimed.
415 void set_priority(priority_t);
416 // set the priority of the thread.
418 static omni_thread* create(void (*fn)(void*), void* arg = NULL,
419 priority_t pri = PRIORITY_NORMAL);
420 static omni_thread* create(void* (*fn)(void*), void* arg = NULL,
421 priority_t pri = PRIORITY_NORMAL);
422 // create spawns a new thread executing the given function with the
423 // given argument at the given priority. Returns a pointer to the
424 // thread object. It simply constructs a new thread object then calls
427 static void exit(void* return_value = NULL);
428 // causes the calling thread to terminate.
430 static omni_thread* self(void);
431 // returns the calling thread's omni_thread object. If the
432 // calling thread is not the main thread and is not created
433 // using this library, returns 0. (But see create_dummy()
436 static void yield(void);
437 // allows another thread to run.
439 static void sleep(unsigned long secs, unsigned long nanosecs = 0);
440 // sleeps for the given time.
442 static void get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
443 unsigned long rel_sec = 0, unsigned long rel_nsec=0);
444 // calculates an absolute time in seconds and nanoseconds, suitable for
445 // use in timed_waits on condition variables, which is the current time
446 // plus the given relative offset.
449 static void stacksize(unsigned long sz);
450 static unsigned long stacksize();
451 // Use this value as the stack size when spawning a new thread.
452 // The default value (0) means that the thread library default is
458 // These functions allow you to attach additional data to an
459 // omni_thread. First allocate a key for yourself with
460 // allocate_key(). Then you can store any object whose class is
461 // derived from value_t. Any values still stored in the
462 // omni_thread when the thread exits are deleted.
464 // These functions are NOT thread safe, so you should be very
465 // careful about setting/getting data in a different thread to the
468 typedef unsigned int key_t;
469 static key_t allocate_key();
473 virtual ~value_t() {}
476 value_t* set_value(key_t k, value_t* v);
477 // Sets a value associated with the given key. The key must
478 // have been allocated with allocate_key(). If a value has
479 // already been set with the specified key, the old value_t
480 // object is deleted and replaced. Returns the value which was
481 // set, or zero if the key is invalid.
483 value_t* get_value(key_t k);
484 // Returns the value associated with the key. If the key is
485 // invalid, or there is no value for the key, returns zero.
487 value_t* remove_value(key_t k);
488 // Removes the value associated with the key and returns it.
489 // If the key is invalid, or there is no value for the key,
495 // Sometimes, an application finds itself with threads created
496 // outside of omnithread which must interact with omnithread
497 // features such as the per-thread data. In this situation,
498 // omni_thread::self() would normally return 0. These functions
499 // allow the application to create a suitable dummy omni_thread
502 static omni_thread* create_dummy(void);
503 // creates a dummy omni_thread for the calling thread. Future
504 // calls to self() will return the dummy omni_thread. Throws
505 // omni_thread_invalid if this thread already has an
506 // associated omni_thread (real or dummy).
508 static void release_dummy();
509 // release the dummy omni_thread for this thread. This
510 // function MUST be called before the thread exits. Throws
511 // omni_thread_invalid if the calling thread does not have a
512 // dummy omni_thread.
514 // class ensure_self should be created on the stack. If created in
515 // a thread without an associated omni_thread, it creates a dummy
516 // thread which is released when the ensure_self object is deleted.
520 inline ensure_self() : _dummy(0)
522 _self = omni_thread::self();
525 _self = omni_thread::create_dummy();
528 inline ~ensure_self()
531 omni_thread::release_dummy();
533 inline omni_thread* self() { return _self; }
542 virtual void run(void* /*arg*/) {}
543 virtual void* run_undetached(void* /*arg*/) { return NULL; }
544 // can be overridden in a derived class. When constructed using the
545 // the constructor omni_thread(void*, priority_t), these functions are
546 // called by start() and start_undetached() respectively.
548 void common_constructor(void* arg, priority_t pri, int det);
549 // implements the common parts of the constructors.
552 // used to protect any members which can change after construction,
553 // i.e. the following 2 members.
556 priority_t _priority;
558 static omni_mutex* next_id_mutex;
562 void (*fn_void)(void*);
563 void* (*fn_ret)(void*);
568 unsigned long _value_alloc;
570 omni_thread(const omni_thread&);
571 omni_thread& operator=(const omni_thread&);
576 priority_t priority(void) {
578 // return this thread's priority.
580 omni_mutex_lock l(mutex);
584 state_t state(void) {
586 // return thread state (invalid, new, running or terminated).
588 omni_mutex_lock l(mutex);
592 int id(void) { return _id; }
593 // return unique thread id within the current process.
596 // This class plus the instance of it declared below allows us to execute
597 // some initialisation code before main() is called.
599 class _OMNITHREAD_NTDLL_ init_t {
606 friend class omni_thread_dummy;
609 OMNI_THREAD_IMPLEMENTATION
613 static omni_thread::init_t omni_thread_init;
615 // RTEMS calls global Ctor/Dtor in a context that is not
616 // a posix thread. Calls to functions to pthread_self() in
617 // that context returns NULL.
618 // So, for RTEMS we will make the thread initialization at the
619 // beginning of the Init task that has a posix context.