* dbus/dbus-threads.c: Allow recursive mutex's to be passed into
[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 #undef LOCK_ADDR
455   };
456
457   _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
458                 _DBUS_N_GLOBAL_LOCKS);
459
460   i = 0;
461   
462   dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
463   if (dynamic_global_locks == NULL)
464     goto failed;
465   
466   while (i < _DBUS_N_ELEMENTS (global_locks))
467     {
468       *global_locks[i] = _dbus_mutex_new ();
469       
470       if (*global_locks[i] == NULL)
471         goto failed;
472
473       dynamic_global_locks[i] = global_locks[i];
474
475       ++i;
476     }
477   
478   if (!_dbus_register_shutdown_func (shutdown_global_locks,
479                                      dynamic_global_locks))
480     goto failed;
481
482   if (!init_uninitialized_locks ())
483     goto failed;
484   
485   return TRUE;
486
487  failed:
488   dbus_free (dynamic_global_locks);
489                                      
490   for (i = i - 1; i >= 0; i--)
491     {
492       _dbus_mutex_free (*global_locks[i]);
493       *global_locks[i] = NULL;
494     }
495   return FALSE;
496 }
497
498 /** @} */ /* end of internals */
499
500 /**
501  * @defgroup DBusThreads Thread functions
502  * @ingroup  DBus
503  * @brief dbus_threads_init()
504  *
505  * Functions and macros related to threads and thread locks.
506  *
507  * @{
508  */
509
510 /**
511  * 
512  * Initializes threads. If this function is not called,
513  * the D-Bus library will not lock any data structures.
514  * If it is called, D-Bus will do locking, at some cost
515  * in efficiency. Note that this function must be called
516  * BEFORE the second thread is started.
517  *
518  * Use dbus_threads_init_default() if you don't need a
519  * particular thread implementation.
520  *
521  * This function may be called more than once.  The first
522  * one wins.
523  *
524  * @param functions functions for using threads
525  * @returns #TRUE on success, #FALSE if no memory
526  */
527 dbus_bool_t
528 dbus_threads_init (const DBusThreadFunctions *functions)
529 {
530   dbus_bool_t mutex_set;
531   dbus_bool_t recursive_mutex_set;
532
533   _dbus_assert (functions != NULL);
534
535   /* these base functions are required. Future additions to
536    * DBusThreadFunctions may be optional.
537    */
538   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK);
539   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK);
540   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK);
541   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK);
542   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK);
543   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK);
544   _dbus_assert (functions->condvar_new != NULL);
545   _dbus_assert (functions->condvar_free != NULL);
546   _dbus_assert (functions->condvar_wait != NULL);
547   _dbus_assert (functions->condvar_wait_timeout != NULL);
548   _dbus_assert (functions->condvar_wake_one != NULL);
549   _dbus_assert (functions->condvar_wake_all != NULL);
550
551   /* Either the mutex function set or recursive mutex set needs 
552    * to be available but not both
553    */
554   mutex_set = (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK) &&  
555               (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK) && 
556               (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK) &&
557               (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK) &&
558                functions->mutex_new &&
559                functions->mutex_free &&
560                functions->mutex_lock &&
561                functions->mutex_unlock;
562
563   recursive_mutex_set = 
564               (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK) && 
565               (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK) && 
566               (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK) && 
567               (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK) &&
568                 functions->recursive_mutex_new &&
569                 functions->recursive_mutex_free &&
570                 functions->recursive_mutex_lock &&
571                 functions->recursive_mutex_unlock;
572
573   if (!(mutex_set || recursive_mutex_set))
574     _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex " 
575                               "functions sets should be passed into "
576                               "dbus_threads_init. Neither sets were passed.");
577
578   if (mutex_set && recursive_mutex_set)
579     _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex " 
580                               "functions sets should be passed into "
581                               "dbus_threads_init. Both sets were passed. "
582                               "You most likely just want to set the recursive "
583                               "mutex functions to avoid deadlocks in D-Bus.");
584                           
585   /* Check that all bits in the mask actually are valid mask bits.
586    * ensures people won't write code that breaks when we add
587    * new bits.
588    */
589   _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
590
591   if (thread_init_generation != _dbus_current_generation)
592     thread_functions.mask = 0; /* allow re-init in new generation */
593  
594   /* Silently allow multiple init
595    * First init wins and D-Bus will always use its threading system 
596    */ 
597   if (thread_functions.mask != 0)
598     return TRUE;
599   
600   thread_functions.mutex_new = functions->mutex_new;
601   thread_functions.mutex_free = functions->mutex_free;
602   thread_functions.mutex_lock = functions->mutex_lock;
603   thread_functions.mutex_unlock = functions->mutex_unlock;
604   
605   thread_functions.condvar_new = functions->condvar_new;
606   thread_functions.condvar_free = functions->condvar_free;
607   thread_functions.condvar_wait = functions->condvar_wait;
608   thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
609   thread_functions.condvar_wake_one = functions->condvar_wake_one;
610   thread_functions.condvar_wake_all = functions->condvar_wake_all;
611  
612   if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK)
613     thread_functions.recursive_mutex_new = functions->recursive_mutex_new;
614   
615   if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK)
616     thread_functions.recursive_mutex_free = functions->recursive_mutex_free;
617   
618   if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK)
619     thread_functions.recursive_mutex_lock = functions->recursive_mutex_lock;
620
621   if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK)
622     thread_functions.recursive_mutex_unlock = functions->recursive_mutex_unlock;
623
624   thread_functions.mask = functions->mask;
625
626   if (!init_locks ())
627     return FALSE;
628
629   thread_init_generation = _dbus_current_generation;
630   
631   return TRUE;
632 }
633
634
635
636 /* Default thread implemenation */
637
638 static DBusMutex*   _dbus_internal_mutex_new            (void);
639 static void         _dbus_internal_mutex_free           (DBusMutex   *mutex);
640 static dbus_bool_t  _dbus_internal_mutex_lock           (DBusMutex   *mutex);
641 static dbus_bool_t  _dbus_internal_mutex_unlock         (DBusMutex   *mutex);
642 static DBusCondVar *_dbus_internal_condvar_new          (void);
643 static void         _dbus_internal_condvar_free         (DBusCondVar *cond);
644 static void         _dbus_internal_condvar_wait         (DBusCondVar *cond,
645                                                          DBusMutex   *mutex);
646 static dbus_bool_t  _dbus_internal_condvar_wait_timeout (DBusCondVar *cond,
647                                                          DBusMutex   *mutex,
648                                                          int          timeout_milliseconds);
649 static void         _dbus_internal_condvar_wake_one     (DBusCondVar *cond);
650 static void         _dbus_internal_condvar_wake_all     (DBusCondVar *cond);
651
652 #ifdef USE_WIN32_THREADS
653
654 BOOL WINAPI DllMain (HINSTANCE hinstDLL,
655                      DWORD     fdwReason,
656                      LPVOID    lpvReserved);
657
658 /* We need this to free the TLS events on thread exit */
659 BOOL WINAPI
660 DllMain (HINSTANCE hinstDLL,
661          DWORD     fdwReason,
662          LPVOID    lpvReserved)
663 {
664   HANDLE event;
665   switch (fdwReason) 
666     { 
667     case DLL_THREAD_DETACH:
668       if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
669         {
670           event = TlsGetValue(dbus_cond_event_tls);
671           CloseHandle (event);
672           TlsSetValue(dbus_cond_event_tls, NULL);
673         }
674       break;
675     case DLL_PROCESS_DETACH: 
676       if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
677         {
678           event = TlsGetValue(dbus_cond_event_tls);
679           CloseHandle (event);
680           TlsSetValue(dbus_cond_event_tls, NULL);
681
682           TlsFree(dbus_cond_event_tls); 
683         }
684       break;
685     default: 
686       break; 
687     }
688   return TRUE;
689 }
690
691 static DBusMutex*
692 _dbus_internal_mutex_new (void)
693 {
694   HANDLE handle;
695   handle = CreateMutex (NULL, FALSE, NULL);
696   return (DBusMutex *) handle;
697 }
698
699 static void
700 _dbus_internal_mutex_free (DBusMutex *mutex)
701 {
702   CloseHandle ((HANDLE *) mutex);
703 }
704
705 static dbus_bool_t
706 _dbus_internal_mutex_lock (DBusMutex *mutex)
707 {
708   return WaitForSingleObject ((HANDLE *) mutex, INFINITE) != WAIT_FAILED;
709 }
710
711 static dbus_bool_t
712 _dbus_internal_mutex_unlock (DBusMutex *mutex)
713 {
714   return ReleaseMutex ((HANDLE *) mutex) != 0;
715 }
716
717 static DBusCondVar *
718 _dbus_internal_condvar_new (void)
719 {
720   DBusCondVar *cond;
721     
722   cond = dbus_new (DBusCondVar, 1);
723   if (cond == NULL)
724     return NULL;
725   
726   cond->list = NULL;
727   
728   InitializeCriticalSection (&cond->lock);
729   return (DBusCondVar *) cond;
730 }
731
732 static void
733 _dbus_internal_condvar_free (DBusCondVar *cond)
734 {
735   DeleteCriticalSection (&cond->lock);
736   _dbus_list_clear (&cond->list);
737   dbus_free (cond);
738 }
739
740 static dbus_bool_t
741 _dbus_condvar_wait_win32 (DBusCondVar *cond,
742                           DBusMutex *mutex,
743                           int milliseconds)
744 {
745   DWORD retval;
746   dbus_bool_t ret;
747   HANDLE event = TlsGetValue (dbus_cond_event_tls);
748
749   if (!event)
750     {
751       event = CreateEvent (0, FALSE, FALSE, NULL);
752       if (event == 0)
753         return FALSE;
754       TlsSetValue (dbus_cond_event_tls, event);
755     }
756
757   EnterCriticalSection (&cond->lock);
758
759   /* The event must not be signaled. Check this */
760   _dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT);
761
762   ret = _dbus_list_append (&cond->list, event);
763   
764   LeaveCriticalSection (&cond->lock);
765   
766   if (!ret)
767     return FALSE; /* Prepend failed */
768
769   _dbus_mutex_unlock (mutex);
770   retval = WaitForSingleObject (event, milliseconds);
771   _dbus_mutex_lock (mutex);
772   
773   if (retval == WAIT_TIMEOUT)
774     {
775       EnterCriticalSection (&cond->lock);
776       _dbus_list_remove (&cond->list, event);
777
778       /* In the meantime we could have been signaled, so we must again
779        * wait for the signal, this time with no timeout, to reset
780        * it. retval is set again to honour the late arrival of the
781        * signal */
782       retval = WaitForSingleObject (event, 0);
783
784       LeaveCriticalSection (&cond->lock);
785     }
786
787 #ifndef DBUS_DISABLE_ASSERT
788   EnterCriticalSection (&cond->lock);
789
790   /* Now event must not be inside the array, check this */
791   _dbus_assert (_dbus_list_remove (cond->list, event) == FALSE);
792
793   LeaveCriticalSection (&cond->lock);
794 #endif /* !G_DISABLE_ASSERT */
795
796   return retval != WAIT_TIMEOUT;
797 }
798
799 static void
800 _dbus_internal_condvar_wait (DBusCondVar *cond,
801                     DBusMutex   *mutex)
802 {
803   _dbus_condvar_wait_win32 (cond, mutex, INFINITE);
804 }
805
806 static dbus_bool_t
807 _dbus_internal_condvar_wait_timeout (DBusCondVar               *cond,
808                                      DBusMutex                 *mutex,
809                                      int                        timeout_milliseconds)
810 {
811   return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds);
812 }
813
814 static void
815 _dbus_internal_condvar_wake_one (DBusCondVar *cond)
816 {
817   EnterCriticalSection (&cond->lock);
818   
819   if (cond->list != NULL)
820     SetEvent (_dbus_list_pop_first (&cond->list));
821     
822   LeaveCriticalSection (&cond->lock);
823 }
824
825 static void
826 _dbus_internal_condvar_wake_all (DBusCondVar *cond)
827 {
828   EnterCriticalSection (&cond->lock);
829
830   while (cond->list != NULL)
831     SetEvent (_dbus_list_pop_first (&cond->list));
832   
833   LeaveCriticalSection (&cond->lock);
834 }
835
836
837 #else /* Posix threads */
838
839 static DBusMutex*
840 _dbus_internal_mutex_new (void)
841 {
842   pthread_mutex_t *retval;
843   
844   retval = dbus_new (pthread_mutex_t, 1);
845   if (retval == NULL)
846     return NULL;
847   
848   if (pthread_mutex_init (retval, NULL))
849     {
850       dbus_free (retval);
851       return NULL;
852     }
853   return (DBusMutex *) retval;
854 }
855
856 static void
857 _dbus_internal_mutex_free (DBusMutex *mutex)
858 {
859   pthread_mutex_destroy ((pthread_mutex_t *) mutex);
860   dbus_free (mutex);
861 }
862
863 static dbus_bool_t
864 _dbus_internal_mutex_lock (DBusMutex *mutex)
865 {
866   return pthread_mutex_lock ((pthread_mutex_t *) mutex) == 0;
867 }
868
869 static dbus_bool_t
870 _dbus_internal_mutex_unlock (DBusMutex *mutex)
871 {
872   return pthread_mutex_unlock ((pthread_mutex_t *) mutex) == 0;
873 }
874
875 static DBusCondVar *
876 _dbus_internal_condvar_new (void)
877 {
878   pthread_cond_t *retval;
879   
880   retval = dbus_new (pthread_cond_t, 1);
881   if (retval == NULL)
882     return NULL;
883   
884   if (pthread_cond_init (retval, NULL))
885     {
886       dbus_free (retval);
887       return NULL;
888     }
889   return (DBusCondVar *) retval;
890 }
891
892 static void
893 _dbus_internal_condvar_free (DBusCondVar *cond)
894 {
895   pthread_cond_destroy ((pthread_cond_t *) cond);
896   dbus_free (cond);
897 }
898
899 static void
900 _dbus_internal_condvar_wait (DBusCondVar *cond,
901                     DBusMutex   *mutex)
902 {
903   pthread_cond_wait ((pthread_cond_t *)cond,
904                      (pthread_mutex_t *) mutex);
905 }
906
907 static dbus_bool_t
908 _dbus_internal_condvar_wait_timeout (DBusCondVar               *cond,
909                                      DBusMutex                 *mutex,
910                                      int                        timeout_milliseconds)
911 {
912   struct timeval time_now;
913   struct timespec end_time;
914   int result;
915   
916   gettimeofday (&time_now, NULL);
917   
918   end_time.tv_sec = time_now.tv_sec + timeout_milliseconds / 1000;
919   end_time.tv_nsec = (time_now.tv_usec + (timeout_milliseconds % 1000) * 1000) * 1000;
920   if (end_time.tv_nsec > 1000*1000*1000)
921     {
922       end_time.tv_sec += 1;
923       end_time.tv_nsec -= 1000*1000*1000;
924     }
925   
926   result = pthread_cond_timedwait ((pthread_cond_t *) cond,
927                                    (pthread_mutex_t *) mutex,
928                                    &end_time);
929   return result == ETIMEDOUT;
930 }
931
932 static void
933 _dbus_internal_condvar_wake_one (DBusCondVar *cond)
934 {
935   pthread_cond_signal ((pthread_cond_t *)cond);
936 }
937
938 static void
939 _dbus_internal_condvar_wake_all (DBusCondVar *cond)
940 {
941   pthread_cond_broadcast ((pthread_cond_t *)cond);
942 }
943
944 #endif
945
946 static const DBusThreadFunctions internal_functions =
947 {
948   DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
949   DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
950   DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
951   DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
952   DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
953   DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
954   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
955   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
956   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
957   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
958   _dbus_internal_mutex_new,
959   _dbus_internal_mutex_free,
960   _dbus_internal_mutex_lock,
961   _dbus_internal_mutex_unlock,
962   _dbus_internal_condvar_new,
963   _dbus_internal_condvar_free,
964   _dbus_internal_condvar_wait,
965   _dbus_internal_condvar_wait_timeout,
966   _dbus_internal_condvar_wake_one,
967   _dbus_internal_condvar_wake_all
968 };
969
970 /**
971  * 
972  * Initializes threads. If this function is not called,
973  * the D-Bus library will not lock any data structures.
974  * If it is called, D-Bus will do locking, at some cost
975  * in efficiency. Note that this function must be called
976  * BEFORE the second thread is started.
977  *
978  * This function may be called more than once.  The first
979  * one wins.
980  *
981  * @returns #TRUE on success, #FALSE if no memory
982  */
983 dbus_bool_t
984 dbus_threads_init_default (void)
985 {
986 #ifdef USE_WIN32_THREADS
987   /* We reuse this over several generations, because we can't
988    * free the events once they are in use
989    */
990   if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
991     {
992       dbus_cond_event_tls = TlsAlloc ();
993       if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
994         return FALSE;
995     }
996 #endif
997   
998   return dbus_threads_init (&internal_functions);
999 }
1000
1001
1002 /** @} */
1003
1004 #ifdef DBUS_BUILD_TESTS
1005 /** Fake mutex used for debugging */
1006 typedef struct DBusFakeMutex DBusFakeMutex;
1007 /** Fake mutex used for debugging */
1008 struct DBusFakeMutex
1009 {
1010   dbus_bool_t locked; /**< Mutex is "locked" */
1011 };      
1012
1013 static DBusMutex *  dbus_fake_mutex_new            (void);
1014 static void         dbus_fake_mutex_free           (DBusMutex   *mutex);
1015 static dbus_bool_t  dbus_fake_mutex_lock           (DBusMutex   *mutex);
1016 static dbus_bool_t  dbus_fake_mutex_unlock         (DBusMutex   *mutex);
1017 static DBusCondVar* dbus_fake_condvar_new          (void);
1018 static void         dbus_fake_condvar_free         (DBusCondVar *cond);
1019 static void         dbus_fake_condvar_wait         (DBusCondVar *cond,
1020                                                     DBusMutex   *mutex);
1021 static dbus_bool_t  dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
1022                                                     DBusMutex   *mutex,
1023                                                     int          timeout_msec);
1024 static void         dbus_fake_condvar_wake_one     (DBusCondVar *cond);
1025 static void         dbus_fake_condvar_wake_all     (DBusCondVar *cond);
1026
1027
1028 static const DBusThreadFunctions fake_functions =
1029 {
1030   DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
1031   DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
1032   DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
1033   DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
1034   DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
1035   DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
1036   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
1037   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
1038   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
1039   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
1040   dbus_fake_mutex_new,
1041   dbus_fake_mutex_free,
1042   dbus_fake_mutex_lock,
1043   dbus_fake_mutex_unlock,
1044   dbus_fake_condvar_new,
1045   dbus_fake_condvar_free,
1046   dbus_fake_condvar_wait,
1047   dbus_fake_condvar_wait_timeout,
1048   dbus_fake_condvar_wake_one,
1049   dbus_fake_condvar_wake_all
1050 };
1051
1052 static DBusMutex *
1053 dbus_fake_mutex_new (void)
1054 {
1055   DBusFakeMutex *mutex;
1056
1057   mutex = dbus_new0 (DBusFakeMutex, 1);
1058
1059   return (DBusMutex *)mutex;
1060 }
1061
1062 static void
1063 dbus_fake_mutex_free (DBusMutex *mutex)
1064 {
1065   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
1066
1067   _dbus_assert (!fake->locked);
1068   
1069   dbus_free (fake);
1070 }
1071
1072 static dbus_bool_t
1073 dbus_fake_mutex_lock (DBusMutex *mutex)
1074 {
1075   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
1076
1077   _dbus_assert (!fake->locked);
1078
1079   fake->locked = TRUE;
1080   
1081   return TRUE;
1082 }
1083
1084 static dbus_bool_t
1085 dbus_fake_mutex_unlock (DBusMutex *mutex)
1086 {
1087   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
1088
1089   _dbus_assert (fake->locked);
1090
1091   fake->locked = FALSE;
1092   
1093   return TRUE;
1094 }
1095
1096 static DBusCondVar*
1097 dbus_fake_condvar_new (void)
1098 {
1099   return (DBusCondVar*) _dbus_strdup ("FakeCondvar");
1100 }
1101
1102 static void
1103 dbus_fake_condvar_free (DBusCondVar *cond)
1104 {
1105   dbus_free (cond);
1106 }
1107
1108 static void
1109 dbus_fake_condvar_wait (DBusCondVar *cond,
1110                         DBusMutex   *mutex)
1111 {
1112   
1113 }
1114
1115 static dbus_bool_t
1116 dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
1117                                 DBusMutex   *mutex,
1118                                 int         timeout_msec)
1119 {
1120   return TRUE;
1121 }
1122
1123 static void
1124 dbus_fake_condvar_wake_one (DBusCondVar *cond)
1125 {
1126
1127 }
1128
1129 static void
1130 dbus_fake_condvar_wake_all (DBusCondVar *cond)
1131 {
1132
1133 }
1134
1135 dbus_bool_t
1136 _dbus_threads_init_debug (void)
1137 {
1138   return dbus_threads_init (&fake_functions);
1139 }
1140
1141 #endif /* DBUS_BUILD_TESTS */