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.