2006-10-21 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-threads.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-threads.h  D-Bus threads handling
3  *
4  * Copyright (C) 2002, 2003 Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include "dbus-threads.h"
24 #include "dbus-internals.h"
25 #include "dbus-threads-internal.h"
26 #include "dbus-list.h"
27
28 #if defined(__WIN32) || defined(__CYGWIN__)
29 #define USE_WIN32_THREADS
30 #endif
31
32 #ifdef USE_WIN32_THREADS
33 #include <windows.h>
34 #else
35 #include <sys/time.h>
36 #include <pthread.h>
37 #endif
38
39 static DBusThreadFunctions thread_functions =
40 {
41   0,
42   NULL, NULL, NULL, NULL, NULL,
43   NULL, NULL, NULL, NULL, NULL,
44   NULL, NULL, NULL, NULL,
45   
46   NULL, NULL, NULL, NULL
47 };
48
49 #ifdef USE_WIN32_THREADS
50 struct DBusCondVar {
51   DBusList *list;
52   CRITICAL_SECTION lock;
53 };
54
55 static DWORD dbus_cond_event_tls = TLS_OUT_OF_INDEXES;
56 #endif
57
58 static int thread_init_generation = 0;
59  
60 static DBusList *uninitialized_mutex_list = NULL;
61 static DBusList *uninitialized_condvar_list = NULL;
62
63 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
64 #define _DBUS_DUMMY_MUTEX ((DBusMutex*)0xABCDEF)
65
66 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
67 #define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2)
68
69 /**
70  * @defgroup DBusThreadsInternals Thread functions
71  * @ingroup  DBusInternals
72  * @brief _dbus_mutex_lock(), etc.
73  *
74  * Functions and macros related to threads and thread locks.
75  *
76  * @{
77  */
78
79 /**
80  * Creates a new mutex using the function supplied to dbus_threads_init(),
81  * or creates a no-op mutex if threads are not initialized.
82  * May return #NULL even if threads are initialized, indicating
83  * out-of-memory.
84  *
85  * @returns new mutex or #NULL
86  */
87 DBusMutex*
88 _dbus_mutex_new (void)
89 {
90   if (thread_functions.recursive_mutex_new)
91     return (* thread_functions.recursive_mutex_new) ();
92   else if (thread_functions.mutex_new)
93     return (* thread_functions.mutex_new) ();
94   else
95     return _DBUS_DUMMY_MUTEX;
96 }
97
98 /**
99  * This does the same thing as _dbus_mutex_new.  It however
100  * gives another level of indirection by allocating a pointer
101  * to point to the mutex location.  This allows the threading
102  * module to swap out dummy mutexes for real a real mutex so libraries
103  * can initialize threads even after the D-Bus API has been used.
104  *
105  * @param location_p the location of the new mutex, can return #NULL on OOM
106  */
107 void
108 _dbus_mutex_new_at_location (DBusMutex **location_p)
109 {
110   _dbus_assert (location_p != NULL);
111
112   *location_p = _dbus_mutex_new();
113
114   if (thread_init_generation != _dbus_current_generation && *location_p)
115     {
116       if (!_dbus_list_append (&uninitialized_mutex_list, location_p))
117         {
118           _dbus_mutex_free (*location_p);
119           *location_p = NULL;
120         }
121     }
122 }
123
124 /**
125  * Frees a mutex created with dbus_mutex_new(); does
126  * nothing if passed a #NULL pointer.
127  */
128 void
129 _dbus_mutex_free (DBusMutex *mutex)
130 {
131   if (mutex)
132     {
133       if (mutex && thread_functions.recursive_mutex_free)
134         (* thread_functions.recursive_mutex_free) (mutex);
135       else if (mutex && thread_functions.mutex_free)
136         (* thread_functions.mutex_free) (mutex);
137     }
138 }
139
140 /**
141  * Frees a mutex and removes it from the 
142  * uninitialized_mutex_list;
143  * does nothing if passed a #NULL pointer.
144  */
145 void
146 _dbus_mutex_free_at_location (DBusMutex **location_p)
147 {
148   if (location_p)
149     {
150       if (thread_init_generation != _dbus_current_generation)
151         _dbus_list_remove (&uninitialized_mutex_list, location_p);
152
153       _dbus_mutex_free (*location_p);
154     }
155 }
156
157 /**
158  * Locks a mutex. Does nothing if passed a #NULL pointer.
159  * Locks may be recursive if threading implementation initialized
160  * recursive locks.
161  */
162 void
163 _dbus_mutex_lock (DBusMutex *mutex)
164 {
165   if (mutex) 
166     {
167       if (thread_functions.recursive_mutex_lock)
168         (* thread_functions.recursive_mutex_lock) (mutex);
169       else if (thread_functions.mutex_lock)
170         (* thread_functions.mutex_lock) (mutex);
171     }
172 }
173
174 /**
175  * Unlocks a mutex. Does nothing if passed a #NULL pointer.
176  *
177  * @returns #TRUE on success
178  */
179 void
180 _dbus_mutex_unlock (DBusMutex *mutex)
181 {
182   if (mutex)
183     {
184       if (thread_functions.recursive_mutex_unlock)
185         (* thread_functions.recursive_mutex_unlock) (mutex);
186       else if (thread_functions.mutex_unlock)
187         (* thread_functions.mutex_unlock) (mutex);
188     }
189 }
190
191 /**
192  * Creates a new condition variable using the function supplied
193  * to dbus_threads_init(), or creates a no-op condition variable
194  * if threads are not initialized. May return #NULL even if
195  * threads are initialized, indicating out-of-memory.
196  *
197  * @returns new mutex or #NULL
198  */
199 DBusCondVar *
200 _dbus_condvar_new (void)
201 {
202   if (thread_functions.condvar_new)
203     return (* thread_functions.condvar_new) ();
204   else
205     return _DBUS_DUMMY_CONDVAR;
206 }
207
208
209 /**
210  * This does the same thing as _dbus_condvar_new.  It however
211  * gives another level of indirection by allocating a pointer
212  * to point to the condvar location.  This allows the threading
213  * module to swap out dummy condvars for real a real condvar so libraries
214  * can initialize threads even after the D-Bus API has been used.
215  *
216  * @returns the location of a new condvar or #NULL on OOM
217  */
218
219 void 
220 _dbus_condvar_new_at_location (DBusCondVar **location_p)
221 {
222   *location_p = _dbus_condvar_new();
223
224   if (thread_init_generation != _dbus_current_generation && *location_p)
225     {
226       if (!_dbus_list_append (&uninitialized_condvar_list, location_p))
227         {
228           _dbus_condvar_free (*location_p);
229           *location_p = NULL;
230         }
231     }
232 }
233
234
235 /**
236  * Frees a conditional variable created with dbus_condvar_new(); does
237  * nothing if passed a #NULL pointer.
238  */
239 void
240 _dbus_condvar_free (DBusCondVar *cond)
241 {
242   if (cond && thread_functions.condvar_free)
243     (* thread_functions.condvar_free) (cond);
244 }
245
246 /**
247  * Frees a conditional variable and removes it from the 
248  * uninitialized_condvar_list; 
249  * does nothing if passed a #NULL pointer.
250  */
251 void
252 _dbus_condvar_free_at_location (DBusCondVar **location_p)
253 {
254   if (location_p)
255     {
256       if (thread_init_generation != _dbus_current_generation)
257         _dbus_list_remove (&uninitialized_condvar_list, location_p);
258
259       _dbus_condvar_free (*location_p);
260     }
261 }
262
263 /**
264  * Atomically unlocks the mutex and waits for the conditions
265  * variable to be signalled. Locks the mutex again before
266  * returning.
267  * Does nothing if passed a #NULL pointer.
268  */
269 void
270 _dbus_condvar_wait (DBusCondVar *cond,
271                     DBusMutex   *mutex)
272 {
273   if (cond && mutex && thread_functions.condvar_wait)
274     (* thread_functions.condvar_wait) (cond, mutex);
275 }
276
277 /**
278  * Atomically unlocks the mutex and waits for the conditions
279  * variable to be signalled, or for a timeout. Locks the
280  * mutex again before returning.
281  * Does nothing if passed a #NULL pointer.
282  *
283  * @param cond the condition variable
284  * @param mutex the mutex
285  * @param timeout_milliseconds the maximum time to wait
286  * @returns TRUE if the condition was reached, or FALSE if the
287  * timeout was reached.
288  */
289 dbus_bool_t
290 _dbus_condvar_wait_timeout (DBusCondVar               *cond,
291                             DBusMutex                 *mutex,
292                             int                        timeout_milliseconds)
293 {
294   if (cond && mutex && thread_functions.condvar_wait)
295     return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds);
296   else
297     return TRUE;
298 }
299
300 /**
301  * If there are threads waiting on the condition variable, wake
302  * up exactly one. 
303  * Does nothing if passed a #NULL pointer.
304  */
305 void
306 _dbus_condvar_wake_one (DBusCondVar *cond)
307 {
308   if (cond && thread_functions.condvar_wake_one)
309     (* thread_functions.condvar_wake_one) (cond);
310 }
311
312 /**
313  * If there are threads waiting on the condition variable, wake
314  * up all of them. 
315  * Does nothing if passed a #NULL pointer.
316  */
317 void
318 _dbus_condvar_wake_all (DBusCondVar *cond)
319 {
320   if (cond && thread_functions.condvar_wake_all)
321     (* thread_functions.condvar_wake_all) (cond);
322 }
323
324 static void
325 shutdown_global_locks (void *data)
326 {
327   DBusMutex ***locks = data;
328   int i;
329
330   i = 0;
331   while (i < _DBUS_N_GLOBAL_LOCKS)
332     {
333       _dbus_mutex_free (*(locks[i]));
334       *(locks[i]) = NULL;
335       ++i;
336     }
337   
338   dbus_free (locks);
339 }
340
341 static void
342 shutdown_uninitialized_locks (void *data)
343 {
344   _dbus_list_clear (&uninitialized_mutex_list);
345   _dbus_list_clear (&uninitialized_condvar_list);
346 }
347
348 static dbus_bool_t
349 init_uninitialized_locks (void)
350 {
351   DBusList *link;
352
353   _dbus_assert (thread_init_generation == 0);
354
355   link = uninitialized_mutex_list;
356   while (link != NULL)
357     {
358       DBusMutex **mp;
359
360       mp = (DBusMutex **)link->data;
361       _dbus_assert (*mp == _DBUS_DUMMY_MUTEX);
362
363       *mp = _dbus_mutex_new ();
364       if (*mp == NULL)
365         goto fail_mutex;
366
367       link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
368     }
369
370   link = uninitialized_condvar_list;
371   while (link != NULL)
372     {
373       DBusCondVar **cp;
374
375       cp = (DBusCondVar **)link->data;
376       _dbus_assert (*cp == _DBUS_DUMMY_CONDVAR);
377
378       *cp = _dbus_condvar_new ();
379       if (*cp == NULL)
380         goto fail_condvar;
381
382       link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
383     }
384
385   _dbus_list_clear (&uninitialized_mutex_list);
386   _dbus_list_clear (&uninitialized_condvar_list);
387
388   if (!_dbus_register_shutdown_func (shutdown_uninitialized_locks,
389                                      NULL))
390     goto fail_condvar;
391
392   return TRUE;
393
394  fail_condvar:
395   link = uninitialized_condvar_list;
396   while (link != NULL)
397     {
398       DBusCondVar **cp;
399
400       cp = (DBusCondVar **)link->data;
401
402       if (*cp != _DBUS_DUMMY_CONDVAR)
403         _dbus_condvar_free (*cp);
404       else
405         break;
406
407       *cp = _DBUS_DUMMY_CONDVAR;
408
409       link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
410     }
411
412  fail_mutex:
413   link = uninitialized_mutex_list;
414   while (link != NULL)
415     {
416       DBusMutex **mp;
417
418       mp = (DBusMutex **)link->data;
419
420       if (*mp != _DBUS_DUMMY_MUTEX)
421         _dbus_mutex_free (*mp);
422       else
423         break;
424
425       *mp = _DBUS_DUMMY_MUTEX;
426
427       link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
428     }
429
430   return FALSE;
431 }
432
433 static dbus_bool_t
434 init_locks (void)
435 {
436   int i;
437   DBusMutex ***dynamic_global_locks;
438   
439   DBusMutex **global_locks[] = {
440 #define LOCK_ADDR(name) (& _dbus_lock_##name)
441     LOCK_ADDR (win_fds),
442     LOCK_ADDR (sid_atom_cache),
443     LOCK_ADDR (list),
444     LOCK_ADDR (connection_slots),
445     LOCK_ADDR (pending_call_slots),
446     LOCK_ADDR (server_slots),
447     LOCK_ADDR (message_slots),
448     LOCK_ADDR (atomic),
449     LOCK_ADDR (bus),
450     LOCK_ADDR (shutdown_funcs),
451     LOCK_ADDR (system_users),
452     LOCK_ADDR (message_cache),
453     LOCK_ADDR (shared_connections),
454     LOCK_ADDR (machine_uuid)
455 #undef LOCK_ADDR
456   };
457
458   _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
459                 _DBUS_N_GLOBAL_LOCKS);
460
461   i = 0;
462   
463   dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
464   if (dynamic_global_locks == NULL)
465     goto failed;
466   
467   while (i < _DBUS_N_ELEMENTS (global_locks))
468     {
469       *global_locks[i] = _dbus_mutex_new ();
470       
471       if (*global_locks[i] == NULL)
472         goto failed;
473
474       dynamic_global_locks[i] = global_locks[i];
475
476       ++i;
477     }
478   
479   if (!_dbus_register_shutdown_func (shutdown_global_locks,
480                                      dynamic_global_locks))
481     goto failed;
482
483   if (!init_uninitialized_locks ())
484     goto failed;
485   
486   return TRUE;
487
488  failed:
489   dbus_free (dynamic_global_locks);
490                                      
491   for (i = i - 1; i >= 0; i--)
492     {
493       _dbus_mutex_free (*global_locks[i]);
494       *global_locks[i] = NULL;
495     }
496   return FALSE;
497 }
498
499 /** @} */ /* end of internals */
500
501 /**
502  * @defgroup DBusThreads Thread functions
503  * @ingroup  DBus
504  * @brief dbus_threads_init() and dbus_threads_init_default()
505  *
506  * Functions and macros related to threads and thread locks.
507  *
508  * If threads are initialized, the D-Bus library has locks on all
509  * global data structures.  In addition, each #DBusConnection has a
510  * lock, so only one thread at a time can touch the connection.  (See
511  * @ref DBusConnection for more on connection locking.)
512  *
513  * Most other objects, however, do not have locks - they can only be
514  * used from a single thread at a time, unless you lock them yourself.
515  * For example, a #DBusMessage can't be modified from two threads
516  * at once.
517  * 
518  * @{
519  */
520
521 /**
522  * 
523  * Initializes threads. If this function is not called,
524  * the D-Bus library will not lock any data structures.
525  * If it is called, D-Bus will do locking, at some cost
526  * in efficiency. Note that this function must be called
527  * BEFORE the second thread is started.
528  *
529  * Use dbus_threads_init_default() if you don't need a
530  * particular thread implementation.
531  *
532  * This function may be called more than once.  The first
533  * one wins.
534  *
535  * @param functions functions for using threads
536  * @returns #TRUE on success, #FALSE if no memory
537  */
538 dbus_bool_t
539 dbus_threads_init (const DBusThreadFunctions *functions)
540 {
541   dbus_bool_t mutex_set;
542   dbus_bool_t recursive_mutex_set;
543
544   _dbus_assert (functions != NULL);
545
546   /* these base functions are required. Future additions to
547    * DBusThreadFunctions may be optional.
548    */
549   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK);
550   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK);
551   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK);
552   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK);
553   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK);
554   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK);
555   _dbus_assert (functions->condvar_new != NULL);
556   _dbus_assert (functions->condvar_free != NULL);
557   _dbus_assert (functions->condvar_wait != NULL);
558   _dbus_assert (functions->condvar_wait_timeout != NULL);
559   _dbus_assert (functions->condvar_wake_one != NULL);
560   _dbus_assert (functions->condvar_wake_all != NULL);
561
562   /* Either the mutex function set or recursive mutex set needs 
563    * to be available but not both
564    */
565   mutex_set = (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK) &&  
566               (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK) && 
567               (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK) &&
568               (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK) &&
569                functions->mutex_new &&
570                functions->mutex_free &&
571                functions->mutex_lock &&
572                functions->mutex_unlock;
573
574   recursive_mutex_set = 
575               (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK) && 
576               (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK) && 
577               (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK) && 
578               (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK) &&
579                 functions->recursive_mutex_new &&
580                 functions->recursive_mutex_free &&
581                 functions->recursive_mutex_lock &&
582                 functions->recursive_mutex_unlock;
583
584   if (!(mutex_set || recursive_mutex_set))
585     _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex " 
586                               "functions sets should be passed into "
587                               "dbus_threads_init. Neither sets were passed.");
588
589   if (mutex_set && recursive_mutex_set)
590     _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex " 
591                               "functions sets should be passed into "
592                               "dbus_threads_init. Both sets were passed. "
593                               "You most likely just want to set the recursive "
594                               "mutex functions to avoid deadlocks in D-Bus.");
595                           
596   /* Check that all bits in the mask actually are valid mask bits.
597    * ensures people won't write code that breaks when we add
598    * new bits.
599    */
600   _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
601
602   if (thread_init_generation != _dbus_current_generation)
603     thread_functions.mask = 0; /* allow re-init in new generation */
604  
605   /* Silently allow multiple init
606    * First init wins and D-Bus will always use its threading system 
607    */ 
608   if (thread_functions.mask != 0)
609     return TRUE;
610   
611   thread_functions.mutex_new = functions->mutex_new;
612   thread_functions.mutex_free = functions->mutex_free;
613   thread_functions.mutex_lock = functions->mutex_lock;
614   thread_functions.mutex_unlock = functions->mutex_unlock;
615   
616   thread_functions.condvar_new = functions->condvar_new;
617   thread_functions.condvar_free = functions->condvar_free;
618   thread_functions.condvar_wait = functions->condvar_wait;
619   thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
620   thread_functions.condvar_wake_one = functions->condvar_wake_one;
621   thread_functions.condvar_wake_all = functions->condvar_wake_all;
622  
623   if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK)
624     thread_functions.recursive_mutex_new = functions->recursive_mutex_new;
625   
626   if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK)
627     thread_functions.recursive_mutex_free = functions->recursive_mutex_free;
628   
629   if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK)
630     thread_functions.recursive_mutex_lock = functions->recursive_mutex_lock;
631
632   if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK)
633     thread_functions.recursive_mutex_unlock = functions->recursive_mutex_unlock;
634
635   thread_functions.mask = functions->mask;
636
637   if (!init_locks ())
638     return FALSE;
639
640   thread_init_generation = _dbus_current_generation;
641   
642   return TRUE;
643 }
644
645
646
647 /* Default thread implemenation */
648
649 static DBusMutex*   _dbus_internal_mutex_new            (void);
650 static void         _dbus_internal_mutex_free           (DBusMutex   *mutex);
651 static dbus_bool_t  _dbus_internal_mutex_lock           (DBusMutex   *mutex);
652 static dbus_bool_t  _dbus_internal_mutex_unlock         (DBusMutex   *mutex);
653 static DBusCondVar *_dbus_internal_condvar_new          (void);
654 static void         _dbus_internal_condvar_free         (DBusCondVar *cond);
655 static void         _dbus_internal_condvar_wait         (DBusCondVar *cond,
656                                                          DBusMutex   *mutex);
657 static dbus_bool_t  _dbus_internal_condvar_wait_timeout (DBusCondVar *cond,
658                                                          DBusMutex   *mutex,
659                                                          int          timeout_milliseconds);
660 static void         _dbus_internal_condvar_wake_one     (DBusCondVar *cond);
661 static void         _dbus_internal_condvar_wake_all     (DBusCondVar *cond);
662
663 #ifdef USE_WIN32_THREADS
664
665 BOOL WINAPI DllMain (HINSTANCE hinstDLL,
666                      DWORD     fdwReason,
667                      LPVOID    lpvReserved);
668
669 /* We need this to free the TLS events on thread exit */
670 BOOL WINAPI
671 DllMain (HINSTANCE hinstDLL,
672          DWORD     fdwReason,
673          LPVOID    lpvReserved)
674 {
675   HANDLE event;
676   switch (fdwReason) 
677     { 
678     case DLL_THREAD_DETACH:
679       if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
680         {
681           event = TlsGetValue(dbus_cond_event_tls);
682           CloseHandle (event);
683           TlsSetValue(dbus_cond_event_tls, NULL);
684         }
685       break;
686     case DLL_PROCESS_DETACH: 
687       if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
688         {
689           event = TlsGetValue(dbus_cond_event_tls);
690           CloseHandle (event);
691           TlsSetValue(dbus_cond_event_tls, NULL);
692
693           TlsFree(dbus_cond_event_tls); 
694         }
695       break;
696     default: 
697       break; 
698     }
699   return TRUE;
700 }
701
702 static DBusMutex*
703 _dbus_internal_mutex_new (void)
704 {
705   HANDLE handle;
706   handle = CreateMutex (NULL, FALSE, NULL);
707   return (DBusMutex *) handle;
708 }
709
710 static void
711 _dbus_internal_mutex_free (DBusMutex *mutex)
712 {
713   CloseHandle ((HANDLE *) mutex);
714 }
715
716 static dbus_bool_t
717 _dbus_internal_mutex_lock (DBusMutex *mutex)
718 {
719   return WaitForSingleObject ((HANDLE *) mutex, INFINITE) != WAIT_FAILED;
720 }
721
722 static dbus_bool_t
723 _dbus_internal_mutex_unlock (DBusMutex *mutex)
724 {
725   return ReleaseMutex ((HANDLE *) mutex) != 0;
726 }
727
728 static DBusCondVar *
729 _dbus_internal_condvar_new (void)
730 {
731   DBusCondVar *cond;
732     
733   cond = dbus_new (DBusCondVar, 1);
734   if (cond == NULL)
735     return NULL;
736   
737   cond->list = NULL;
738   
739   InitializeCriticalSection (&cond->lock);
740   return (DBusCondVar *) cond;
741 }
742
743 static void
744 _dbus_internal_condvar_free (DBusCondVar *cond)
745 {
746   DeleteCriticalSection (&cond->lock);
747   _dbus_list_clear (&cond->list);
748   dbus_free (cond);
749 }
750
751 static dbus_bool_t
752 _dbus_condvar_wait_win32 (DBusCondVar *cond,
753                           DBusMutex *mutex,
754                           int milliseconds)
755 {
756   DWORD retval;
757   dbus_bool_t ret;
758   HANDLE event = TlsGetValue (dbus_cond_event_tls);
759
760   if (!event)
761     {
762       event = CreateEvent (0, FALSE, FALSE, NULL);
763       if (event == 0)
764         return FALSE;
765       TlsSetValue (dbus_cond_event_tls, event);
766     }
767
768   EnterCriticalSection (&cond->lock);
769
770   /* The event must not be signaled. Check this */
771   _dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT);
772
773   ret = _dbus_list_append (&cond->list, event);
774   
775   LeaveCriticalSection (&cond->lock);
776   
777   if (!ret)
778     return FALSE; /* Prepend failed */
779
780   _dbus_mutex_unlock (mutex);
781   retval = WaitForSingleObject (event, milliseconds);
782   _dbus_mutex_lock (mutex);
783   
784   if (retval == WAIT_TIMEOUT)
785     {
786       EnterCriticalSection (&cond->lock);
787       _dbus_list_remove (&cond->list, event);
788
789       /* In the meantime we could have been signaled, so we must again
790        * wait for the signal, this time with no timeout, to reset
791        * it. retval is set again to honour the late arrival of the
792        * signal */
793       retval = WaitForSingleObject (event, 0);
794
795       LeaveCriticalSection (&cond->lock);
796     }
797
798 #ifndef DBUS_DISABLE_ASSERT
799   EnterCriticalSection (&cond->lock);
800
801   /* Now event must not be inside the array, check this */
802   _dbus_assert (_dbus_list_remove (cond->list, event) == FALSE);
803
804   LeaveCriticalSection (&cond->lock);
805 #endif /* !G_DISABLE_ASSERT */
806
807   return retval != WAIT_TIMEOUT;
808 }
809
810 static void
811 _dbus_internal_condvar_wait (DBusCondVar *cond,
812                     DBusMutex   *mutex)
813 {
814   _dbus_condvar_wait_win32 (cond, mutex, INFINITE);
815 }
816
817 static dbus_bool_t
818 _dbus_internal_condvar_wait_timeout (DBusCondVar               *cond,
819                                      DBusMutex                 *mutex,
820                                      int                        timeout_milliseconds)
821 {
822   return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds);
823 }
824
825 static void
826 _dbus_internal_condvar_wake_one (DBusCondVar *cond)
827 {
828   EnterCriticalSection (&cond->lock);
829   
830   if (cond->list != NULL)
831     SetEvent (_dbus_list_pop_first (&cond->list));
832     
833   LeaveCriticalSection (&cond->lock);
834 }
835
836 static void
837 _dbus_internal_condvar_wake_all (DBusCondVar *cond)
838 {
839   EnterCriticalSection (&cond->lock);
840
841   while (cond->list != NULL)
842     SetEvent (_dbus_list_pop_first (&cond->list));
843   
844   LeaveCriticalSection (&cond->lock);
845 }
846
847
848 #else /* Posix threads */
849
850 static DBusMutex*
851 _dbus_internal_mutex_new (void)
852 {
853   pthread_mutex_t *retval;
854   
855   retval = dbus_new (pthread_mutex_t, 1);
856   if (retval == NULL)
857     return NULL;
858   
859   if (pthread_mutex_init (retval, NULL))
860     {
861       dbus_free (retval);
862       return NULL;
863     }
864   return (DBusMutex *) retval;
865 }
866
867 static void
868 _dbus_internal_mutex_free (DBusMutex *mutex)
869 {
870   pthread_mutex_destroy ((pthread_mutex_t *) mutex);
871   dbus_free (mutex);
872 }
873
874 static dbus_bool_t
875 _dbus_internal_mutex_lock (DBusMutex *mutex)
876 {
877   return pthread_mutex_lock ((pthread_mutex_t *) mutex) == 0;
878 }
879
880 static dbus_bool_t
881 _dbus_internal_mutex_unlock (DBusMutex *mutex)
882 {
883   return pthread_mutex_unlock ((pthread_mutex_t *) mutex) == 0;
884 }
885
886 static DBusCondVar *
887 _dbus_internal_condvar_new (void)
888 {
889   pthread_cond_t *retval;
890   
891   retval = dbus_new (pthread_cond_t, 1);
892   if (retval == NULL)
893     return NULL;
894   
895   if (pthread_cond_init (retval, NULL))
896     {
897       dbus_free (retval);
898       return NULL;
899     }
900   return (DBusCondVar *) retval;
901 }
902
903 static void
904 _dbus_internal_condvar_free (DBusCondVar *cond)
905 {
906   pthread_cond_destroy ((pthread_cond_t *) cond);
907   dbus_free (cond);
908 }
909
910 static void
911 _dbus_internal_condvar_wait (DBusCondVar *cond,
912                     DBusMutex   *mutex)
913 {
914   pthread_cond_wait ((pthread_cond_t *)cond,
915                      (pthread_mutex_t *) mutex);
916 }
917
918 static dbus_bool_t
919 _dbus_internal_condvar_wait_timeout (DBusCondVar               *cond,
920                                      DBusMutex                 *mutex,
921                                      int                        timeout_milliseconds)
922 {
923   struct timeval time_now;
924   struct timespec end_time;
925   int result;
926   
927   gettimeofday (&time_now, NULL);
928   
929   end_time.tv_sec = time_now.tv_sec + timeout_milliseconds / 1000;
930   end_time.tv_nsec = (time_now.tv_usec + (timeout_milliseconds % 1000) * 1000) * 1000;
931   if (end_time.tv_nsec > 1000*1000*1000)
932     {
933       end_time.tv_sec += 1;
934       end_time.tv_nsec -= 1000*1000*1000;
935     }
936   
937   result = pthread_cond_timedwait ((pthread_cond_t *) cond,
938                                    (pthread_mutex_t *) mutex,
939                                    &end_time);
940   return result == ETIMEDOUT;
941 }
942
943 static void
944 _dbus_internal_condvar_wake_one (DBusCondVar *cond)
945 {
946   pthread_cond_signal ((pthread_cond_t *)cond);
947 }
948
949 static void
950 _dbus_internal_condvar_wake_all (DBusCondVar *cond)
951 {
952   pthread_cond_broadcast ((pthread_cond_t *)cond);
953 }
954
955 #endif
956
957 static const DBusThreadFunctions internal_functions =
958 {
959   DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
960   DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
961   DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
962   DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
963   DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
964   DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
965   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
966   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
967   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
968   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
969   _dbus_internal_mutex_new,
970   _dbus_internal_mutex_free,
971   _dbus_internal_mutex_lock,
972   _dbus_internal_mutex_unlock,
973   _dbus_internal_condvar_new,
974   _dbus_internal_condvar_free,
975   _dbus_internal_condvar_wait,
976   _dbus_internal_condvar_wait_timeout,
977   _dbus_internal_condvar_wake_one,
978   _dbus_internal_condvar_wake_all
979 };
980
981 /**
982  *
983  * Calls dbus_threads_init() with a default set of
984  * #DBusThreadFunctions appropriate for the platform.
985  *
986  * @returns #TRUE on success, #FALSE if not enough memory
987  */
988 dbus_bool_t
989 dbus_threads_init_default (void)
990 {
991 #ifdef USE_WIN32_THREADS
992   /* We reuse this over several generations, because we can't
993    * free the events once they are in use
994    */
995   if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
996     {
997       dbus_cond_event_tls = TlsAlloc ();
998       if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
999         return FALSE;
1000     }
1001 #endif
1002   
1003   return dbus_threads_init (&internal_functions);
1004 }
1005
1006
1007 /** @} */
1008
1009 #ifdef DBUS_BUILD_TESTS
1010 /** Fake mutex used for debugging */
1011 typedef struct DBusFakeMutex DBusFakeMutex;
1012 /** Fake mutex used for debugging */
1013 struct DBusFakeMutex
1014 {
1015   dbus_bool_t locked; /**< Mutex is "locked" */
1016 };      
1017
1018 static DBusMutex *  dbus_fake_mutex_new            (void);
1019 static void         dbus_fake_mutex_free           (DBusMutex   *mutex);
1020 static dbus_bool_t  dbus_fake_mutex_lock           (DBusMutex   *mutex);
1021 static dbus_bool_t  dbus_fake_mutex_unlock         (DBusMutex   *mutex);
1022 static DBusCondVar* dbus_fake_condvar_new          (void);
1023 static void         dbus_fake_condvar_free         (DBusCondVar *cond);
1024 static void         dbus_fake_condvar_wait         (DBusCondVar *cond,
1025                                                     DBusMutex   *mutex);
1026 static dbus_bool_t  dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
1027                                                     DBusMutex   *mutex,
1028                                                     int          timeout_msec);
1029 static void         dbus_fake_condvar_wake_one     (DBusCondVar *cond);
1030 static void         dbus_fake_condvar_wake_all     (DBusCondVar *cond);
1031
1032
1033 static const DBusThreadFunctions fake_functions =
1034 {
1035   DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
1036   DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
1037   DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
1038   DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
1039   DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
1040   DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
1041   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
1042   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
1043   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
1044   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
1045   dbus_fake_mutex_new,
1046   dbus_fake_mutex_free,
1047   dbus_fake_mutex_lock,
1048   dbus_fake_mutex_unlock,
1049   dbus_fake_condvar_new,
1050   dbus_fake_condvar_free,
1051   dbus_fake_condvar_wait,
1052   dbus_fake_condvar_wait_timeout,
1053   dbus_fake_condvar_wake_one,
1054   dbus_fake_condvar_wake_all
1055 };
1056
1057 static DBusMutex *
1058 dbus_fake_mutex_new (void)
1059 {
1060   DBusFakeMutex *mutex;
1061
1062   mutex = dbus_new0 (DBusFakeMutex, 1);
1063
1064   return (DBusMutex *)mutex;
1065 }
1066
1067 static void
1068 dbus_fake_mutex_free (DBusMutex *mutex)
1069 {
1070   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
1071
1072   _dbus_assert (!fake->locked);
1073   
1074   dbus_free (fake);
1075 }
1076
1077 static dbus_bool_t
1078 dbus_fake_mutex_lock (DBusMutex *mutex)
1079 {
1080   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
1081
1082   _dbus_assert (!fake->locked);
1083
1084   fake->locked = TRUE;
1085   
1086   return TRUE;
1087 }
1088
1089 static dbus_bool_t
1090 dbus_fake_mutex_unlock (DBusMutex *mutex)
1091 {
1092   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
1093
1094   _dbus_assert (fake->locked);
1095
1096   fake->locked = FALSE;
1097   
1098   return TRUE;
1099 }
1100
1101 static DBusCondVar*
1102 dbus_fake_condvar_new (void)
1103 {
1104   return (DBusCondVar*) _dbus_strdup ("FakeCondvar");
1105 }
1106
1107 static void
1108 dbus_fake_condvar_free (DBusCondVar *cond)
1109 {
1110   dbus_free (cond);
1111 }
1112
1113 static void
1114 dbus_fake_condvar_wait (DBusCondVar *cond,
1115                         DBusMutex   *mutex)
1116 {
1117   
1118 }
1119
1120 static dbus_bool_t
1121 dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
1122                                 DBusMutex   *mutex,
1123                                 int         timeout_msec)
1124 {
1125   return TRUE;
1126 }
1127
1128 static void
1129 dbus_fake_condvar_wake_one (DBusCondVar *cond)
1130 {
1131
1132 }
1133
1134 static void
1135 dbus_fake_condvar_wake_all (DBusCondVar *cond)
1136 {
1137
1138 }
1139
1140 dbus_bool_t
1141 _dbus_threads_init_debug (void)
1142 {
1143   return dbus_threads_init (&fake_functions);
1144 }
1145
1146 #endif /* DBUS_BUILD_TESTS */