new files from sakari, missed last time
[ardour.git] / libs / glibmm2 / glib / src / thread.hg
1 /* $Id: thread.hg,v 1.13 2005/01/21 12:48:05 murrayc Exp $ */
2
3 /* Copyright (C) 2002 The gtkmm Development Team
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the Free
17  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 _DEFS(glibmm,glib)
21
22 #include <glib/gthread.h>
23 #include <cstddef>
24
25 #include <sigc++/sigc++.h>
26 #include <glibmm/error.h>
27 #include <glibmm/timeval.h>
28
29 /* Shadow THREAD_PRIORITY_NORMAL macro (from winbase.h).
30  */
31 #if defined(THREAD_PRIORITY_NORMAL) && !defined(GLIBMM_MACRO_SHADOW_THREAD_PRIORITY_NORMAL)
32 enum { GLIBMM_MACRO_DEFINITION_THREAD_PRIORITY_NORMAL = THREAD_PRIORITY_NORMAL };
33 #undef THREAD_PRIORITY_NORMAL
34 enum { THREAD_PRIORITY_NORMAL = GLIBMM_MACRO_DEFINITION_THREAD_PRIORITY_NORMAL };
35 #define THREAD_PRIORITY_NORMAL THREAD_PRIORITY_NORMAL
36 #define GLIBMM_MACRO_SHADOW_THREAD_PRIORITY_NORMAL 1
37 #endif
38
39
40 /** Initializer macro for Glib::StaticMutex.
41  * @relates Glib::StaticMutex
42  * @hideinitializer
43  */
44 #define GLIBMM_STATIC_MUTEX_INIT { G_STATIC_MUTEX_INIT }
45
46 /** Initializer macro for Glib::StaticRecMutex.
47  * @relates Glib::StaticRecMutex
48  * @hideinitializer
49  */
50 #define GLIBMM_STATIC_REC_MUTEX_INIT { G_STATIC_REC_MUTEX_INIT }
51
52 /** Initializer macro for Glib::StaticRWLock.
53  * @relates Glib::StaticRWLock
54  * @hideinitializer
55  */
56 #define GLIBMM_STATIC_RW_LOCK_INIT { G_STATIC_RW_LOCK_INIT }
57
58 /** Initializer macro for Glib::StaticPrivate.
59  * @relates Glib::StaticPrivate
60  * @hideinitializer
61  */
62 #define GLIBMM_STATIC_PRIVATE_INIT { G_STATIC_PRIVATE_INIT }
63
64
65 namespace Glib
66 {
67
68 /** Specifies the priority of a thread.
69  * @note It is not guaranteed, that threads with different priorities really
70  * behave accordingly. On some systems (e.g. Linux) only <tt>root</tt> can
71  * increase priorities. On other systems (e.g. Solaris) there doesn't seem to
72  * be different scheduling for different priorities. All in all try to avoid
73  * being dependent on priorities.
74  */
75 _WRAP_ENUM(ThreadPriority, GThreadPriority, NO_GTYPE)
76
77 /*! @var ThreadPriority THREAD_PRIORITY_LOW
78  * A priority lower than normal.
79  */
80 /*! @var ThreadPriority THREAD_PRIORITY_NORMAL
81  * The default priority.
82  */
83 /*! @var ThreadPriority THREAD_PRIORITY_HIGH
84  * A priority higher than normal.
85  */
86 /*! @var ThreadPriority THREAD_PRIORITY_URGENT
87  * The highest priority.
88  */
89
90
91 /** @defgroup Threads Threads
92  * Thread abstraction; including threads, different mutexes,
93  * conditions and thread private data.
94  * @{
95  */
96
97 enum NotLock { NOT_LOCK };
98 enum TryLock { TRY_LOCK };
99
100 /** Initializes the GLib thread system.
101  * Before you use a thread related function in glibmm, you should initialize
102  * the thread system.  This is done by calling Glib::thread_init().
103  *
104  * @note You should only call thread_init() with a non-<tt>0</tt> parameter
105  * if you really know what you are doing.
106  *
107  * @note thread_init() must not be called directly or indirectly as
108  * a callback from glibmm.  Also no mutexes may be currently locked while
109  * calling thread_init().
110  *
111  * thread_init() might only be called once.  On the second call it will
112  * abort with an error.  If you want to make sure that the thread system
113  * is initialized, you can do that too:
114  * @code
115  * if(!Glib::thread_supported()) Glib::thread_init();
116  * @endcode
117  * After that line either the thread system is initialized, or the program
118  * will abort if no thread system is available in GLib, i.e. either
119  * @c G_THREADS_ENABLED is not defined or @c G_THREADS_IMPL_NONE is defined.
120  *
121  * If no thread system is available and @a vtable is <tt>0</tt> or if not all
122  * elements of @a vtable are non-<tt>0</tt>, then thread_init() will abort.
123  *
124  * @note To use thread_init() in your program, you have to link with the
125  * libraries that the command <tt>pkg-config&nbsp;--libs&nbsp;gthread-2.0</tt>
126  * outputs.  This is not the case for all the other thread related functions
127  * of glibmm.  Those can be used without having to link with the thread
128  * libraries.  (You @em have to link with <tt>gthread-2.0</tt> if you actually
129  * want to use threads in your application, though.)
130  *
131  * @param vtable A function table of type @c GThreadFunctions, that provides
132  * the entry points to the thread system to be used.
133  */
134 inline void thread_init(GThreadFunctions* vtable = 0);
135
136 /** Returns whether the thread system is initialized.
137  * @return @c true, if the thread system is initialized.
138  */
139 inline bool thread_supported();
140
141
142 class Mutex;
143 class RecMutex;
144 class RWLock;
145 struct StaticMutex;
146 struct StaticRecMutex;
147 struct StaticRWLock;
148
149
150 /** Exception class for thread-related errors.
151  */
152 _WRAP_GERROR(ThreadError, GThreadError, G_THREAD_ERROR, NO_GTYPE)
153
154
155 /** Represents a running thread.
156  * An instance of this class can only be obtained with create(), self(),
157  * or wrap(GThread*).  It's not possible to delete a Thread object.  If the
158  * thread is @em not joinable, its resources will be freed automatically
159  * when it exits.  Otherwise, if the thread @em is joinable, you must call
160  * join() to avoid a memory leak.
161  *
162  * @note g_thread_exit() is not wrapped, because that function exits a thread
163  * without any cleanup.  That's especially dangerous in C++ code, since the
164  * destructors of automatic objects won't be invoked.  Instead, you can throw
165  * a Thread::Exit exception, which will be caught by the internal thread
166  * entry function.
167  *
168  * @note You might have noticed that the thread entry slot doesn't have the
169  * usual void* return value.  If you want to return any data from your thread
170  * you can pass an additional output argument to the thread's entry slot.
171  */
172 class Thread
173 {
174 public:
175   class Exit;
176
177   /** Creates a new thread with the priority <tt>THREAD_PRIORITY_NORMAL</tt>.
178    * If @a joinable is @c true, you can wait for this thread's termination by
179    * calling join().  Otherwise the thread will just disappear, when ready.
180    *
181    * The new thread executes the function or method @a slot points to.  You can
182    * pass additional arguments using sigc::bind().  If the thread was created
183    * successfully, it is returned, otherwise a ThreadError exception is thrown.
184    *
185    * @param slot A slot to execute in the new thread.
186    * @param joinable Should this thread be joinable?
187    * @return The new Thread* on success.
188    * @throw Glib::ThreadError
189    */
190   static Thread* create(const sigc::slot<void>& slot, bool joinable);
191
192   /** Creates a new thread with the priority @a priority. The stack gets the
193    * size @a stack_size or the default value for the current platform, if
194    * @a stack_size is <tt>0</tt>.
195    *
196    * If @a joinable is @c true, you can wait for this thread's termination by
197    * calling join().  Otherwise the thread will just disappear, when ready.
198    * If @a bound is @c true, this thread will be scheduled in the system scope,
199    * otherwise the implementation is free to do scheduling in the process
200    * scope.  The first variant is more expensive resource-wise, but generally
201    * faster.  On some systems (e.g. Linux) all threads are bound.
202    *
203    * The new thread executes the function or method @a slot points to.  You can
204    * pass additional arguments using sigc::bind().  If the thread was created
205    * successfully, it is returned.
206    *
207    * @note It is not guaranteed, that threads with different priorities really
208    * behave accordingly.  On some systems (e.g. Linux) only root can increase
209    * priorities.  On other systems (e.g. Solaris) there doesn't seem to be
210    * different scheduling for different priorities.  All in all try to avoid
211    * being dependent on priorities.  Use <tt>Glib::THREAD_PRIORITY_NORMAL</tt>
212    * here as a default.
213    *
214    * @note Only use the extended
215    * create(const sigc::slot<void>&, unsigned long, bool, bool, ThreadPriority)
216    * function, when you really can't use the simple
217    * create(const sigc::slot<void>&, bool)
218    * instead.  The latter overload does not take @a stack_size, @a bound and
219    * @a priority as arguments, as they should only be used for cases, where
220    * it is inevitable.
221    *
222    * @param slot A slot to execute in the new thread.
223    * @param stack_size A stack size for the new thread, or <tt>0</tt>.
224    * @param joinable Should this thread be joinable?
225    * @param bound Should this thread be bound to a system thread?
226    * @param priority A priority for the thread.
227    * @return The new Thread* on success.
228    * @throw Glib::ThreadError
229    */
230   static Thread* create(const sigc::slot<void>& slot, unsigned long stack_size,
231                         bool joinable, bool bound, ThreadPriority priority);
232
233   /** Returns the Thread* corresponding to the calling thread.
234    * @return The current thread.
235    */
236   static Thread* self();
237
238   /** Returns whether the thread is joinable.
239    * @return Whether the thread is joinable.
240    */
241   bool joinable() const;
242
243   /** Waits until the thread finishes.
244    * Waits until the thread finishes, i.e. the slot, as given to create(),
245    * returns or g_thread_exit() is called by the thread.  (Calling
246    * g_thread_exit() in a C++ program should be avoided.)  All resources of
247    * the thread including the Glib::Thread object are released.  The thread
248    * must have been created with <tt>joinable&nbsp;=&nbsp;true</tt>.
249    */
250   void join();
251
252   /** Changes the priority of the thread to @a priority.
253    * @note It is not guaranteed, that threads with different priorities really
254    * behave accordingly.  On some systems (e.g. Linux) only @c root can
255    * increase priorities.  On other systems (e.g. Solaris) there doesn't seem
256    * to be different scheduling for different priorities.  All in all try to
257    * avoid being dependent on priorities.
258    * @param priority A new priority for the thread.
259    */
260   void set_priority(ThreadPriority priority);
261
262   /** Returns the priority of the thread.
263    * @return The thread's priority.
264    */
265   ThreadPriority get_priority() const;
266
267   /** Gives way to other threads waiting to be scheduled.
268    * This function is often used as a method to make busy wait less evil.  But
269    * in most cases, you will encounter, there are better methods to do that.
270    * So in general you shouldn't use this function.
271    */
272   static void yield();
273
274   GThread*       gobj()       { return &gobject_; }
275   const GThread* gobj() const { return &gobject_; }
276
277 private:
278   GThread gobject_;
279
280   // Glib::Thread can neither be constructed nor deleted.
281   Thread();
282   void operator delete(void*, size_t);
283
284   // noncopyable
285   Thread(const Thread&);
286   Thread& operator=(const Thread&);
287 };
288
289 /** %Exception class used to exit from a thread.
290  * @code
291  * throw Glib::Thread::Exit();
292  * @endcode
293  * Write this if you want to exit from a thread created by Thread::create().
294  * Of course you must make sure not to catch Thread::Exit by accident, i.e.
295  * when using <tt>catch(...)</tt> somewhere in your code.
296  */
297 class Thread::Exit
298 {};
299
300 /** @relates Glib::Thread */
301 Thread* wrap(GThread* gobject);
302
303
304 /** Like Glib::Mutex, but can be defined at compile time.
305  * Use @c GLIBMM_STATIC_MUTEX_INIT to initialize a StaticMutex:
306  * @code
307  * Glib::StaticMutex mutex = GLIBMM_STATIC_MUTEX_INIT;
308  * @endcode
309  * A StaticMutex can be used without calling Glib::thread_init(), it will
310  * silently do nothing then.  That will also work when using the implicit
311  * conversion to Mutex&, thus you can safely use Mutex::Lock with a
312  * StaticMutex.
313  */
314 struct StaticMutex
315 {
316   void lock();
317   bool trylock();
318   void unlock();
319
320   operator Mutex&();
321
322   GStaticMutex* gobj() { return &gobject_; }
323
324 #ifndef DOXYGEN_SHOULD_SKIP_THIS
325   // Must be public to allow initialization at compile time.
326   GStaticMutex gobject_;
327 #endif
328 };
329
330 /** Represents a mutex (mutual exclusion).
331  * It can be used to protect data against shared access.  Try to use
332  * Mutex::Lock instead of calling lock() and unlock() directly&nbsp;--
333  * it will make your life much easier.
334  *
335  * @note Before creating a Glib::Mutex, Glib::thread_init() has to be called.
336  *
337  * @note Glib::Mutex is not recursive, i.e. a thread will deadlock, if it
338  * already has locked the mutex while calling lock().  Use Glib::RecMutex
339  * instead, if you need recursive mutexes.
340  */
341 class Mutex
342 {
343 public:
344   class Lock;
345
346   Mutex();
347   ~Mutex();
348
349   /** Locks the mutex.
350    * If mutex is already locked by another thread, the current thread will
351    * block until mutex is unlocked by the other thread.
352    * @see Mutex::Lock
353    */
354   void lock();
355
356   /** Tries to lock the mutex.
357    * If the mutex is already locked by another thread, it immediately returns
358    * @c false.  Otherwise it locks the mutex and returns @c true.
359    * @return Whether the mutex could be locked.
360    * @see Mutex::Lock
361    */
362   bool trylock();
363
364   /** Unlocks the mutex.
365    * If another thread is blocked in a lock() call for this mutex, it will be
366    * woken and can lock the mutex itself.
367    * @see Mutex::Lock
368    */
369   void unlock();
370
371   GMutex* gobj() { return gobject_; }
372
373 private:
374   GMutex* gobject_;
375
376   // noncopyable
377   Mutex(const Mutex&);
378   Mutex& operator=(const Mutex&);
379 };
380
381 /** Utility class for exception-safe mutex locking.
382  * @par Usage example:
383  * @code
384  * {
385  *   Glib::Mutex::Lock lock (mutex); // calls mutex.lock()
386  *   do_something();
387  * } // the destructor calls mutex.unlock()
388  * @endcode
389  * As you can see, the compiler takes care of the unlocking.  This is not
390  * only exception safe but also much less error-prone.  You could even
391  * <tt>return</tt> while still holding the lock and it will be released
392  * properly.
393  */
394 class Mutex::Lock
395 {
396 public:
397   explicit inline Lock(Mutex& mutex);
398   inline Lock(Mutex& mutex, NotLock);
399   inline Lock(Mutex& mutex, TryLock);
400   inline ~Lock();
401
402   inline void acquire();
403   inline bool try_acquire();
404   inline void release();
405   inline bool locked() const;
406
407 private:
408   Mutex&  mutex_;
409   bool    locked_;
410
411   // noncopyable
412   Lock(const Mutex::Lock&);
413   Mutex::Lock& operator=(const Mutex::Lock&);
414 };
415
416
417 /** Like Glib::RecMutex, but can be defined at compile time.
418  * Use @c GLIBMM_STATIC_REC_MUTEX_INIT to initialize a StaticRecMutex:
419  * @code
420  * Glib::StaticRecMutex mutex = GLIBMM_STATIC_REC_MUTEX_INIT;
421  * @endcode
422  * A StaticRecMutex can be used without calling Glib::thread_init(), it will
423  * silently do nothing then.  That will also work when using the implicit
424  * conversion to RecMutex&, thus you can safely use RecMutex::Lock with a
425  * StaticRecMutex.
426  */
427 struct StaticRecMutex
428 {
429   void lock();
430   bool trylock();
431   void unlock();
432
433   void lock_full(unsigned int depth);
434   unsigned int unlock_full();
435
436   operator RecMutex&();
437
438   GStaticRecMutex* gobj() { return &gobject_; }
439
440 #ifndef DOXYGEN_SHOULD_SKIP_THIS
441   // Must be public to allow initialization at compile time.
442   GStaticRecMutex gobject_;
443 #endif
444 };
445
446 class RecMutex : public StaticRecMutex
447 {
448 public:
449   class Lock;
450
451   RecMutex();
452   ~RecMutex();
453
454 private:
455   // noncopyable
456   RecMutex(const RecMutex&);
457   RecMutex& operator=(const RecMutex&);
458 };
459
460 /** Utility class for exception-safe locking of recursive mutexes.
461  */
462 class RecMutex::Lock
463 {
464 public:
465   explicit inline Lock(RecMutex& mutex);
466   inline Lock(RecMutex& mutex, NotLock);
467   inline Lock(RecMutex& mutex, TryLock);
468   inline ~Lock();
469
470   inline void acquire();
471   inline bool try_acquire();
472   inline void release();
473   inline bool locked() const;
474
475 private:
476   RecMutex& mutex_;
477   bool      locked_;
478
479   // noncopyable
480   Lock(const RecMutex::Lock&);
481   RecMutex::Lock& operator=(const RecMutex::Lock&);
482 };
483
484
485 /** Like Glib::RWLock, but can be defined at compile time.
486  * Use @c GLIBMM_STATIC_RW_LOCK_INIT to initialize a StaticRWLock:
487  * @code
488  * Glib::StaticRWLock rw_lock = GLIBMM_STATIC_RW_LOCK_INIT;
489  * @endcode
490  * A StaticRWLock can be used without calling Glib::thread_init(), it will
491  * silently do nothing then.  That will also work when using the implicit
492  * conversion to RWLock&, thus you can safely use RWLock::ReaderLock and
493  * RWLock::WriterLock with a StaticRWLock.
494  */
495 struct StaticRWLock
496 {
497   void reader_lock();
498   bool reader_trylock();
499   void reader_unlock();
500
501   void writer_lock();
502   bool writer_trylock();
503   void writer_unlock();
504
505   operator RWLock&();
506
507   GStaticRWLock* gobj() { return &gobject_; }
508
509 #ifndef DOXYGEN_SHOULD_SKIP_THIS
510   // Must be public to allow initialization at compile time.
511   GStaticRWLock gobject_;
512 #endif
513 };
514
515 class RWLock : public StaticRWLock
516 {
517 public:
518   class ReaderLock;
519   class WriterLock;
520
521   RWLock();
522   ~RWLock();
523
524 private:
525   // noncopyable
526   RWLock(const RWLock&);
527   RWLock& operator=(const RWLock&);
528 };
529
530 /** Utility class for exception-safe locking of read/write locks.
531  */
532 class RWLock::ReaderLock
533 {
534 public:
535   explicit inline ReaderLock(RWLock& rwlock);
536   inline ReaderLock(RWLock& rwlock, NotLock);
537   inline ReaderLock(RWLock& rwlock, TryLock);
538   inline ~ReaderLock();
539
540   inline void acquire();
541   inline bool try_acquire();
542   inline void release();
543   inline bool locked() const;
544
545 private:
546   RWLock& rwlock_;
547   bool    locked_;
548
549   // noncopyable
550   ReaderLock(const RWLock::ReaderLock&);
551   RWLock::ReaderLock& operator=(const RWLock::ReaderLock&);
552 };
553
554 /** Utility class for exception-safe locking of read/write locks.
555  */
556 class RWLock::WriterLock
557 {
558 public:
559   explicit inline WriterLock(RWLock& rwlock);
560   inline WriterLock(RWLock& rwlock, NotLock);
561   inline WriterLock(RWLock& rwlock, TryLock);
562   inline ~WriterLock();
563
564   inline void acquire();
565   inline bool try_acquire();
566   inline void release();
567   inline bool locked() const;
568
569 private:
570   RWLock& rwlock_;
571   bool    locked_;
572
573   // noncopyable
574   WriterLock(const RWLock::WriterLock&);
575   RWLock::WriterLock& operator=(const RWLock::WriterLock&);
576 };
577
578 /** An opaque data structure to represent a condition. 
579  * A @a Cond is an object that threads can block on, if they find a certain 
580  * condition to be false. If other threads change the state of this condition 
581  * they can signal the @a Cond, such that the waiting thread is woken up.
582  * @par Usage example:
583  * @code
584  * Glib::Cond data_cond;
585  * Glib::Mutex data_mutex;
586  * void* current_data = NULL;
587  * 
588  * void push_data (void* data)
589  * {
590  *   data_mutex.lock();
591  *   current_data = data;
592  *   data_cond.signal();
593  *   data_mutex.unlock();
594  * }
595  * 
596  * void* pop_data ()
597  * {
598  *   void* data;
599  * 
600  *   data_mutex.lock();
601  *   while (!current_data)
602  *       data_cond.wait(data_mutex);
603  *   data = current_data;
604  *   current_data = NULL;
605  *   data_mutex.unlock();
606  *   return data;
607  * }
608  * @endcode
609 */
610 class Cond
611 {
612 public:
613   Cond();
614   ~Cond();
615
616   /** If threads are waiting for this @a Cond, exactly one of them is woken up. 
617    * It is good practice to hold the same lock as the waiting thread, while calling 
618    * this method, though not required.
619    *
620    * @note This method can also be used if @a Glib::thread_init() has not yet been 
621    * called and will do nothing then.
622    */
623   void signal();
624
625   /** If threads are waiting for this @a Cond, all of them are woken up.
626    * It is good practice to hold the same lock as the waiting thread, while calling 
627    * this method, though not required.
628    *
629    * @note This method can also be used if @a Glib::thread_init() has not yet been 
630    * called and will do nothing then.
631    */
632   void broadcast();
633
634   /** Waits until this thread is woken up on this @a Cond.
635    * The mutex is unlocked before falling asleep and locked again before resuming.
636    *
637    * This method can also be used if @a Glib::thread_init() has not yet been 
638    * called and will immediately return then. 
639    *
640    * @param mutex a @a Mutex that is currently locked.
641    * 
642    * @note It is important to use the @a wait() and @a timed_wait() methods
643    * only inside a loop, which checks for the condition to be true as it is not 
644    * guaranteed that the waiting thread will find it fulfilled, even if the signaling 
645    * thread left the condition in that state. This is because another thread can have 
646    * altered the condition, before the waiting thread got the chance to be woken up, 
647    * even if the condition itself is protected by a @a Mutex.
648    */
649   void wait(Mutex& mutex);
650
651   /** Waits until this thread is woken up on this @a Cond, but not longer than until the time, that is specified by @a abs_time.
652    * The mutex is unlocked before falling asleep and locked again before resuming.
653    *
654    * This function can also be used, if @a Glib::thread_init() has not yet been 
655    * called and will immediately return @c true then. 
656    *
657    * @param mutex a @a Mutex that is currently locked.
658    * @param abs_time a max time to wait.
659    * 
660    * @note It is important to use the @a wait() and @a timed_wait() methods
661    * only inside a loop, which checks for the condition to be true as it is not 
662    * guaranteed that the waiting thread will find it fulfilled, even if the signaling 
663    * thread left the condition in that state. This is because another thread can have 
664    * altered the condition, before the waiting thread got the chance to be woken up, 
665    * even if the condition itself is protected by a @a Mutex.
666    */
667   bool timed_wait(Mutex& mutex, const Glib::TimeVal& abs_time);
668
669   GCond* gobj() { return gobject_; }
670
671 private:
672   GCond* gobject_;
673
674   // noncopyable
675   Cond(const Cond&);
676   Cond& operator=(const Cond&);
677 };
678
679
680 template <class T>
681 struct StaticPrivate
682 {
683   typedef void (*DestroyNotifyFunc) (void*);
684
685   static void delete_ptr(void* data);
686
687   inline T* get();
688   inline void set(T* data, DestroyNotifyFunc notify_func = &StaticPrivate<T>::delete_ptr);
689
690   GStaticPrivate* gobj() { return &gobject_; }
691
692 #ifndef DOXYGEN_SHOULD_SKIP_THIS
693   // Must be public to allow initialization at compile time.
694   GStaticPrivate gobject_;
695 #endif
696 };
697
698 template <class T>
699 class Private
700 {
701 public:
702   typedef void (*DestructorFunc) (void*);
703
704   static void delete_ptr(void* data);
705
706   explicit inline Private(DestructorFunc destructor_func = &Private<T>::delete_ptr);
707   inline T* get();
708   inline void set(T* data);
709
710   GPrivate* gobj() { return gobject_; }
711
712 private:
713   GPrivate* gobject_;
714
715   // noncopyable
716   Private(const Private<T>&);
717   Private<T>& operator=(const Private<T>&);
718 };
719
720 /** @} group Threads */
721
722 /*! A glibmm thread example.
723  * @example thread/thread.cc
724  */
725
726
727 #ifndef DOXYGEN_SHOULD_SKIP_THIS
728
729 /***************************************************************************/
730 /*  inline implementation                                                  */
731 /***************************************************************************/
732
733 // internal
734 void thread_init_impl();
735
736 /* This function must be inline, to avoid an unnecessary dependency on
737  * libgthread even if the thread system is not used.  libgthread might
738  * not even be available if GLib was compiled without thread support.
739  */
740 inline
741 void thread_init(GThreadFunctions* vtable)
742 {
743   g_thread_init(vtable);
744   Glib::thread_init_impl();
745 }
746
747 inline
748 bool thread_supported()
749 {
750   //MSVC++ needs the != 0 to avoid an int -> bool cast warning.
751   return (g_thread_supported() != 0);
752 }
753
754
755 /**** Glib::Mutex::Lock ****************************************************/
756
757 inline
758 Mutex::Lock::Lock(Mutex& mutex)
759 :
760   mutex_  (mutex),
761   locked_ (true)
762 {
763   mutex_.lock();
764 }
765
766 inline
767 Mutex::Lock::Lock(Mutex& mutex, NotLock)
768 :
769   mutex_  (mutex),
770   locked_ (false)
771 {}
772
773 inline
774 Mutex::Lock::Lock(Mutex& mutex, TryLock)
775 :
776   mutex_  (mutex),
777   locked_ (mutex.trylock())
778 {}
779
780 inline
781 Mutex::Lock::~Lock()
782 {
783   if(locked_)
784     mutex_.unlock();
785 }
786
787 inline
788 void Mutex::Lock::acquire()
789 {
790   mutex_.lock();
791   locked_ = true;
792 }
793
794 inline
795 bool Mutex::Lock::try_acquire()
796 {
797   locked_ = mutex_.trylock();
798   return locked_;
799 }
800
801 inline
802 void Mutex::Lock::release()
803 {
804   mutex_.unlock();
805   locked_ = false;
806 }
807
808 inline
809 bool Mutex::Lock::locked() const
810 {
811   return locked_;
812 }
813
814
815 /**** Glib::RecMutex::Lock *************************************************/
816
817 inline
818 RecMutex::Lock::Lock(RecMutex& mutex)
819 :
820   mutex_  (mutex),
821   locked_ (true)
822 {
823   mutex_.lock();
824 }
825
826 inline
827 RecMutex::Lock::Lock(RecMutex& mutex, NotLock)
828 :
829   mutex_  (mutex),
830   locked_ (false)
831 {}
832
833 inline
834 RecMutex::Lock::Lock(RecMutex& mutex, TryLock)
835 :
836   mutex_  (mutex),
837   locked_ (mutex.trylock())
838 {}
839
840 inline
841 RecMutex::Lock::~Lock()
842 {
843   if(locked_)
844     mutex_.unlock();
845 }
846
847 inline
848 void RecMutex::Lock::acquire()
849 {
850   mutex_.lock();
851   locked_ = true;
852 }
853
854 inline
855 bool RecMutex::Lock::try_acquire()
856 {
857   locked_ = mutex_.trylock();
858   return locked_;
859 }
860
861 inline
862 void RecMutex::Lock::release()
863 {
864   mutex_.unlock();
865   locked_ = false;
866 }
867
868 inline
869 bool RecMutex::Lock::locked() const
870 {
871   return locked_;
872 }
873
874
875 /**** Glib::RWLock::ReaderLock *********************************************/
876
877 inline
878 RWLock::ReaderLock::ReaderLock(RWLock& rwlock)
879 :
880   rwlock_ (rwlock),
881   locked_ (true)
882 {
883   rwlock_.reader_lock();
884 }
885
886 inline
887 RWLock::ReaderLock::ReaderLock(RWLock& rwlock, NotLock)
888 :
889   rwlock_ (rwlock),
890   locked_ (false)
891 {}
892
893 inline
894 RWLock::ReaderLock::ReaderLock(RWLock& rwlock, TryLock)
895 :
896   rwlock_ (rwlock),
897   locked_ (rwlock.reader_trylock())
898 {}
899
900 inline
901 RWLock::ReaderLock::~ReaderLock()
902 {
903   if(locked_)
904     rwlock_.reader_unlock();
905 }
906
907 inline
908 void RWLock::ReaderLock::acquire()
909 {
910   rwlock_.reader_lock();
911   locked_ = true;
912 }
913
914 inline
915 bool RWLock::ReaderLock::try_acquire()
916 {
917   locked_ = rwlock_.reader_trylock();
918   return locked_;
919 }
920
921 inline
922 void RWLock::ReaderLock::release()
923 {
924   rwlock_.reader_unlock();
925   locked_ = false;
926 }
927
928 inline
929 bool RWLock::ReaderLock::locked() const
930 {
931   return locked_;
932 }
933
934
935 /**** Glib::RWLock::WriterLock *********************************************/
936
937 inline
938 RWLock::WriterLock::WriterLock(RWLock& rwlock)
939 :
940   rwlock_ (rwlock),
941   locked_ (true)
942 {
943   rwlock_.writer_lock();
944 }
945
946 inline
947 RWLock::WriterLock::WriterLock(RWLock& rwlock, NotLock)
948 :
949   rwlock_ (rwlock),
950   locked_ (false)
951 {}
952
953 inline
954 RWLock::WriterLock::WriterLock(RWLock& rwlock, TryLock)
955 :
956   rwlock_ (rwlock),
957   locked_ (rwlock.writer_trylock())
958 {}
959
960 inline
961 RWLock::WriterLock::~WriterLock()
962 {
963   if(locked_)
964     rwlock_.writer_unlock();
965 }
966
967 inline
968 void RWLock::WriterLock::acquire()
969 {
970   rwlock_.writer_lock();
971   locked_ = true;
972 }
973
974 inline
975 bool RWLock::WriterLock::try_acquire()
976 {
977   locked_ = rwlock_.writer_trylock();
978   return locked_;
979 }
980
981 inline
982 void RWLock::WriterLock::release()
983 {
984   rwlock_.writer_unlock();
985   locked_ = false;
986 }
987
988 inline
989 bool RWLock::WriterLock::locked() const
990 {
991   return locked_;
992 }
993
994
995 /**** Glib::StaticPrivate **************************************************/
996
997 // static
998 template <class T>
999 void StaticPrivate<T>::delete_ptr(void* data)
1000 {
1001   delete static_cast<T*>(data);
1002 }
1003
1004 template <class T> inline
1005 T* StaticPrivate<T>::get()
1006 {
1007   return static_cast<T*>(g_static_private_get(&gobject_));
1008 }
1009
1010 template <class T> inline
1011 void StaticPrivate<T>::set(T* data, typename StaticPrivate<T>::DestroyNotifyFunc notify_func)
1012 {
1013   g_static_private_set(&gobject_, data, notify_func);
1014 }
1015
1016
1017 /**** Glib::Private ********************************************************/
1018
1019 // static
1020 template <class T>
1021 void Private<T>::delete_ptr(void* data)
1022 {
1023   delete static_cast<T*>(data);
1024 }
1025
1026 template <class T> inline
1027 Private<T>::Private(typename Private<T>::DestructorFunc destructor_func)
1028 :
1029   gobject_ (g_private_new(destructor_func))
1030 {}
1031
1032 template <class T> inline
1033 T* Private<T>::get()
1034 {
1035   return static_cast<T*>(g_private_get(gobject_));
1036 }
1037
1038 template <class T> inline
1039 void Private<T>::set(T* data)
1040 {
1041   g_private_set(gobject_, data);
1042 }
1043
1044 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
1045
1046 } // namespace Glib
1047