* s/D-BUS/D-Bus/g
[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     LOCK_ADDR (shared_connections)
236 #undef LOCK_ADDR
237   };
238
239   _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
240                 _DBUS_N_GLOBAL_LOCKS);
241
242   i = 0;
243   
244   dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
245   if (dynamic_global_locks == NULL)
246     goto failed;
247   
248   while (i < _DBUS_N_ELEMENTS (global_locks))
249     {
250       *global_locks[i] = _dbus_mutex_new ();
251       
252       if (*global_locks[i] == NULL)
253         goto failed;
254
255       dynamic_global_locks[i] = global_locks[i];
256
257       ++i;
258     }
259   
260   if (!_dbus_register_shutdown_func (shutdown_global_locks,
261                                      dynamic_global_locks))
262     goto failed;
263   
264   return TRUE;
265
266  failed:
267   dbus_free (dynamic_global_locks);
268                                      
269   for (i = i - 1; i >= 0; i--)
270     {
271       _dbus_mutex_free (*global_locks[i]);
272       *global_locks[i] = NULL;
273     }
274   return FALSE;
275 }
276
277 /** @} */ /* end of internals */
278
279 /**
280  * @defgroup DBusThreads Thread functions
281  * @ingroup  DBus
282  * @brief dbus_threads_init()
283  *
284  * Functions and macros related to threads and thread locks.
285  *
286  * @{
287  */
288
289 /**
290  * 
291  * Initializes threads. If this function is not called,
292  * the D-Bus library will not lock any data structures.
293  * If it is called, D-Bus will do locking, at some cost
294  * in efficiency. Note that this function must be called
295  * BEFORE using any other D-Bus functions.
296  *
297  * This function may be called more than once, as long
298  * as you pass in the same functions each time. If it's
299  * called multiple times with different functions, then
300  * a warning is printed, because someone is confused.
301  *
302  * @param functions functions for using threads
303  * @returns #TRUE on success, #FALSE if no memory
304  */
305 dbus_bool_t
306 dbus_threads_init (const DBusThreadFunctions *functions)
307 {
308   _dbus_assert (functions != NULL);
309
310   /* these base functions are required. Future additions to
311    * DBusThreadFunctions may be optional.
312    */
313   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK);
314   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK);
315   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK);
316   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK);
317   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK);
318   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK);
319   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK);
320   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK);
321   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK);
322   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK);
323   _dbus_assert (functions->mutex_new != NULL);
324   _dbus_assert (functions->mutex_free != NULL);
325   _dbus_assert (functions->mutex_lock != NULL);
326   _dbus_assert (functions->mutex_unlock != NULL);
327   _dbus_assert (functions->condvar_new != NULL);
328   _dbus_assert (functions->condvar_free != NULL);
329   _dbus_assert (functions->condvar_wait != NULL);
330   _dbus_assert (functions->condvar_wait_timeout != NULL);
331   _dbus_assert (functions->condvar_wake_one != NULL);
332   _dbus_assert (functions->condvar_wake_all != NULL);
333
334   /* Check that all bits in the mask actually are valid mask bits.
335    * ensures people won't write code that breaks when we add
336    * new bits.
337    */
338   _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
339
340   if (thread_init_generation != _dbus_current_generation)
341     thread_functions.mask = 0; /* allow re-init in new generation */
342   
343   if (thread_functions.mask != 0)
344     {
345       /* Silently allow multiple init if the functions are the same ones.
346        * Well, we only bother checking two of them, just out of laziness.
347        */
348       if (thread_functions.mask == functions->mask &&
349           thread_functions.mutex_new == functions->mutex_new &&
350           thread_functions.condvar_new == functions->condvar_new)
351         {
352           return TRUE;
353         }
354       else
355         {
356           _dbus_warn ("dbus_threads_init() called twice with two different sets of functions\n");
357           return FALSE;
358         }
359     }
360   
361   thread_functions.mutex_new = functions->mutex_new;
362   thread_functions.mutex_free = functions->mutex_free;
363   thread_functions.mutex_lock = functions->mutex_lock;
364   thread_functions.mutex_unlock = functions->mutex_unlock;
365   
366   thread_functions.condvar_new = functions->condvar_new;
367   thread_functions.condvar_free = functions->condvar_free;
368   thread_functions.condvar_wait = functions->condvar_wait;
369   thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
370   thread_functions.condvar_wake_one = functions->condvar_wake_one;
371   thread_functions.condvar_wake_all = functions->condvar_wake_all;
372   
373   thread_functions.mask = functions->mask;
374
375   if (!init_global_locks ())
376     return FALSE;
377
378   thread_init_generation = _dbus_current_generation;
379   
380   return TRUE;
381 }
382
383 /** @} */
384
385 #ifdef DBUS_BUILD_TESTS
386 /** Fake mutex used for debugging */
387 typedef struct DBusFakeMutex DBusFakeMutex;
388 /** Fake mutex used for debugging */
389 struct DBusFakeMutex
390 {
391   dbus_bool_t locked; /**< Mutex is "locked" */
392 };      
393
394 static DBusMutex *  dbus_fake_mutex_new            (void);
395 static void         dbus_fake_mutex_free           (DBusMutex   *mutex);
396 static dbus_bool_t  dbus_fake_mutex_lock           (DBusMutex   *mutex);
397 static dbus_bool_t  dbus_fake_mutex_unlock         (DBusMutex   *mutex);
398 static DBusCondVar* dbus_fake_condvar_new          (void);
399 static void         dbus_fake_condvar_free         (DBusCondVar *cond);
400 static void         dbus_fake_condvar_wait         (DBusCondVar *cond,
401                                                     DBusMutex   *mutex);
402 static dbus_bool_t  dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
403                                                     DBusMutex   *mutex,
404                                                     int          timeout_msec);
405 static void         dbus_fake_condvar_wake_one     (DBusCondVar *cond);
406 static void         dbus_fake_condvar_wake_all     (DBusCondVar *cond);
407
408
409 static const DBusThreadFunctions fake_functions =
410 {
411   DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
412   DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
413   DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
414   DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
415   DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
416   DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
417   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
418   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
419   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
420   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
421   dbus_fake_mutex_new,
422   dbus_fake_mutex_free,
423   dbus_fake_mutex_lock,
424   dbus_fake_mutex_unlock,
425   dbus_fake_condvar_new,
426   dbus_fake_condvar_free,
427   dbus_fake_condvar_wait,
428   dbus_fake_condvar_wait_timeout,
429   dbus_fake_condvar_wake_one,
430   dbus_fake_condvar_wake_all
431 };
432
433 static DBusMutex *
434 dbus_fake_mutex_new (void)
435 {
436   DBusFakeMutex *mutex;
437
438   mutex = dbus_new0 (DBusFakeMutex, 1);
439
440   return (DBusMutex *)mutex;
441 }
442
443 static void
444 dbus_fake_mutex_free (DBusMutex *mutex)
445 {
446   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
447
448   _dbus_assert (!fake->locked);
449   
450   dbus_free (fake);
451 }
452
453 static dbus_bool_t
454 dbus_fake_mutex_lock (DBusMutex *mutex)
455 {
456   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
457
458   _dbus_assert (!fake->locked);
459
460   fake->locked = TRUE;
461   
462   return TRUE;
463 }
464
465 static dbus_bool_t
466 dbus_fake_mutex_unlock (DBusMutex *mutex)
467 {
468   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
469
470   _dbus_assert (fake->locked);
471
472   fake->locked = FALSE;
473   
474   return TRUE;
475 }
476
477 static DBusCondVar*
478 dbus_fake_condvar_new (void)
479 {
480   return (DBusCondVar*) _dbus_strdup ("FakeCondvar");
481 }
482
483 static void
484 dbus_fake_condvar_free (DBusCondVar *cond)
485 {
486   dbus_free (cond);
487 }
488
489 static void
490 dbus_fake_condvar_wait (DBusCondVar *cond,
491                         DBusMutex   *mutex)
492 {
493   
494 }
495
496 static dbus_bool_t
497 dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
498                                 DBusMutex   *mutex,
499                                 int         timeout_msec)
500 {
501   return TRUE;
502 }
503
504 static void
505 dbus_fake_condvar_wake_one (DBusCondVar *cond)
506 {
507
508 }
509
510 static void
511 dbus_fake_condvar_wake_all (DBusCondVar *cond)
512 {
513
514 }
515
516 dbus_bool_t
517 _dbus_threads_init_debug (void)
518 {
519   return dbus_threads_init (&fake_functions);
520 }
521
522 #endif /* DBUS_BUILD_TESTS */