2005-02-24 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
27 static DBusThreadFunctions thread_functions =
28 {
29   0,
30   NULL, NULL, NULL, NULL,
31   NULL, NULL, NULL, NULL, NULL,
32
33   NULL, NULL, NULL, NULL,
34   NULL, NULL, NULL, NULL
35 };
36 static int thread_init_generation = 0;
37
38 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
39 #define _DBUS_DUMMY_MUTEX ((DBusMutex*)0xABCDEF)
40
41 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
42 #define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2)
43
44 /**
45  * @defgroup DBusThreadsInternals Thread functions
46  * @ingroup  DBusInternals
47  * @brief _dbus_mutex_lock(), etc.
48  *
49  * Functions and macros related to threads and thread locks.
50  *
51  * @{
52  */
53
54 /**
55  * Creates a new mutex using the function supplied to dbus_threads_init(),
56  * or creates a no-op mutex if threads are not initialized.
57  * May return #NULL even if threads are initialized, indicating
58  * out-of-memory.
59  *
60  * @returns new mutex or #NULL
61  */
62 DBusMutex*
63 _dbus_mutex_new (void)
64 {
65   if (thread_functions.mutex_new)
66     return (* thread_functions.mutex_new) ();
67   else
68     return _DBUS_DUMMY_MUTEX;
69 }
70
71 /**
72  * Frees a mutex created with dbus_mutex_new(); does
73  * nothing if passed a #NULL pointer.
74  */
75 void
76 _dbus_mutex_free (DBusMutex *mutex)
77 {
78   if (mutex && thread_functions.mutex_free)
79     (* thread_functions.mutex_free) (mutex);
80 }
81
82 /**
83  * Locks a mutex. Does nothing if passed a #NULL pointer.
84  * Locks are not recursive.
85  *
86  * @returns #TRUE on success
87  */
88 dbus_bool_t
89 _dbus_mutex_lock (DBusMutex *mutex)
90 {
91   if (mutex && thread_functions.mutex_lock)
92     return (* thread_functions.mutex_lock) (mutex);
93   else
94     return TRUE;
95 }
96
97 /**
98  * Unlocks a mutex. Does nothing if passed a #NULL pointer.
99  *
100  * @returns #TRUE on success
101  */
102 dbus_bool_t
103 _dbus_mutex_unlock (DBusMutex *mutex)
104 {
105   if (mutex && thread_functions.mutex_unlock)
106     return (* thread_functions.mutex_unlock) (mutex);
107   else
108     return TRUE;
109 }
110
111 /**
112  * Creates a new condition variable using the function supplied
113  * to dbus_threads_init(), or creates a no-op condition variable
114  * if threads are not initialized. May return #NULL even if
115  * threads are initialized, indicating out-of-memory.
116  *
117  * @returns new mutex or #NULL
118  */
119 DBusCondVar *
120 _dbus_condvar_new (void)
121 {
122   if (thread_functions.condvar_new)
123     return (* thread_functions.condvar_new) ();
124   else
125     return _DBUS_DUMMY_CONDVAR;
126 }
127
128 /**
129  * Frees a conditional variable created with dbus_condvar_new(); does
130  * nothing if passed a #NULL pointer.
131  */
132 void
133 _dbus_condvar_free (DBusCondVar *cond)
134 {
135   if (cond && thread_functions.condvar_free)
136     (* thread_functions.condvar_free) (cond);
137 }
138
139 /**
140  * Atomically unlocks the mutex and waits for the conditions
141  * variable to be signalled. Locks the mutex again before
142  * returning.
143  * Does nothing if passed a #NULL pointer.
144  */
145 void
146 _dbus_condvar_wait (DBusCondVar *cond,
147                     DBusMutex   *mutex)
148 {
149   if (cond && mutex && thread_functions.condvar_wait)
150     (* thread_functions.condvar_wait) (cond, mutex);
151 }
152
153 /**
154  * Atomically unlocks the mutex and waits for the conditions
155  * variable to be signalled, or for a timeout. Locks the
156  * mutex again before returning.
157  * Does nothing if passed a #NULL pointer.
158  *
159  * @param cond the condition variable
160  * @param mutex the mutex
161  * @param timeout_milliseconds the maximum time to wait
162  * @returns TRUE if the condition was reached, or FALSE if the
163  * timeout was reached.
164  */
165 dbus_bool_t
166 _dbus_condvar_wait_timeout (DBusCondVar               *cond,
167                             DBusMutex                 *mutex,
168                             int                        timeout_milliseconds)
169 {
170   if (cond && mutex && thread_functions.condvar_wait)
171     return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds);
172   else
173     return TRUE;
174 }
175
176 /**
177  * If there are threads waiting on the condition variable, wake
178  * up exactly one. 
179  * Does nothing if passed a #NULL pointer.
180  */
181 void
182 _dbus_condvar_wake_one (DBusCondVar *cond)
183 {
184   if (cond && thread_functions.condvar_wake_one)
185     (* thread_functions.condvar_wake_one) (cond);
186 }
187
188 /**
189  * If there are threads waiting on the condition variable, wake
190  * up all of them. 
191  * Does nothing if passed a #NULL pointer.
192  */
193 void
194 _dbus_condvar_wake_all (DBusCondVar *cond)
195 {
196   if (cond && thread_functions.condvar_wake_all)
197     (* thread_functions.condvar_wake_all) (cond);
198 }
199
200 static void
201 shutdown_global_locks (void *data)
202 {
203   DBusMutex ***locks = data;
204   int i;
205
206   i = 0;
207   while (i < _DBUS_N_GLOBAL_LOCKS)
208     {
209       _dbus_mutex_free (*(locks[i]));
210       *(locks[i]) = NULL;
211       ++i;
212     }
213   
214   dbus_free (locks);
215 }
216
217 static dbus_bool_t
218 init_global_locks (void)
219 {
220   int i;
221   DBusMutex ***dynamic_global_locks;
222   
223   DBusMutex **global_locks[] = {
224 #define LOCK_ADDR(name) (& _dbus_lock_##name)
225     LOCK_ADDR (list),
226     LOCK_ADDR (connection_slots),
227     LOCK_ADDR (pending_call_slots),
228     LOCK_ADDR (server_slots),
229     LOCK_ADDR (message_slots),
230     LOCK_ADDR (atomic),
231     LOCK_ADDR (bus),
232     LOCK_ADDR (shutdown_funcs),
233     LOCK_ADDR (system_users),
234     LOCK_ADDR (message_cache)
235 #undef LOCK_ADDR
236   };
237
238   _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
239                 _DBUS_N_GLOBAL_LOCKS);
240
241   i = 0;
242   
243   dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
244   if (dynamic_global_locks == NULL)
245     goto failed;
246   
247   while (i < _DBUS_N_ELEMENTS (global_locks))
248     {
249       *global_locks[i] = _dbus_mutex_new ();
250       
251       if (*global_locks[i] == NULL)
252         goto failed;
253
254       dynamic_global_locks[i] = global_locks[i];
255
256       ++i;
257     }
258   
259   if (!_dbus_register_shutdown_func (shutdown_global_locks,
260                                      dynamic_global_locks))
261     goto failed;
262   
263   return TRUE;
264
265  failed:
266   dbus_free (dynamic_global_locks);
267                                      
268   for (i = i - 1; i >= 0; i--)
269     {
270       _dbus_mutex_free (*global_locks[i]);
271       *global_locks[i] = NULL;
272     }
273   return FALSE;
274 }
275
276 /** @} */ /* end of internals */
277
278 /**
279  * @defgroup DBusThreads Thread functions
280  * @ingroup  DBus
281  * @brief dbus_threads_init()
282  *
283  * Functions and macros related to threads and thread locks.
284  *
285  * @{
286  */
287
288 /**
289  * 
290  * Initializes threads. If this function is not called,
291  * the D-BUS library will not lock any data structures.
292  * If it is called, D-BUS will do locking, at some cost
293  * in efficiency. Note that this function must be called
294  * BEFORE using any other D-BUS functions.
295  *
296  * This function may be called more than once, as long
297  * as you pass in the same functions each time. If it's
298  * called multiple times with different functions, then
299  * a warning is printed, because someone is confused.
300  *
301  * @param functions functions for using threads
302  * @returns #TRUE on success, #FALSE if no memory
303  */
304 dbus_bool_t
305 dbus_threads_init (const DBusThreadFunctions *functions)
306 {
307   _dbus_assert (functions != NULL);
308
309   /* these base functions are required. Future additions to
310    * DBusThreadFunctions may be optional.
311    */
312   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK);
313   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK);
314   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK);
315   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK);
316   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK);
317   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK);
318   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK);
319   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK);
320   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK);
321   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK);
322   _dbus_assert (functions->mutex_new != NULL);
323   _dbus_assert (functions->mutex_free != NULL);
324   _dbus_assert (functions->mutex_lock != NULL);
325   _dbus_assert (functions->mutex_unlock != NULL);
326   _dbus_assert (functions->condvar_new != NULL);
327   _dbus_assert (functions->condvar_free != NULL);
328   _dbus_assert (functions->condvar_wait != NULL);
329   _dbus_assert (functions->condvar_wait_timeout != NULL);
330   _dbus_assert (functions->condvar_wake_one != NULL);
331   _dbus_assert (functions->condvar_wake_all != NULL);
332
333   /* Check that all bits in the mask actually are valid mask bits.
334    * ensures people won't write code that breaks when we add
335    * new bits.
336    */
337   _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
338
339   if (thread_init_generation != _dbus_current_generation)
340     thread_functions.mask = 0; /* allow re-init in new generation */
341   
342   if (thread_functions.mask != 0)
343     {
344       /* Silently allow multiple init if the functions are the same ones.
345        * Well, we only bother checking two of them, just out of laziness.
346        */
347       if (thread_functions.mask == functions->mask &&
348           thread_functions.mutex_new == functions->mutex_new &&
349           thread_functions.condvar_new == functions->condvar_new)
350         {
351           return TRUE;
352         }
353       else
354         {
355           _dbus_warn ("dbus_threads_init() called twice with two different sets of functions\n");
356           return FALSE;
357         }
358     }
359   
360   thread_functions.mutex_new = functions->mutex_new;
361   thread_functions.mutex_free = functions->mutex_free;
362   thread_functions.mutex_lock = functions->mutex_lock;
363   thread_functions.mutex_unlock = functions->mutex_unlock;
364   
365   thread_functions.condvar_new = functions->condvar_new;
366   thread_functions.condvar_free = functions->condvar_free;
367   thread_functions.condvar_wait = functions->condvar_wait;
368   thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
369   thread_functions.condvar_wake_one = functions->condvar_wake_one;
370   thread_functions.condvar_wake_all = functions->condvar_wake_all;
371   
372   thread_functions.mask = functions->mask;
373
374   if (!init_global_locks ())
375     return FALSE;
376
377   thread_init_generation = _dbus_current_generation;
378   
379   return TRUE;
380 }
381
382 /** @} */
383
384 #ifdef DBUS_BUILD_TESTS
385 /** Fake mutex used for debugging */
386 typedef struct DBusFakeMutex DBusFakeMutex;
387 /** Fake mutex used for debugging */
388 struct DBusFakeMutex
389 {
390   dbus_bool_t locked; /**< Mutex is "locked" */
391 };      
392
393 static DBusMutex *  dbus_fake_mutex_new            (void);
394 static void         dbus_fake_mutex_free           (DBusMutex   *mutex);
395 static dbus_bool_t  dbus_fake_mutex_lock           (DBusMutex   *mutex);
396 static dbus_bool_t  dbus_fake_mutex_unlock         (DBusMutex   *mutex);
397 static DBusCondVar* dbus_fake_condvar_new          (void);
398 static void         dbus_fake_condvar_free         (DBusCondVar *cond);
399 static void         dbus_fake_condvar_wait         (DBusCondVar *cond,
400                                                     DBusMutex   *mutex);
401 static dbus_bool_t  dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
402                                                     DBusMutex   *mutex,
403                                                     int          timeout_msec);
404 static void         dbus_fake_condvar_wake_one     (DBusCondVar *cond);
405 static void         dbus_fake_condvar_wake_all     (DBusCondVar *cond);
406
407
408 static const DBusThreadFunctions fake_functions =
409 {
410   DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
411   DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
412   DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
413   DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
414   DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
415   DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
416   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
417   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
418   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
419   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
420   dbus_fake_mutex_new,
421   dbus_fake_mutex_free,
422   dbus_fake_mutex_lock,
423   dbus_fake_mutex_unlock,
424   dbus_fake_condvar_new,
425   dbus_fake_condvar_free,
426   dbus_fake_condvar_wait,
427   dbus_fake_condvar_wait_timeout,
428   dbus_fake_condvar_wake_one,
429   dbus_fake_condvar_wake_all
430 };
431
432 static DBusMutex *
433 dbus_fake_mutex_new (void)
434 {
435   DBusFakeMutex *mutex;
436
437   mutex = dbus_new0 (DBusFakeMutex, 1);
438
439   return (DBusMutex *)mutex;
440 }
441
442 static void
443 dbus_fake_mutex_free (DBusMutex *mutex)
444 {
445   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
446
447   _dbus_assert (!fake->locked);
448   
449   dbus_free (fake);
450 }
451
452 static dbus_bool_t
453 dbus_fake_mutex_lock (DBusMutex *mutex)
454 {
455   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
456
457   _dbus_assert (!fake->locked);
458
459   fake->locked = TRUE;
460   
461   return TRUE;
462 }
463
464 static dbus_bool_t
465 dbus_fake_mutex_unlock (DBusMutex *mutex)
466 {
467   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
468
469   _dbus_assert (fake->locked);
470
471   fake->locked = FALSE;
472   
473   return TRUE;
474 }
475
476 static DBusCondVar*
477 dbus_fake_condvar_new (void)
478 {
479   return (DBusCondVar*) _dbus_strdup ("FakeCondvar");
480 }
481
482 static void
483 dbus_fake_condvar_free (DBusCondVar *cond)
484 {
485   dbus_free (cond);
486 }
487
488 static void
489 dbus_fake_condvar_wait (DBusCondVar *cond,
490                         DBusMutex   *mutex)
491 {
492   
493 }
494
495 static dbus_bool_t
496 dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
497                                 DBusMutex   *mutex,
498                                 int         timeout_msec)
499 {
500   return TRUE;
501 }
502
503 static void
504 dbus_fake_condvar_wake_one (DBusCondVar *cond)
505 {
506
507 }
508
509 static void
510 dbus_fake_condvar_wake_all (DBusCondVar *cond)
511 {
512
513 }
514
515 dbus_bool_t
516 _dbus_threads_init_debug (void)
517 {
518   return dbus_threads_init (&fake_functions);
519 }
520
521 #endif /* DBUS_BUILD_TESTS */