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