1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-threads.h D-Bus threads handling
4 * Copyright (C) 2002, 2003 Red Hat Inc.
6 * Licensed under the Academic Free License version 2.1
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.
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.
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
23 #include "dbus-threads.h"
24 #include "dbus-internals.h"
25 #include "dbus-threads-internal.h"
27 static DBusThreadFunctions thread_functions =
30 NULL, NULL, NULL, NULL,
31 NULL, NULL, NULL, NULL, NULL,
33 NULL, NULL, NULL, NULL,
34 NULL, NULL, NULL, NULL
36 static int thread_init_generation = 0;
38 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
39 #define _DBUS_DUMMY_MUTEX ((DBusMutex*)0xABCDEF)
41 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
42 #define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2)
45 * @defgroup DBusThreadsInternals Thread functions
46 * @ingroup DBusInternals
47 * @brief _dbus_mutex_lock(), etc.
49 * Functions and macros related to threads and thread locks.
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
60 * @returns new mutex or #NULL
63 _dbus_mutex_new (void)
65 if (thread_functions.mutex_new)
66 return (* thread_functions.mutex_new) ();
68 return _DBUS_DUMMY_MUTEX;
72 * Frees a mutex created with dbus_mutex_new(); does
73 * nothing if passed a #NULL pointer.
76 _dbus_mutex_free (DBusMutex *mutex)
78 if (mutex && thread_functions.mutex_free)
79 (* thread_functions.mutex_free) (mutex);
83 * Locks a mutex. Does nothing if passed a #NULL pointer.
84 * Locks are not recursive.
86 * @returns #TRUE on success
89 _dbus_mutex_lock (DBusMutex *mutex)
91 if (mutex && thread_functions.mutex_lock)
92 return (* thread_functions.mutex_lock) (mutex);
98 * Unlocks a mutex. Does nothing if passed a #NULL pointer.
100 * @returns #TRUE on success
103 _dbus_mutex_unlock (DBusMutex *mutex)
105 if (mutex && thread_functions.mutex_unlock)
106 return (* thread_functions.mutex_unlock) (mutex);
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.
117 * @returns new mutex or #NULL
120 _dbus_condvar_new (void)
122 if (thread_functions.condvar_new)
123 return (* thread_functions.condvar_new) ();
125 return _DBUS_DUMMY_CONDVAR;
129 * Frees a conditional variable created with dbus_condvar_new(); does
130 * nothing if passed a #NULL pointer.
133 _dbus_condvar_free (DBusCondVar *cond)
135 if (cond && thread_functions.condvar_free)
136 (* thread_functions.condvar_free) (cond);
140 * Atomically unlocks the mutex and waits for the conditions
141 * variable to be signalled. Locks the mutex again before
143 * Does nothing if passed a #NULL pointer.
146 _dbus_condvar_wait (DBusCondVar *cond,
149 if (cond && mutex && thread_functions.condvar_wait)
150 (* thread_functions.condvar_wait) (cond, mutex);
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.
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.
166 _dbus_condvar_wait_timeout (DBusCondVar *cond,
168 int timeout_milliseconds)
170 if (cond && mutex && thread_functions.condvar_wait)
171 return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds);
177 * If there are threads waiting on the condition variable, wake
179 * Does nothing if passed a #NULL pointer.
182 _dbus_condvar_wake_one (DBusCondVar *cond)
184 if (cond && thread_functions.condvar_wake_one)
185 (* thread_functions.condvar_wake_one) (cond);
189 * If there are threads waiting on the condition variable, wake
191 * Does nothing if passed a #NULL pointer.
194 _dbus_condvar_wake_all (DBusCondVar *cond)
196 if (cond && thread_functions.condvar_wake_all)
197 (* thread_functions.condvar_wake_all) (cond);
201 shutdown_global_locks (void *data)
203 DBusMutex ***locks = data;
207 while (i < _DBUS_N_GLOBAL_LOCKS)
209 _dbus_mutex_free (*(locks[i]));
218 init_global_locks (void)
221 DBusMutex ***dynamic_global_locks;
223 DBusMutex **global_locks[] = {
224 #define LOCK_ADDR(name) (& _dbus_lock_##name)
226 LOCK_ADDR (connection_slots),
227 LOCK_ADDR (pending_call_slots),
228 LOCK_ADDR (server_slots),
229 LOCK_ADDR (message_slots),
232 LOCK_ADDR (shutdown_funcs),
233 LOCK_ADDR (system_users),
234 LOCK_ADDR (message_cache),
235 LOCK_ADDR (shared_connections)
239 _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
240 _DBUS_N_GLOBAL_LOCKS);
244 dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
245 if (dynamic_global_locks == NULL)
248 while (i < _DBUS_N_ELEMENTS (global_locks))
250 *global_locks[i] = _dbus_mutex_new ();
252 if (*global_locks[i] == NULL)
255 dynamic_global_locks[i] = global_locks[i];
260 if (!_dbus_register_shutdown_func (shutdown_global_locks,
261 dynamic_global_locks))
267 dbus_free (dynamic_global_locks);
269 for (i = i - 1; i >= 0; i--)
271 _dbus_mutex_free (*global_locks[i]);
272 *global_locks[i] = NULL;
277 /** @} */ /* end of internals */
280 * @defgroup DBusThreads Thread functions
282 * @brief dbus_threads_init()
284 * Functions and macros related to threads and thread locks.
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.
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.
302 * @param functions functions for using threads
303 * @returns #TRUE on success, #FALSE if no memory
306 dbus_threads_init (const DBusThreadFunctions *functions)
308 _dbus_assert (functions != NULL);
310 /* these base functions are required. Future additions to
311 * DBusThreadFunctions may be optional.
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);
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
338 _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
340 if (thread_init_generation != _dbus_current_generation)
341 thread_functions.mask = 0; /* allow re-init in new generation */
343 if (thread_functions.mask != 0)
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.
348 if (thread_functions.mask == functions->mask &&
349 thread_functions.mutex_new == functions->mutex_new &&
350 thread_functions.condvar_new == functions->condvar_new)
356 _dbus_warn ("dbus_threads_init() called twice with two different sets of functions\n");
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;
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;
373 thread_functions.mask = functions->mask;
375 if (!init_global_locks ())
378 thread_init_generation = _dbus_current_generation;
385 #ifdef DBUS_BUILD_TESTS
386 /** Fake mutex used for debugging */
387 typedef struct DBusFakeMutex DBusFakeMutex;
388 /** Fake mutex used for debugging */
391 dbus_bool_t locked; /**< Mutex is "locked" */
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,
402 static dbus_bool_t dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
405 static void dbus_fake_condvar_wake_one (DBusCondVar *cond);
406 static void dbus_fake_condvar_wake_all (DBusCondVar *cond);
409 static const DBusThreadFunctions fake_functions =
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,
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
434 dbus_fake_mutex_new (void)
436 DBusFakeMutex *mutex;
438 mutex = dbus_new0 (DBusFakeMutex, 1);
440 return (DBusMutex *)mutex;
444 dbus_fake_mutex_free (DBusMutex *mutex)
446 DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
448 _dbus_assert (!fake->locked);
454 dbus_fake_mutex_lock (DBusMutex *mutex)
456 DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
458 _dbus_assert (!fake->locked);
466 dbus_fake_mutex_unlock (DBusMutex *mutex)
468 DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
470 _dbus_assert (fake->locked);
472 fake->locked = FALSE;
478 dbus_fake_condvar_new (void)
480 return (DBusCondVar*) _dbus_strdup ("FakeCondvar");
484 dbus_fake_condvar_free (DBusCondVar *cond)
490 dbus_fake_condvar_wait (DBusCondVar *cond,
497 dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
505 dbus_fake_condvar_wake_one (DBusCondVar *cond)
511 dbus_fake_condvar_wake_all (DBusCondVar *cond)
517 _dbus_threads_init_debug (void)
519 return dbus_threads_init (&fake_functions);
522 #endif /* DBUS_BUILD_TESTS */