1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-threads.h D-BUS threads handling
4 * Copyright (C) 2002 Red Hat Inc.
6 * Licensed under the Academic Free License version 1.2
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"
26 static DBusThreadFunctions thread_functions =
29 NULL, NULL, NULL, NULL,
30 NULL, NULL, NULL, NULL, NULL,
32 NULL, NULL, NULL, NULL,
33 NULL, NULL, NULL, NULL
35 static int thread_init_generation = 0;
37 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
38 #ifdef DBUS_BUILD_TESTS
39 #define _DBUS_DUMMY_MUTEX_NEW ((DBusMutex*)_dbus_strdup ("FakeMutex"))
41 #define _DBUS_DUMMY_MUTEX_NEW ((DBusMutex*)0xABCDEF)
44 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
45 #ifdef DBUS_BUILD_TESTS
46 #define _DBUS_DUMMY_CONDVAR_NEW ((DBusCondVar*)_dbus_strdup ("FakeCondvar"))
48 #define _DBUS_DUMMY_CONDVAR_NEW ((DBusCondVar*)0xABCDEF2)
52 * @defgroup DBusThreads Thread functions
54 * @brief dbus_threads_init(), dbus_mutex_lock(), etc.
56 * Functions and macros related to threads and thread locks.
62 * Creates a new mutex using the function supplied to dbus_threads_init(),
63 * or creates a no-op mutex if threads are not initialized.
64 * May return #NULL even if threads are initialized, indicating
67 * @returns new mutex or #NULL
72 if (thread_functions.mutex_new)
73 return (* thread_functions.mutex_new) ();
75 return _DBUS_DUMMY_MUTEX_NEW;
79 * Frees a mutex created with dbus_mutex_new(); does
80 * nothing if passed a #NULL pointer.
83 dbus_mutex_free (DBusMutex *mutex)
85 if (mutex && thread_functions.mutex_free)
86 (* thread_functions.mutex_free) (mutex);
87 #ifdef DBUS_BUILD_TESTS
88 /* Free the fake mutex */
95 * Locks a mutex. Does nothing if passed a #NULL pointer.
96 * Locks are not recursive.
98 * @returns #TRUE on success
101 dbus_mutex_lock (DBusMutex *mutex)
103 if (mutex && thread_functions.mutex_lock)
104 return (* thread_functions.mutex_lock) (mutex);
110 * Unlocks a mutex. Does nothing if passed a #NULL pointer.
112 * @returns #TRUE on success
115 dbus_mutex_unlock (DBusMutex *mutex)
117 if (mutex && thread_functions.mutex_unlock)
118 return (* thread_functions.mutex_unlock) (mutex);
124 * Creates a new condition variable using the function supplied
125 * to dbus_threads_init(), or creates a no-op condition variable
126 * if threads are not initialized. May return #NULL even if
127 * threads are initialized, indicating out-of-memory.
129 * @returns new mutex or #NULL
132 dbus_condvar_new (void)
134 if (thread_functions.condvar_new)
135 return (* thread_functions.condvar_new) ();
137 return _DBUS_DUMMY_CONDVAR_NEW;
141 * Frees a conditional variable created with dbus_condvar_new(); does
142 * nothing if passed a #NULL pointer.
145 dbus_condvar_free (DBusCondVar *cond)
147 if (cond && thread_functions.condvar_free)
148 (* thread_functions.condvar_free) (cond);
149 #ifdef DBUS_BUILD_TESTS
151 /* Free the fake condvar */
157 * Atomically unlocks the mutex and waits for the conditions
158 * variable to be signalled. Locks the mutex again before
160 * Does nothing if passed a #NULL pointer.
163 dbus_condvar_wait (DBusCondVar *cond,
166 if (cond && mutex && thread_functions.condvar_wait)
167 (* thread_functions.condvar_wait) (cond, mutex);
171 * Atomically unlocks the mutex and waits for the conditions
172 * variable to be signalled, or for a timeout. Locks the
173 * mutex again before returning.
174 * Does nothing if passed a #NULL pointer.
176 * @param cond the condition variable
177 * @param mutex the mutex
178 * @param timeout_milliseconds the maximum time to wait
179 * @returns TRUE if the condition was reached, or FALSE if the
180 * timeout was reached.
183 dbus_condvar_wait_timeout (DBusCondVar *cond,
185 int timeout_milliseconds)
187 if (cond && mutex && thread_functions.condvar_wait)
188 return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds);
194 * If there are threads waiting on the condition variable, wake
196 * Does nothing if passed a #NULL pointer.
199 dbus_condvar_wake_one (DBusCondVar *cond)
201 if (cond && thread_functions.condvar_wake_one)
202 (* thread_functions.condvar_wake_one) (cond);
206 * If there are threads waiting on the condition variable, wake
208 * Does nothing if passed a #NULL pointer.
211 dbus_condvar_wake_all (DBusCondVar *cond)
213 if (cond && thread_functions.condvar_wake_all)
214 (* thread_functions.condvar_wake_all) (cond);
218 shutdown_global_locks (void *data)
220 DBusMutex ***locks = data;
224 while (i < _DBUS_N_GLOBAL_LOCKS)
226 dbus_mutex_free (*(locks[i]));
235 init_global_locks (void)
238 DBusMutex ***dynamic_global_locks;
240 DBusMutex **global_locks[] = {
241 #define LOCK_ADDR(name) (& _dbus_lock_##name)
243 LOCK_ADDR (connection_slots),
244 LOCK_ADDR (server_slots),
246 LOCK_ADDR (message_handler),
247 LOCK_ADDR (user_info),
252 _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
253 _DBUS_N_GLOBAL_LOCKS);
257 dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
258 if (dynamic_global_locks == NULL)
261 while (i < _DBUS_N_ELEMENTS (global_locks))
263 *global_locks[i] = dbus_mutex_new ();
265 if (*global_locks[i] == NULL)
268 dynamic_global_locks[i] = global_locks[i];
273 if (!_dbus_register_shutdown_func (shutdown_global_locks,
274 dynamic_global_locks))
280 dbus_free (dynamic_global_locks);
282 for (i = i - 1; i >= 0; i--)
284 dbus_mutex_free (*global_locks[i]);
285 *global_locks[i] = NULL;
292 * Initializes threads. If this function is not called,
293 * the D-BUS library will not lock any data structures.
294 * If it is called, D-BUS will do locking, at some cost
295 * in efficiency. Note that this function must be called
296 * BEFORE using any other D-BUS functions.
298 * @todo right now this function can only be called once,
299 * maybe we should instead silently ignore multiple calls.
301 * @param functions functions for using threads
302 * @returns #TRUE on success, #FALSE if no memory
305 dbus_threads_init (const DBusThreadFunctions *functions)
307 _dbus_assert (functions != NULL);
309 /* these base functions are required. Future additions to
310 * DBusThreadFunctions may be optional.
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);
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
337 _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
339 if (thread_init_generation != _dbus_current_generation)
340 thread_functions.mask = 0; /* allow re-init in new generation */
342 if (thread_functions.mask != 0)
344 _dbus_warn ("dbus_threads_init() may only be called one time\n");
348 thread_functions.mutex_new = functions->mutex_new;
349 thread_functions.mutex_free = functions->mutex_free;
350 thread_functions.mutex_lock = functions->mutex_lock;
351 thread_functions.mutex_unlock = functions->mutex_unlock;
353 thread_functions.condvar_new = functions->condvar_new;
354 thread_functions.condvar_free = functions->condvar_free;
355 thread_functions.condvar_wait = functions->condvar_wait;
356 thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
357 thread_functions.condvar_wake_one = functions->condvar_wake_one;
358 thread_functions.condvar_wake_all = functions->condvar_wake_all;
360 thread_functions.mask = functions->mask;
362 if (!init_global_locks ())
365 thread_init_generation = _dbus_current_generation;