1 // -*- Mode: C++; -*-
  2 //                              Package : omnithread
  3 // omnithread.h                 Created : 7/94 tjr
  4 //
  5 //    Copyright (C) 1994,1995,1996, 1997 Olivetti & Oracle Research Laboratory
  6 //
  7 //    This file is part of the omnithread library
  8 //
  9 //    The omnithread library is free software; you can redistribute it and/or
 10 //    modify it under the terms of the GNU Library General Public
 11 //    License as published by the Free Software Foundation; either
 12 //    version 2 of the License, or (at your option) any later version.
 13 //
 14 //    This library is distributed in the hope that it will be useful,
 15 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 //    Library General Public License for more details.
 18 //
 19 //    You should have received a copy of the GNU Library General Public
 20 //    License along with this library; if not, write to the Free
 21 //    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
 22 //    02111-1307, USA
 23 //
 24 
 25 //
 26 // Interface to OMNI thread abstraction.
 27 //
 28 // This file declares classes for threads and synchronisation objects
 29 // (mutexes, condition variables and counting semaphores).
 30 //
 31 // Wherever a seemingly arbitrary choice has had to be made as to the interface
 32 // provided, the intention here has been to be as POSIX-like as possible.  This
 33 // is why there is no semaphore timed wait, for example.
 34 //
 35 
 36 #ifndef __omnithread_h_
 37 #define __omnithread_h_
 38 
 39 #ifndef NULL
 40 #define NULL 0
 41 #endif
 42 
 43 class omni_mutex;
 44 class omni_condition;
 45 class omni_semaphore;
 46 class omni_thread;
 47 
 48 //
 49 // OMNI_THREAD_EXPOSE can be defined as public or protected to expose the
 50 // implementation class - this may be useful for debugging.  Hopefully this
 51 // won't change the underlying structure which the compiler generates so that
 52 // this can work without recompiling the library.
 53 //
 54 
 55 #ifndef OMNI_THREAD_EXPOSE
 56 #define OMNI_THREAD_EXPOSE private
 57 #endif
 58 
 59 //
 60 // Include implementation-specific header file.
 61 //
 62 // This must define 4 CPP macros of the form OMNI_x_IMPLEMENTATION for mutex,
 63 // condition variable, semaphore and thread.  Each should define any
 64 // implementation-specific members of the corresponding classes.
 65 //
 66 
 67 
 68 #if defined(__arm__) && defined(__atmos__)
 69 #include <omnithread/posix.h>
 70 
 71 #elif defined(__osf1__)
 72 #include <omnithread/posix.h>
 73 
 74 #elif defined(__aix__)
 75 #include <omnithread/posix.h>
 76 
 77 #elif defined(__MacOSX__) || defined(__IPhoneOS__) || defined(__APPLE__)
 78 #include <omnithread/posix.h>
 79 
 80 #elif defined(__hpux__)
 81 #include <omnithread/posix.h>
 82 
 83 #elif defined(__vxWorks__)
 84 #include <omnithread/VxThread.h>
 85 
 86 #elif defined(WINCE)
 87 
 88 #if defined(__POSIX_NT__)
 89 #include <omnithread/posix.h>
 90 #else
 91 #include <omnithread/nt.h>
 92 #endif
 93 
 94 #elif defined(__WIN32__)
 95 
 96 #if defined(__POSIX_NT__)
 97 #include <omnithread/posix.h>
 98 #else
 99 #include <omnithread/nt.h>
100 #endif
101 
102 #if defined(_MSC_VER) || defined(__BCPLUSPLUS__)
103 
104 // Using MSVC++ or Borland C++ to compile. If compiling library as a
105 // DLL, define _OMNITHREAD_DLL. If compiling as a static library,
106 // define _WINSTATIC. If compiling an application that is to be
107 // statically linked to omnithread, define _WINSTATIC (if the
108 // application is to be dynamically linked, there is no need to define
109 // any of these macros).
110 
111 #if defined (_OMNITHREAD_DLL) && defined(_WINSTATIC)
112 #error "Both _OMNITHREAD_DLL and _WINSTATIC are defined."
113 #elif defined(_OMNITHREAD_DLL)
114 #define _OMNITHREAD_NTDLL_ __declspec(dllexport)
115 #elif !defined(_WINSTATIC)
116 #define _OMNITHREAD_NTDLL_ __declspec(dllimport)
117 #elif defined(_WINSTATIC)
118 #define _OMNITHREAD_NTDLL_
119 #endif
120  // _OMNITHREAD_DLL && _WINSTATIC
121 
122 #else
123 
124 // Not using MSVC++ to compile
125 #define _OMNITHREAD_NTDLL_
126 
127 #endif
128  // _MSC_VER
129  
130 #elif defined(__sunos__)
131 #if __OSVERSION__ != 5
132 // XXX Workaround for SUN C++ compiler (seen on 4.2) Template.DB code
133 //     regeneration bug. See omniORB2/CORBA_sysdep.h for details.
134 #if !defined(__SUNPRO_CC) || __OSVERSION__ != '5'
135 #error "Only SunOS 5.x or later is supported."
136 #endif
137 #endif
138 #ifdef UseSolarisThreads
139 #include <omnithread/solaris.h>
140 #else
141 #include <omnithread/posix.h>
142 #endif
143 
144 #elif defined(__linux__)
145 #include <omnithread/posix.h>
146 
147 #elif defined(__nextstep__)
148 #include <omnithread/mach.h>
149 
150 #elif defined(__VMS)
151 #include <omnithread/posix.h>
152 
153 #elif defined(__SINIX__)
154 #include <omnithread/posix.h>
155 
156 #elif defined(__osr5__)
157 #include <omnithread/posix.h>
158 
159 #elif defined(__uw7__)
160 #include <omnithread/posix.h>
161 
162 #elif defined(__irix__)
163 #include <omnithread/posix.h>
164 
165 #elif defined(__freebsd__)
166 #include <omnithread/posix.h>
167 
168 #elif defined(__rtems__)
169 #include <omnithread/posix.h>
170 #include <sched.h>
171 
172 #elif defined(__darwin__)
173 #include <omnithread/posix.h>
174 
175 #elif defined(__macos__)
176 #include <omnithread/posix.h>
177 #include <sched.h>
178 
179 #else
180 #error "No implementation header file"
181 #endif
182 
183 #if !defined(__WIN32__)
184 #define _OMNITHREAD_NTDLL_
185 #endif
186 
187 #if (!defined(OMNI_MUTEX_IMPLEMENTATION)        || \
188      !defined(OMNI_MUTEX_LOCK_IMPLEMENTATION)   || \
189      !defined(OMNI_MUTEX_UNLOCK_IMPLEMENTATION) || \
190      !defined(OMNI_CONDITION_IMPLEMENTATION)    || \
191      !defined(OMNI_SEMAPHORE_IMPLEMENTATION)    || \
192      !defined(OMNI_THREAD_IMPLEMENTATION))
193 #error "Implementation header file incomplete"
194 #endif
195 
196 
197 //
198 // This exception is thrown in the event of a fatal error.
199 //
200 
201 class _OMNITHREAD_NTDLL_ omni_thread_fatal {
202 public:
203     int error;
204     omni_thread_fatal(int e = 0) : error(e) {}
205 };
206 
207 
208 //
209 // This exception is thrown when an operation is invoked with invalid
210 // arguments.
211 //
212 
213 class _OMNITHREAD_NTDLL_ omni_thread_invalid {};
214 
215 
216 ///////////////////////////////////////////////////////////////////////////
217 //
218 // Mutex
219 //
220 ///////////////////////////////////////////////////////////////////////////
221 
222 class _OMNITHREAD_NTDLL_ omni_mutex {
223 
224 public:
225     /**
226      * The locks may not be called recursive.
227      * @param recursive If true the same thread may call the lock recursive
228      *                  Note that the thread needs to free the lock as many times again.
229      * @since xmlBlaster 1.0.5
230      */
231     omni_mutex(bool recursive=false);
232     virtual ~omni_mutex(void);
233 
234     inline void lock(void)    { OMNI_MUTEX_LOCK_IMPLEMENTATION   }
235     inline void unlock(void)  { OMNI_MUTEX_UNLOCK_IMPLEMENTATION }
236     inline void acquire(void) { lock(); }
237     inline void release(void) { unlock(); }
238         // the names lock and unlock are preferred over acquire and release
239         // since we are attempting to be as POSIX-like as possible.
240 
241     friend class omni_condition;
242 
243 private:
244     // dummy copy constructor and operator= to prevent copying
245     omni_mutex(const omni_mutex&);
246     omni_mutex& operator=(const omni_mutex&);
247 
248 OMNI_THREAD_EXPOSE:
249     OMNI_MUTEX_IMPLEMENTATION
250 };
251 
252 //
253 // As an alternative to:
254 // {
255 //   mutex.lock();
256 //   .....
257 //   mutex.unlock();
258 // }
259 //
260 // you can use a single instance of the omni_mutex_lock class:
261 //
262 // {
263 //   omni_mutex_lock l(mutex);
264 //   ....
265 // }
266 //
267 // This has the advantage that mutex.unlock() will be called automatically
268 // when an exception is thrown.
269 //
270 
271 class _OMNITHREAD_NTDLL_ omni_mutex_lock {
272     omni_mutex& mutex;
273 public:
274     omni_mutex_lock(omni_mutex& m) : mutex(m) { mutex.lock(); }
275     ~omni_mutex_lock(void) { mutex.unlock(); }
276 private:
277     // dummy copy constructor and operator= to prevent copying
278     omni_mutex_lock(const omni_mutex_lock&);
279     omni_mutex_lock& operator=(const omni_mutex_lock&);
280 };
281 
282 
283 ///////////////////////////////////////////////////////////////////////////
284 //
285 // Condition variable
286 //
287 ///////////////////////////////////////////////////////////////////////////
288 
289 class _OMNITHREAD_NTDLL_ omni_condition {
290 
291     omni_mutex* mutex;
292 
293 public:
294     omni_condition(omni_mutex* m);
295         // constructor must be given a pointer to an existing mutex. The
296         // condition variable is then linked to the mutex, so that there is an
297         // implicit unlock and lock around wait() and timed_wait().
298 
299     virtual ~omni_condition(void);
300 
301     void wait(void);
302         // wait for the condition variable to be signalled.  The mutex is
303         // implicitly released before waiting and locked again after waking up.
304         // If wait() is called by multiple threads, a signal may wake up more
305         // than one thread.  See POSIX threads documentation for details.
306 
307     int timedwait(unsigned long secs, unsigned long nanosecs = 0);
308         // timedwait() is given an absolute time to wait until.  To wait for a
309         // relative time from now, use omni_thread::get_time. See POSIX threads
310         // documentation for why absolute times are better than relative.
311         // Returns 1 (true) if successfully signalled, 0 (false) if time
312         // expired.
313 
314     void signal(void);
315         // if one or more threads have called wait(), signal wakes up at least
316         // one of them, possibly more.  See POSIX threads documentation for
317         // details.
318 
319     void broadcast(void);
320         // broadcast is like signal but wakes all threads which have called
321         // wait().
322 
323 private:
324     // dummy copy constructor and operator= to prevent copying
325     omni_condition(const omni_condition&);
326     omni_condition& operator=(const omni_condition&);
327 
328 OMNI_THREAD_EXPOSE:
329     OMNI_CONDITION_IMPLEMENTATION
330 };
331 
332 
333 ///////////////////////////////////////////////////////////////////////////
334 //
335 // Counting semaphore
336 //
337 ///////////////////////////////////////////////////////////////////////////
338 
339 class _OMNITHREAD_NTDLL_ omni_semaphore {
340 
341 public:
342     omni_semaphore(unsigned int initial = 1);
343     ~omni_semaphore(void);
344 
345     void wait(void);
346         // if semaphore value is > 0 then decrement it and carry on. If it's
347         // already 0 then block.
348 
349     int trywait(void);
350         // if semaphore value is > 0 then decrement it and return 1 (true).
351         // If it's already 0 then return 0 (false).
352 
353     void post(void);
354         // if any threads are blocked in wait(), wake one of them up. Otherwise
355         // increment the value of the semaphore.
356 
357 private:
358     // dummy copy constructor and operator= to prevent copying
359     omni_semaphore(const omni_semaphore&);
360     omni_semaphore& operator=(const omni_semaphore&);
361 
362 OMNI_THREAD_EXPOSE:
363     OMNI_SEMAPHORE_IMPLEMENTATION
364 };
365 
366 //
367 // A helper class for semaphores, similar to omni_mutex_lock above.
368 //
369 
370 class _OMNITHREAD_NTDLL_ omni_semaphore_lock {
371     omni_semaphore& sem;
372 public:
373     omni_semaphore_lock(omni_semaphore& s) : sem(s) { sem.wait(); }
374     ~omni_semaphore_lock(void) { sem.post(); }
375 private:
376     // dummy copy constructor and operator= to prevent copying
377     omni_semaphore_lock(const omni_semaphore_lock&);
378     omni_semaphore_lock& operator=(const omni_semaphore_lock&);
379 };
380 
381 
382 ///////////////////////////////////////////////////////////////////////////
383 //
384 // Thread
385 //
386 ///////////////////////////////////////////////////////////////////////////
387 
388 class _OMNITHREAD_NTDLL_ omni_thread {
389 
390 public:
391 
392     enum priority_t {
393         PRIORITY_LOW,
394         PRIORITY_NORMAL,
395         PRIORITY_HIGH
396     };
397 
398     enum state_t {
399         STATE_NEW,              // thread object exists but thread hasn't
400                                 // started yet.
401         STATE_RUNNING,          // thread is running.
402         STATE_TERMINATED        // thread has terminated but storage has not
403                                 // been reclaimed (i.e. waiting to be joined).
404     };
405 
406     //
407     // Constructors set up the thread object but the thread won't start until
408     // start() is called. The create method can be used to construct and start
409     // a thread in a single call.
410     //
411 
412     omni_thread(void (*fn)(void*), void* arg = NULL,
413                 priority_t pri = PRIORITY_NORMAL);
414     omni_thread(void* (*fn)(void*), void* arg = NULL,
415                 priority_t pri = PRIORITY_NORMAL);
416         // these constructors create a thread which will run the given function
417         // when start() is called.  The thread will be detached if given a
418         // function with void return type, undetached if given a function
419         // returning void*. If a thread is detached, storage for the thread is
420         // reclaimed automatically on termination. Only an undetached thread
421         // can be joined.
422 
423     void start(void);
424         // start() causes a thread created with one of the constructors to
425         // start executing the appropriate function.
426 
427 protected:
428 
429     omni_thread(void* arg = NULL, priority_t pri = PRIORITY_NORMAL);
430         // this constructor is used in a derived class.  The thread will
431         // execute the run() or run_undetached() member functions depending on
432         // whether start() or start_undetached() is called respectively.
433 
434     void start_undetached(void);
435         // can be used with the above constructor in a derived class to cause
436         // the thread to be undetached.  In this case the thread executes the
437         // run_undetached member function.
438 
439     virtual ~omni_thread(void);
440         // destructor cannot be called by user (except via a derived class).
441         // Use exit() or cancel() instead. This also means a thread object must
442         // be allocated with new - it cannot be statically or automatically
443         // allocated. The destructor of a class that inherits from omni_thread
444         // shouldn't be public either (otherwise the thread object can be
445         // destroyed while the underlying thread is still running).
446 
447 public:
448 
449     void join(void**);
450         // join causes the calling thread to wait for another's completion,
451         // putting the return value in the variable of type void* whose address
452         // is given (unless passed a null pointer). Only undetached threads
453         // may be joined. Storage for the thread will be reclaimed.
454 
455     void set_priority(priority_t);
456         // set the priority of the thread.
457 
458     static omni_thread* create(void (*fn)(void*), void* arg = NULL,
459                                priority_t pri = PRIORITY_NORMAL);
460     static omni_thread* create(void* (*fn)(void*), void* arg = NULL,
461                                priority_t pri = PRIORITY_NORMAL);
462         // create spawns a new thread executing the given function with the
463         // given argument at the given priority. Returns a pointer to the
464         // thread object. It simply constructs a new thread object then calls
465         // start.
466 
467     static void exit(void* return_value = NULL);
468         // causes the calling thread to terminate.
469 
470     static omni_thread* self(void);
471         // returns the calling thread's omni_thread object.  If the
472         // calling thread is not the main thread and is not created
473         // using this library, returns 0. (But see create_dummy()
474         // below.)
475 
476     static void yield(void);
477         // allows another thread to run.
478 
479     static void sleep(unsigned long secs, unsigned long nanosecs = 0);
480         // sleeps for the given time.
481 
482     static void get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
483                          unsigned long rel_sec = 0, unsigned long rel_nsec=0);
484         // calculates an absolute time in seconds and nanoseconds, suitable for
485         // use in timed_waits on condition variables, which is the current time
486         // plus the given relative offset.
487 
488 
489     static void stacksize(unsigned long sz);
490     static unsigned long stacksize();
491         // Use this value as the stack size when spawning a new thread.
492         // The default value (0) means that the thread library default is
493         // to be used.
494 
495 
496     // Per-thread data
497     //
498     // These functions allow you to attach additional data to an
499     // omni_thread. First allocate a key for yourself with
500     // allocate_key(). Then you can store any object whose class is
501     // derived from value_t. Any values still stored in the
502     // omni_thread when the thread exits are deleted.
503     //
504     // These functions are NOT thread safe, so you should be very
505     // careful about setting/getting data in a different thread to the
506     // current thread.
507 
508     typedef unsigned int key_t;
509     static key_t allocate_key();
510 
511     class value_t {
512     public:
513       virtual ~value_t() {}
514     };
515 
516     value_t* set_value(key_t k, value_t* v);
517         // Sets a value associated with the given key. The key must
518         // have been allocated with allocate_key(). If a value has
519         // already been set with the specified key, the old value_t
520         // object is deleted and replaced. Returns the value which was
521         // set, or zero if the key is invalid.
522 
523     value_t* get_value(key_t k);
524         // Returns the value associated with the key. If the key is
525         // invalid, or there is no value for the key, returns zero.
526 
527     value_t* remove_value(key_t k);
528         // Removes the value associated with the key and returns it.
529         // If the key is invalid, or there is no value for the key,
530         // returns zero.
531 
532 
533     // Dummy omni_thread
534     //
535     // Sometimes, an application finds itself with threads created
536     // outside of omnithread which must interact with omnithread
537     // features such as the per-thread data. In this situation,
538     // omni_thread::self() would normally return 0. These functions
539     // allow the application to create a suitable dummy omni_thread
540     // object.
541 
542     static omni_thread* create_dummy(void);
543         // creates a dummy omni_thread for the calling thread. Future
544         // calls to self() will return the dummy omni_thread. Throws
545         // omni_thread_invalid if this thread already has an
546         // associated omni_thread (real or dummy).
547 
548     static void release_dummy();
549         // release the dummy omni_thread for this thread. This
550         // function MUST be called before the thread exits. Throws
551         // omni_thread_invalid if the calling thread does not have a
552         // dummy omni_thread.
553 
554     // class ensure_self should be created on the stack. If created in
555     // a thread without an associated omni_thread, it creates a dummy
556     // thread which is released when the ensure_self object is deleted.
557 
558     class ensure_self {
559     public:
560       inline ensure_self() : _dummy(0)
561       {
562         _self = omni_thread::self();
563         if (!_self) {
564           _dummy = 1;
565           _self  = omni_thread::create_dummy();
566         }
567       }
568       inline ~ensure_self()
569       {
570         if (_dummy)
571           omni_thread::release_dummy();
572       }
573       inline omni_thread* self() { return _self; }
574     private:
575       omni_thread* _self;
576       int          _dummy;
577     };
578 
579 
580 private:
581 
582     virtual void run(void* /*arg*/) {}
583     virtual void* run_undetached(void* /*arg*/) { return NULL; }
584         // can be overridden in a derived class.  When constructed using the
585         // the constructor omni_thread(void*, priority_t), these functions are
586         // called by start() and start_undetached() respectively.
587 
588     void common_constructor(void* arg, priority_t pri, int det);
589         // implements the common parts of the constructors.
590 
591     omni_mutex mutex;
592         // used to protect any members which can change after construction,
593         // i.e. the following 2 members.
594 
595     state_t _state;
596     priority_t _priority;
597 
598     static omni_mutex* next_id_mutex;
599     static int next_id;
600     int _id;
601 
602     void (*fn_void)(void*);
603     void* (*fn_ret)(void*);
604     void* thread_arg;
605     int detached;
606     int _dummy;
607     value_t**     _values;
608     unsigned long _value_alloc;
609 
610     omni_thread(const omni_thread&);
611     omni_thread& operator=(const omni_thread&);
612     // Not implemented
613 
614 public:
615 
616     priority_t priority(void) {
617 
618         // return this thread's priority.
619 
620         omni_mutex_lock l(mutex);
621         return _priority;
622     }
623 
624     state_t state(void) {
625 
626         // return thread state (invalid, new, running or terminated).
627 
628         omni_mutex_lock l(mutex);
629         return _state;
630     }
631 
632     int id(void) { return _id; }
633         // return unique thread id within the current process.
634 
635 
636     // This class plus the instance of it declared below allows us to execute
637     // some initialisation code before main() is called.
638 
639     class _OMNITHREAD_NTDLL_ init_t {
640     public:
641         init_t(void);
642         ~init_t(void);
643     };
644 
645     friend class init_t;
646     friend class omni_thread_dummy;
647 
648 OMNI_THREAD_EXPOSE:
649     OMNI_THREAD_IMPLEMENTATION
650 };
651 
652 #ifndef __rtems__
653 static omni_thread::init_t omni_thread_init;
654 #else
655 // RTEMS calls global Ctor/Dtor in a context that is not
656 // a posix thread. Calls to functions to pthread_self() in
657 // that context returns NULL. 
658 // So, for RTEMS we will make the thread initialization at the
659 // beginning of the Init task that has a posix context.
660 #endif
661 
662 #endif


syntax highlighted by Code2HTML, v. 0.9.1