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
36 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
37 #define _DBUS_DUMMY_MUTEX ((void*)0xABCDEF)
39 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
40 #define _DBUS_DUMMY_CONDVAR ((void*)0xABCDEF2)
43 * @defgroup DBusThreads Thread functions
45 * @brief dbus_threads_init(), dbus_mutex_lock(), etc.
47 * Functions and macros related to threads and thread locks.
53 * Creates a new mutex using the function supplied to dbus_threads_init(),
54 * or creates a no-op mutex if threads are not initialized.
55 * May return #NULL even if threads are initialized, indicating
58 * @returns new mutex or #NULL
63 if (thread_functions.mutex_new)
64 return (* thread_functions.mutex_new) ();
66 return _DBUS_DUMMY_MUTEX;
70 * Frees a mutex created with dbus_mutex_new(); does
71 * nothing if passed a #NULL pointer.
74 dbus_mutex_free (DBusMutex *mutex)
76 if (mutex && thread_functions.mutex_free)
77 (* thread_functions.mutex_free) (mutex);
81 * Locks a mutex. Does nothing if passed a #NULL pointer.
82 * Locks are not recursive.
84 * @returns #TRUE on success
87 dbus_mutex_lock (DBusMutex *mutex)
89 if (mutex && thread_functions.mutex_lock)
90 return (* thread_functions.mutex_lock) (mutex);
96 * Unlocks a mutex. Does nothing if passed a #NULL pointer.
98 * @returns #TRUE on success
101 dbus_mutex_unlock (DBusMutex *mutex)
103 if (mutex && thread_functions.mutex_unlock)
104 return (* thread_functions.mutex_unlock) (mutex);
110 * Creates a new condition variable using the function supplied
111 * to dbus_threads_init(), or creates a no-op condition variable
112 * if threads are not initialized. May return #NULL even if
113 * threads are initialized, indicating out-of-memory.
115 * @returns new mutex or #NULL
118 dbus_condvar_new (void)
120 if (thread_functions.condvar_new)
121 return (* thread_functions.condvar_new) ();
123 return _DBUS_DUMMY_MUTEX;
127 * Frees a conditional variable created with dbus_condvar_new(); does
128 * nothing if passed a #NULL pointer.
131 dbus_condvar_free (DBusCondVar *cond)
133 if (cond && thread_functions.condvar_free)
134 (* thread_functions.condvar_free) (cond);
138 * Atomically unlocks the mutex and waits for the conditions
139 * variable to be signalled. Locks the mutex again before
141 * Does nothing if passed a #NULL pointer.
144 dbus_condvar_wait (DBusCondVar *cond,
147 if (cond && mutex && thread_functions.condvar_wait)
148 (* thread_functions.condvar_wait) (cond, mutex);
152 * Atomically unlocks the mutex and waits for the conditions
153 * variable to be signalled, or for a timeout. Locks the
154 * mutex again before returning.
155 * Does nothing if passed a #NULL pointer.
157 * @param timeout_milliseconds the maximum time to wait
158 * @returns TRUE if the condition was reached, or FALSE if the
159 * timeout was reached.
162 dbus_condvar_wait_timeout (DBusCondVar *cond,
164 int timeout_milliseconds)
166 if (cond && mutex && thread_functions.condvar_wait)
167 return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds);
173 * If there are threads waiting on the condition variable, wake
175 * Does nothing if passed a #NULL pointer.
178 dbus_condvar_wake_one (DBusCondVar *cond)
180 if (cond && thread_functions.condvar_wake_one)
181 (* thread_functions.condvar_wake_one) (cond);
185 * If there are threads waiting on the condition variable, wake
187 * Does nothing if passed a #NULL pointer.
190 dbus_condvar_wake_all (DBusCondVar *cond)
192 if (cond && thread_functions.condvar_wake_all)
193 (* thread_functions.condvar_wake_all) (cond);
197 DBusMutex * _dbus_list_init_lock (void);
198 DBusMutex * _dbus_allocated_slots_init_lock (void);
199 DBusMutex *_dbus_atomic_init_lock (void);
200 DBusMutex *_dbus_message_handler_init_lock (void);
203 init_static_locks(void)
208 DBusMutex *(*init_func)(void);
211 {&_dbus_list_init_lock},
212 {&_dbus_allocated_slots_init_lock},
213 {&_dbus_atomic_init_lock},
214 {&_dbus_message_handler_init_lock},
217 for (i = 0; i < _DBUS_N_ELEMENTS (static_locks); i++)
219 static_locks[i].mutex = (*static_locks[i].init_func)();
221 if (static_locks[i].mutex == NULL)
223 for (i = i - 1; i >= 0; i--)
224 dbus_mutex_free (static_locks[i].mutex);
234 * Initializes threads. If this function is not called,
235 * the D-BUS library will not lock any data structures.
236 * If it is called, D-BUS will do locking, at some cost
237 * in efficiency. Note that this function must be called
238 * BEFORE using any other D-BUS functions.
240 * @todo right now this function can only be called once,
241 * maybe we should instead silently ignore multiple calls.
243 * @param functions functions for using threads
244 * @returns #TRUE on success, #FALSE if no memory
247 dbus_threads_init (const DBusThreadFunctions *functions)
249 _dbus_assert (functions != NULL);
251 /* these base functions are required. Future additions to
252 * DBusThreadFunctions may be optional.
254 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK);
255 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK);
256 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK);
257 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK);
258 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK);
259 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK);
260 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK);
261 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK);
262 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK);
263 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK);
264 _dbus_assert (functions->mutex_new != NULL);
265 _dbus_assert (functions->mutex_free != NULL);
266 _dbus_assert (functions->mutex_lock != NULL);
267 _dbus_assert (functions->mutex_unlock != NULL);
268 _dbus_assert (functions->condvar_new != NULL);
269 _dbus_assert (functions->condvar_free != NULL);
270 _dbus_assert (functions->condvar_wait != NULL);
271 _dbus_assert (functions->condvar_wait_timeout != NULL);
272 _dbus_assert (functions->condvar_wake_one != NULL);
273 _dbus_assert (functions->condvar_wake_all != NULL);
275 /* Check that all bits in the mask actually are valid mask bits.
276 * ensures people won't write code that breaks when we add
279 _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
281 if (thread_functions.mask != 0)
283 _dbus_warn ("dbus_threads_init() may only be called one time\n");
287 thread_functions.mutex_new = functions->mutex_new;
288 thread_functions.mutex_free = functions->mutex_free;
289 thread_functions.mutex_lock = functions->mutex_lock;
290 thread_functions.mutex_unlock = functions->mutex_unlock;
292 thread_functions.condvar_new = functions->condvar_new;
293 thread_functions.condvar_free = functions->condvar_free;
294 thread_functions.condvar_wait = functions->condvar_wait;
295 thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
296 thread_functions.condvar_wake_one = functions->condvar_wake_one;
297 thread_functions.condvar_wake_all = functions->condvar_wake_all;
299 thread_functions.mask = functions->mask;
301 if (!init_static_locks ())