OSDN Git Service

FIRST REPOSITORY
[eos/hostdependOTHERS.git] / I386LINUX / util / I386LINUX / include / mico / os-thread.h
1 /* -*- mode: c++; c-basic-offset: 4; -*-
2  *
3  *  MICO --- an Open Source CORBA implementation
4  *  Copyright (c) 1997-2001 by The Mico Team
5  * 
6  *  os-thread wrapper
7  *  Copyright (C) 1999 Andreas Schultz                                 
8  * 
9  *  This 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., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  *  For more information, visit the MICO Home Page at
24  *  http://www.mico.org/
25  */
26
27
28 #ifndef __OS_THREAD_H__
29 #define __OS_THREAD_H__
30
31 #if defined(_WIN32) && !defined(__MINGW32__)
32 #include <mico/config-win32.h>
33 #else
34 #include <mico/config.h>
35 #endif
36         
37
38 /*!
39  * \defgroup micomt     Threading Support
40  *
41  * Definitions in this group provide thread support
42  * for MICO.
43  */
44
45 /*!
46  * \namespace MICOMT
47  * \ingroup micomt
48  *
49  * The MICOMT namespace contains classes and types that provide
50  * a complete multithreaded development environment for the MICO
51  * ORB and applications.
52  */
53
54 //
55 // Define HAVE_THREADS if any type of thread implementations are defined.
56 // supported "implementations" are:
57 //
58 // HAVE_PTHREADS        - POSIX Draft 10 PThreads [Single UNIX Spec V.2 & X/Open Interfaces]
59 //                        (i.e. HP/UX 11, Linux PThreads (Xavier LeRoy@inria.fr))
60 // HAVE_DCE_THREADS     - POSIX Draft 4 (DCE) Threads (i.e. HP/UX 10)
61 // HAVE_WIN_THREADS     - M$ Windows threads or whatever M$ calls them...
62 // HAVE_SOLARIS_THREADS - SUN Solaris Threads.
63 // HAVE_OSPACE_THREADS  - Object Space(r) Thread<ToolKit>(tm) via D10/D4/Linux
64 //                                                                              
65
66 #if defined (HAVE_PTHREADS) || defined (HAVE_DCE_THREADS) ||                         \
67     defined (HAVE_SOLARIS_THREADS) || defined (HAVE_PTH_THREADS) ||                 \
68     defined (HAVE_WIN_THREADS)
69
70     #ifndef HAVE_THREADS
71     #define HAVE_THREADS      // def'd as a convenience
72     #endif // HAVE_THREADS
73
74 #endif // HAVE_THREADS
75
76 #include <mico/mtdebug.h>
77
78 #ifdef HAVE_THREADS
79
80 //
81 // OS dependant includes
82 //
83 #if defined(HAVE_PTH_THREADS) && defined(HAVE_PTH_H)
84 #  include <pth.h>
85 #endif
86 #if defined(HAVE_PTHREADS) || defined(HAVE_DCETHREADS)
87 #  ifdef HAVE_PTHREAD_H
88 #    include <pthread.h>
89 #  endif 
90 #  ifdef HAVE_SEMAPHORE_H
91 #    include <semaphore.h>
92 #  endif 
93 #  ifdef HAVE_SCHED_H
94 #    include <sched.h>
95 #  endif 
96 #endif
97 #if defined(HAVE_SOLARIS_THREADS)
98 #  ifdef HAVE_THREAD_H
99 #    include <thread.h>
100 #  endif 
101 #  ifdef HAVE_SYNCH_H
102 #    include <synch.h>
103 #  endif 
104 #  ifdef HAVE_SEMAPHORE_H
105 #    include <semaphore.h>
106 #  endif 
107 #endif
108
109 // thread startup mode
110 #define _THR_CREATE_AND_BLOCK
111 //#define _THR_DEFERED_CREATE
112
113 namespace MICOMT {
114
115 #ifdef HAVE_PTHREADS
116 #include <mico/os-thread/pthreads.h>
117 #endif // HAVE_PTHREADS
118
119 #ifdef HAVE_DCE_THREADS
120 #include <mico/os-thread/dcethreads.h>
121 #endif // HAVE_DCE_THREADS
122
123 #ifdef HAVE_PTH_THREADS
124 #include <mico/os-thread/pththreads.h>
125 #endif // HAVE_PTH_THREADS
126
127 #ifdef HAVE_WIN_THREADS
128 #error not yet
129 #endif // HAVE_WIN_THREADS
130
131 #ifdef HAVE_SOLARIS_THREADS
132 #include <mico/os-thread/solaris-threads.h>
133 #endif // HAVE_SOLARIS_THREADS
134
135     //
136     // auto locks
137     //
138
139     /*!
140      * \ingroup micomt
141      * The AutoLock class is better way to work with Mutex class, so
142      * instead of:
143      * \code
144      * {
145      *   my_mutex.lock();
146      *   // do something
147      *   my_mutex.unock();
148      * }
149      * \endcode
150      * the user can use:
151      * \code
152      * {
153      *   AutoLock l(my_mutex);
154      *   // do something
155      * }
156      * \endcode
157      * The main advantage here is that it'll automatically unlock
158      * mutex even in case of throwing exception
159      */
160     class AutoLock
161     {
162         Mutex& _m;
163     public:
164         //! \name Constructor/Destructor
165         //@{
166         /*!
167          * \param m  The mutex to lock
168          * The constructor will lock the supplied mutex.
169          */
170         AutoLock(Mutex& m)
171             : _m(m)
172         {
173             m.lock();
174         };
175
176         /*!
177          * The destructor unlocks the mutex.
178          */
179         ~AutoLock()
180         {
181             _m.unlock();
182         };
183         //@}
184     };
185
186
187     /*!
188      * \ingroup micomt
189      * The AutoRDLock is usefull for reader-writer locks in the same
190      * way as AutoLock class is for mutexes, but this class will obtain
191      * reader lock.
192      */
193     class AutoRDLock
194     {
195         RWLock& _l;
196     public:
197         /*!
198          * \name Constructor/Destructor
199          */
200         //@{
201         /*!
202          * \param l  The lock to use
203          * The constructor will obtain reader lock
204          */
205         AutoRDLock(RWLock& l)
206             : _l(l)
207         {
208             l.rdlock();
209         };
210
211         /*!
212          * The destructor frees obtained read lock
213          */
214         ~AutoRDLock()
215         {
216             _l.unlock();
217         };
218         //@}
219     };
220
221
222     /*!
223      * \ingroup micomt
224      * The AutoWRLock is usefull for reader-writer locks in the same
225      * way as AutoLock class for mutexes, but this class will obtain
226      * writer lock
227      */
228     class AutoWRLock
229     {
230         RWLock& _l;
231     public:
232         //! \name Constructor/Destructor
233         //@{
234         /*!
235          * \param l  The lock to use
236          * The constructor will obtain writer lock
237          */
238         AutoWRLock(RWLock& l)
239             : _l(l)
240         {
241             l.wrlock();
242         };
243
244         /*!
245          * The destructor frees obtained write lock
246          */
247         ~AutoWRLock()
248         {
249             _l.unlock();
250         };
251         //@}
252     };
253
254
255     //
256     // lock able classes
257     //
258
259     /*!
260      * \ingroup micomt
261      * The Locked class can be used to make a class lockable
262      * by inheriting from both T and RWLock.
263      *
264      * \param T  The class to make lockable
265      *
266      * Example: (Queue is queue of integers)
267      * \code
268      * Locked<Queue> queue_;
269      * ...
270      * {
271      *   AutoLock l(queue_);
272      *   queue_.push(10);
273      * }
274      * \endcode
275      */
276     template <class T>
277     class Locked: public T, public Mutex
278     {
279     public:
280         Locked()
281         {}
282         Locked(MICO_Boolean locked, Attribute rec)
283             : Mutex(locked, rec)
284         {}
285     };
286
287
288     /*!
289      * \ingroup micomt
290      * The RWLocked class can be used to make a class lockable
291      * by inheriting from both T and RWLock.
292      *
293      * \param T         The class type to make lockable.
294      */
295     template <class T>
296     class RWLocked: public T, public RWLock
297     {
298     };
299
300
301     //
302     // state controlled reference counting
303     //
304
305     /*!
306      * \ingroup micomt
307      * The StateRefCnt class is used to control stated reference counting for
308      * objects used by more than one thread.
309      *
310      * Rules:
311      * \li active_ref() will only succed if the object is "Active"
312      * \li active_deref() will wake threads waiting to change the objects state
313      *   if the ref count is 0
314      * \li a StateChange will only succed after ref count is 0
315      */
316     class StateRefCnt {
317     public:
318         /*!
319          * \enum ExecState
320          * The ExecState defines the state of the reference count.
321          */
322         enum ExecState {
323             Init,                               //!< Initialized
324             Active,                             //!< Active
325             InitShutdown,                       //!< Shutdown started
326             Shutdown,                           //!< Shut down
327             Terminated                          //!< Terminated
328         };
329
330     protected:
331         ExecState  _current_state;              //!< Current state
332         ExecState  _new_state;                  //!< The new state
333         MICO_ULong _activerefs;                 //!< Active references
334         Mutex      _mutex;                      //!< Lock for the ref counter
335         CondVar    _cond;                       //!< Condition var fof the counter
336
337     public:
338         //! \name Constructor/Destructor
339         //@{
340         /*!
341          * Default constructor.
342          */
343         StateRefCnt()
344             : _current_state(Init), _new_state(Init), _activerefs(0),
345               _cond(&_mutex)
346         {};
347
348         /*!
349          * Destructor.
350          */
351         ~StateRefCnt()
352         {};
353         //@}
354
355         /*!
356          * Increment the active reference count if the state is
357          * active.
358          *
359          * \return  False if the object is not active.
360          */
361         MICO_Boolean
362         active_ref()
363         {
364             AutoLock l(_mutex);
365
366             if ((_current_state != _new_state) && (_current_state != Active)) {
367                 return FALSE;
368             }
369             _activerefs++;
370             return TRUE;
371         };
372
373         /*!
374          * Decrement the active reference counts. If the count reaches
375          * 0, the condition variable is broadcasted on.
376          */
377         void
378         active_deref()
379         {
380             AutoLock l(_mutex);
381
382             _activerefs--;
383             if ( (_activerefs == 0) && (_new_state != Active) )
384                 _cond.broadcast();
385         };
386
387         /*!
388          * This function changes the current state to the requested
389          * state.
390          *
391          * \param s  The requested state
392          * \return  True on success, false on failure
393          */
394         MICO_Boolean
395         state_change(ExecState s)
396         {
397             AutoLock l(_mutex);
398
399             if ( s <= _current_state ) {
400                 return FALSE;
401             }
402             _new_state = s;
403             //wait until the state change has become effective
404             while (_activerefs != 0) {
405                 _cond.wait();
406             }
407             if ( _new_state <= _current_state )
408                 return FALSE;
409
410             _current_state = _new_state;
411             return TRUE;
412         };
413
414         /*!
415          * Get the current state.
416          *
417          * \return  The current state
418          */
419         ExecState
420         state() const
421         { return _current_state; };
422
423         /*!
424          * This method puts the state into InitShutdown if
425          * it is Active.
426          *
427          * \return  True on success, false on failure.
428          */
429         MICO_Boolean
430         init_shutdown()
431         {
432             AutoLock l(_mutex);
433
434             if (_new_state != Active ) {
435                 return FALSE;
436             }
437             _current_state = _new_state = InitShutdown;
438             return TRUE;
439         };
440     };
441 }
442
443 #else // HAVE_THREADS
444 //
445 // The user should use following code for making code better portable
446 // between single and multi threaded environment i.e. the user can use
447 // Mutex, CondVar, Semaphore etc. classes even while building
448 // on single-threaded environment - so w/o any #ifdef HAVE_THREADS #endif
449 //
450 // Following code is w/o doxygen documentation because doxyfile defines
451 // HAVE_PTHREADS and so it's not used for generating of documentation
452 //
453 namespace MICOMT {
454
455     class Mutex
456 #ifdef DEBUG_NAMES
457         : public NamedObject
458 #endif // DEBUG_NAMES
459     {
460     public:
461         enum Attribute
462         {
463             Normal,
464             Recursive
465         };
466
467         Mutex(MICO_Boolean locked = FALSE, Attribute attr = MICOMT::Mutex::Normal)
468         {};
469         ~Mutex()
470         {};
471     
472         MICO_ULong
473         trylock()
474         { return 1; };
475
476         void
477         lock()
478         {};
479
480         void
481         unlock()
482         {};
483     };
484
485
486     class CondVar
487 #ifdef DEBUG_NAMES
488         : public NamedObject
489 #endif // DEBUG_NAMES
490     {
491     public:
492         CondVar(Mutex*)
493         {};
494         ~CondVar()
495         {};
496
497         MICO_Boolean
498         wait()
499         { return 1; };
500
501         MICO_Boolean
502         timedwait(MICO_ULong)
503         { return 1; };
504
505         void
506         broadcast()
507         {};
508
509         void
510         signal()
511         {};
512     };
513
514
515     class RWLock
516 #ifdef DEBUG_NAMES
517         : public NamedObject
518 #endif // DEBUG_NAMES
519     {
520     public:
521         RWLock()
522         {};
523         ~RWLock()
524         {};
525
526         void
527         rdlock()
528         {};
529
530         void
531         wrlock()
532         {};
533
534         void
535         unlock()
536         {};
537     };
538
539
540     class Semaphore
541 #ifdef DEBUG_NAMES
542         : public NamedObject
543 #endif // DEBUG_NAMES
544     {
545     public:
546         enum ErrorType {
547             NoError,            //!< No error on semaphore
548             NoPermission,               //!< Permission denied
549             TryAgain,           //!< Try again
550             SemInvalid,         //!< Invalide semaphore
551             Interrupted,                //!< Interrupted by signal
552             UnknownError                //!< Unknow error
553         };
554
555         Semaphore(unsigned int)
556         {};
557         ~Semaphore()
558         {};
559
560         void
561         wait()
562         {};
563
564         Semaphore::ErrorType
565         trylock()
566         { return MICOMT::Semaphore::NoError; };
567
568         void
569         post()
570         {};
571     };
572
573
574     class AutoRDLock
575     {
576     public:
577         AutoRDLock(RWLock& l)
578         {};
579         ~AutoRDLock()
580         {};
581     };
582
583
584     class AutoWRLock
585     {
586     public:
587         AutoWRLock(RWLock& l)
588         {};
589         ~AutoWRLock()
590         {};
591     };
592
593
594     template <class T>
595     class RWLocked: public T, public RWLock
596     {
597     };
598
599
600     class AutoLock
601     {
602     public:
603         AutoLock(Mutex& m)
604         {};
605         ~AutoLock()
606         {};
607     };
608
609
610     template <class T>
611     class Locked: public T, public Mutex
612     {
613     public:
614         Locked()
615         {}
616         Locked(MICO_Boolean locked, Attribute rec)
617             : Mutex(locked, rec)
618         {}
619     };
620
621 } // MICOMT
622 #endif // HAVE_THREADS
623
624 #endif // __OS_THREAD_H__
625