Imported Upstream version 3.2.2
[debian/gnuradio] / omnithread / gnuradio / omnithread.h
1 // -*- Mode: C++; -*-
2 //                              Package : omnithread
3 // omnithread.h                 Created : 7/94 tjr
4 //
5 //    Copyright (C) 2006 Free Software Foundation, Inc.
6 //    Copyright (C) 1994,1995,1996, 1997 Olivetti & Oracle Research Laboratory
7 //
8 //    This file is part of the omnithread library
9 //
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.
14 //
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.
19 //
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  
23 //    02110-1301, USA
24 //
25
26 //
27 // Interface to OMNI thread abstraction.
28 //
29 // This file declares classes for threads and synchronisation objects
30 // (mutexes, condition variables and counting semaphores).
31 //
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.
35 //
36
37 #ifndef __omnithread_h_
38 #define __omnithread_h_
39
40 #ifndef NULL
41 #define NULL 0
42 #endif
43
44 class omni_mutex;
45 class omni_condition;
46 class omni_semaphore;
47 class omni_thread;
48
49 //
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.
54 //
55
56 #ifndef OMNI_THREAD_EXPOSE
57 #define OMNI_THREAD_EXPOSE private
58 #endif
59
60 //
61 // Include implementation-specific header file.
62 //
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.
66 //
67
68
69 //
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.
73 //
74
75 #if !defined(OMNITHREAD_POSIX) && !defined(OMNITHREAD_NT) && defined HAVE_CONFIG_H
76 // #include <config.h>      // No, No, No!  Never include <config.h> from a header
77 #endif
78
79 #if defined(OMNITHREAD_POSIX)
80 #include <gnuradio/ot_posix.h>
81
82 #elif defined(OMNITHREAD_NT)
83 #include <gnuradio/ot_nt.h>
84
85 #ifdef _MSC_VER
86
87 // Using MSVC++ to compile. If compiling library as a DLL,
88 // define _OMNITHREAD_DLL. If compiling as a statuc library, define
89 // _WINSTATIC
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).
93
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_
102 #endif
103  // _OMNITHREAD_DLL && _WINSTATIC
104
105 #else
106
107 // Not using MSVC++ to compile
108 #define _OMNITHREAD_NTDLL_
109
110 #endif
111  // _MSC_VER
112  
113 #elif defined(__vxWorks__)
114 #include <gnuradio/ot_VxThread.h>
115
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."
122 #endif
123 #endif
124 #ifdef UseSolarisThreads
125 #include <gnuradio/ot_solaris.h>
126 #else
127 #include <gnuradio/ot_posix.h>
128 #endif
129
130 #elif defined(__rtems__)
131 #include <gnuradio/ot_posix.h>
132 #include <sched.h>
133
134 #elif defined(__macos__)
135 #include <gnuradio/ot_posix.h>
136 #include <sched.h>
137
138 #else
139 #error "No implementation header file"
140 #endif
141
142
143 #if !defined(__WIN32__)
144 #define _OMNITHREAD_NTDLL_
145 #endif
146
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"
155 #endif
156
157
158 //
159 // This exception is thrown in the event of a fatal error.
160 //
161
162 class _OMNITHREAD_NTDLL_ omni_thread_fatal {
163 public:
164     int error;
165     omni_thread_fatal(int e = 0) : error(e) {}
166 };
167
168
169 //
170 // This exception is thrown when an operation is invoked with invalid
171 // arguments.
172 //
173
174 class _OMNITHREAD_NTDLL_ omni_thread_invalid {};
175
176
177 ///////////////////////////////////////////////////////////////////////////
178 //
179 // Mutex
180 //
181 ///////////////////////////////////////////////////////////////////////////
182
183 class _OMNITHREAD_NTDLL_ omni_mutex {
184
185 public:
186     omni_mutex(void);
187     ~omni_mutex(void);
188
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).
194
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.
199
200     friend class omni_condition;
201
202 private:
203     // dummy copy constructor and operator= to prevent copying
204     omni_mutex(const omni_mutex&);
205     omni_mutex& operator=(const omni_mutex&);
206
207 OMNI_THREAD_EXPOSE:
208     OMNI_MUTEX_IMPLEMENTATION
209 };
210
211 //
212 // As an alternative to:
213 // {
214 //   mutex.lock();
215 //   .....
216 //   mutex.unlock();
217 // }
218 //
219 // you can use a single instance of the omni_mutex_lock class:
220 //
221 // {
222 //   omni_mutex_lock l(mutex);
223 //   ....
224 // }
225 //
226 // This has the advantage that mutex.unlock() will be called automatically
227 // when an exception is thrown.
228 //
229
230 class _OMNITHREAD_NTDLL_ omni_mutex_lock {
231     omni_mutex& mutex;
232 public:
233     omni_mutex_lock(omni_mutex& m) : mutex(m) { mutex.lock(); }
234     ~omni_mutex_lock(void) { mutex.unlock(); }
235 private:
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&);
239 };
240
241
242 ///////////////////////////////////////////////////////////////////////////
243 //
244 // Condition variable
245 //
246 ///////////////////////////////////////////////////////////////////////////
247
248 class _OMNITHREAD_NTDLL_ omni_condition {
249
250     omni_mutex* mutex;
251
252 public:
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().
257
258     ~omni_condition(void);
259
260     void wait(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.
265
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
271         // expired.
272
273     void signal(void);
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
276         // details.
277
278     void broadcast(void);
279         // broadcast is like signal but wakes all threads which have called
280         // wait().
281
282 private:
283     // dummy copy constructor and operator= to prevent copying
284     omni_condition(const omni_condition&);
285     omni_condition& operator=(const omni_condition&);
286
287 OMNI_THREAD_EXPOSE:
288     OMNI_CONDITION_IMPLEMENTATION
289 };
290
291
292 ///////////////////////////////////////////////////////////////////////////
293 //
294 // Counting (or binary) semaphore
295 //
296 ///////////////////////////////////////////////////////////////////////////
297
298 class _OMNITHREAD_NTDLL_ omni_semaphore {
299
300 public:
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);
304
305     void wait(void);
306         // if semaphore value is > 0 then decrement it and carry on. If it's
307         // already 0 then block.
308
309     int trywait(void);
310         // if semaphore value is > 0 then decrement it and return 1 (true).
311         // If it's already 0 then return 0 (false).
312
313     void post(void);
314         // if any threads are blocked in wait(), wake one of them up. Otherwise
315         // increment the value of the semaphore.
316
317 private:
318     // dummy copy constructor and operator= to prevent copying
319     omni_semaphore(const omni_semaphore&);
320     omni_semaphore& operator=(const omni_semaphore&);
321
322 OMNI_THREAD_EXPOSE:
323     OMNI_SEMAPHORE_IMPLEMENTATION
324 };
325
326 //
327 // A helper class for semaphores, similar to omni_mutex_lock above.
328 //
329
330 class _OMNITHREAD_NTDLL_ omni_semaphore_lock {
331     omni_semaphore& sem;
332 public:
333     omni_semaphore_lock(omni_semaphore& s) : sem(s) { sem.wait(); }
334     ~omni_semaphore_lock(void) { sem.post(); }
335 private:
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&);
339 };
340
341
342 ///////////////////////////////////////////////////////////////////////////
343 //
344 // Thread
345 //
346 ///////////////////////////////////////////////////////////////////////////
347
348 class _OMNITHREAD_NTDLL_ omni_thread {
349
350 public:
351
352     enum priority_t {
353         PRIORITY_LOW,
354         PRIORITY_NORMAL,
355         PRIORITY_HIGH
356     };
357
358     enum state_t {
359         STATE_NEW,              // thread object exists but thread hasn't
360                                 // started yet.
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).
364     };
365
366     //
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.
370     //
371
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
381         // can be joined.
382
383     void start(void);
384         // start() causes a thread created with one of the constructors to
385         // start executing the appropriate function.
386
387 protected:
388
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.
393
394 public:
395
396     void start_undetached(void);
397         // can be used with the above constructor in a derived class to cause
398         // the thread to be undetached.  In this case the thread executes the
399         // run_undetached member function.
400
401 protected:
402
403     virtual ~omni_thread(void);
404         // destructor cannot be called by user (except via a derived class).
405         // Use exit() or cancel() instead. This also means a thread object must
406         // be allocated with new - it cannot be statically or automatically
407         // allocated. The destructor of a class that inherits from omni_thread
408         // shouldn't be public either (otherwise the thread object can be
409         // destroyed while the underlying thread is still running).
410
411 public:
412
413     void join(void**);
414         // join causes the calling thread to wait for another's completion,
415         // putting the return value in the variable of type void* whose address
416         // is given (unless passed a null pointer). Only undetached threads
417         // may be joined. Storage for the thread will be reclaimed.
418
419     void set_priority(priority_t);
420         // set the priority of the thread.
421
422     static omni_thread* create(void (*fn)(void*), void* arg = NULL,
423                                priority_t pri = PRIORITY_NORMAL);
424     static omni_thread* create(void* (*fn)(void*), void* arg = NULL,
425                                priority_t pri = PRIORITY_NORMAL);
426         // create spawns a new thread executing the given function with the
427         // given argument at the given priority. Returns a pointer to the
428         // thread object. It simply constructs a new thread object then calls
429         // start.
430
431     static void exit(void* return_value = NULL);
432         // causes the calling thread to terminate.
433
434     static omni_thread* self(void);
435         // returns the calling thread's omni_thread object.  If the
436         // calling thread is not the main thread and is not created
437         // using this library, returns 0. (But see create_dummy()
438         // below.)
439
440     static void yield(void);
441         // allows another thread to run.
442
443     static void sleep(unsigned long secs, unsigned long nanosecs = 0);
444         // sleeps for the given time.
445
446     static void get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
447                          unsigned long rel_sec = 0, unsigned long rel_nsec=0);
448         // calculates an absolute time in seconds and nanoseconds, suitable for
449         // use in timed_waits on condition variables, which is the current time
450         // plus the given relative offset.
451
452
453     static void stacksize(unsigned long sz);
454     static unsigned long stacksize();
455         // Use this value as the stack size when spawning a new thread.
456         // The default value (0) means that the thread library default is
457         // to be used.
458
459
460     // Per-thread data
461     //
462     // These functions allow you to attach additional data to an
463     // omni_thread. First allocate a key for yourself with
464     // allocate_key(). Then you can store any object whose class is
465     // derived from value_t. Any values still stored in the
466     // omni_thread when the thread exits are deleted.
467     //
468     // These functions are NOT thread safe, so you should be very
469     // careful about setting/getting data in a different thread to the
470     // current thread.
471
472     typedef unsigned int key_t;
473     static key_t allocate_key();
474
475     class value_t {
476     public:
477       virtual ~value_t() {}
478     };
479
480     value_t* set_value(key_t k, value_t* v);
481         // Sets a value associated with the given key. The key must
482         // have been allocated with allocate_key(). If a value has
483         // already been set with the specified key, the old value_t
484         // object is deleted and replaced. Returns the value which was
485         // set, or zero if the key is invalid.
486
487     value_t* get_value(key_t k);
488         // Returns the value associated with the key. If the key is
489         // invalid, or there is no value for the key, returns zero.
490
491     value_t* remove_value(key_t k);
492         // Removes the value associated with the key and returns it.
493         // If the key is invalid, or there is no value for the key,
494         // returns zero.
495
496
497     // Dummy omni_thread
498     //
499     // Sometimes, an application finds itself with threads created
500     // outside of omnithread which must interact with omnithread
501     // features such as the per-thread data. In this situation,
502     // omni_thread::self() would normally return 0. These functions
503     // allow the application to create a suitable dummy omni_thread
504     // object.
505
506     static omni_thread* create_dummy(void);
507         // creates a dummy omni_thread for the calling thread. Future
508         // calls to self() will return the dummy omni_thread. Throws
509         // omni_thread_invalid if this thread already has an
510         // associated omni_thread (real or dummy).
511
512     static void release_dummy();
513         // release the dummy omni_thread for this thread. This
514         // function MUST be called before the thread exits. Throws
515         // omni_thread_invalid if the calling thread does not have a
516         // dummy omni_thread.
517
518     // class ensure_self should be created on the stack. If created in
519     // a thread without an associated omni_thread, it creates a dummy
520     // thread which is released when the ensure_self object is deleted.
521
522     class ensure_self {
523     public:
524       inline ensure_self() : _dummy(0)
525       {
526         _self = omni_thread::self();
527         if (!_self) {
528           _dummy = 1;
529           _self  = omni_thread::create_dummy();
530         }
531       }
532       inline ~ensure_self()
533       {
534         if (_dummy)
535           omni_thread::release_dummy();
536       }
537       inline omni_thread* self() { return _self; }
538     private:
539       omni_thread* _self;
540       int          _dummy;
541     };
542
543
544 private:
545
546     virtual void run(void* /*arg*/) {}
547     virtual void* run_undetached(void* /*arg*/) { return NULL; }
548         // can be overridden in a derived class.  When constructed using the
549         // the constructor omni_thread(void*, priority_t), these functions are
550         // called by start() and start_undetached() respectively.
551
552     void common_constructor(void* arg, priority_t pri, int det);
553         // implements the common parts of the constructors.
554
555     omni_mutex mutex;
556         // used to protect any members which can change after construction,
557         // i.e. the following 2 members.
558
559     state_t _state;
560     priority_t _priority;
561
562     static omni_mutex* next_id_mutex;
563     static int next_id;
564     int _id;
565
566     void (*fn_void)(void*);
567     void* (*fn_ret)(void*);
568     void* thread_arg;
569     int detached;
570     int _dummy;
571     value_t**     _values;
572     unsigned long _value_alloc;
573
574     omni_thread(const omni_thread&);
575     omni_thread& operator=(const omni_thread&);
576     // Not implemented
577
578 public:
579
580     priority_t priority(void) {
581
582         // return this thread's priority.
583
584         omni_mutex_lock l(mutex);
585         return _priority;
586     }
587
588     state_t state(void) {
589
590         // return thread state (invalid, new, running or terminated).
591
592         omni_mutex_lock l(mutex);
593         return _state;
594     }
595
596     int id(void) { return _id; }
597         // return unique thread id within the current process.
598
599
600     // This class plus the instance of it declared below allows us to execute
601     // some initialisation code before main() is called.
602
603     class _OMNITHREAD_NTDLL_ init_t {
604     public:
605         init_t(void);
606         ~init_t(void);
607     };
608
609     friend class init_t;
610     friend class omni_thread_dummy;
611
612 OMNI_THREAD_EXPOSE:
613     OMNI_THREAD_IMPLEMENTATION
614 };
615
616 #ifndef __rtems__
617 static omni_thread::init_t omni_thread_init;
618 #else
619 // RTEMS calls global Ctor/Dtor in a context that is not
620 // a posix thread. Calls to functions to pthread_self() in
621 // that context returns NULL. 
622 // So, for RTEMS we will make the thread initialization at the
623 // beginning of the Init task that has a posix context.
624 #endif
625
626 #endif