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 cond the condition variable
158 * @param mutex the mutex
159 * @param timeout_milliseconds the maximum time to wait
160 * @returns TRUE if the condition was reached, or FALSE if the
161 * timeout was reached.
164 dbus_condvar_wait_timeout (DBusCondVar *cond,
166 int timeout_milliseconds)
168 if (cond && mutex && thread_functions.condvar_wait)
169 return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds);
175 * If there are threads waiting on the condition variable, wake
177 * Does nothing if passed a #NULL pointer.
180 dbus_condvar_wake_one (DBusCondVar *cond)
182 if (cond && thread_functions.condvar_wake_one)
183 (* thread_functions.condvar_wake_one) (cond);
187 * If there are threads waiting on the condition variable, wake
189 * Does nothing if passed a #NULL pointer.
192 dbus_condvar_wake_all (DBusCondVar *cond)
194 if (cond && thread_functions.condvar_wake_all)
195 (* thread_functions.condvar_wake_all) (cond);
199 init_static_locks(void)
204 DBusMutex *(*init_func)(void);
207 {&_dbus_list_init_lock},
208 {&_dbus_server_slots_init_lock},
209 {&_dbus_connection_slots_init_lock},
210 {&_dbus_atomic_init_lock},
211 {&_dbus_message_handler_init_lock},
212 {&_dbus_user_info_init_lock},
213 {&_dbus_bus_init_lock}
216 for (i = 0; i < _DBUS_N_ELEMENTS (static_locks); i++)
218 static_locks[i].mutex = (*static_locks[i].init_func)();
220 if (static_locks[i].mutex == NULL)
222 for (i = i - 1; i >= 0; i--)
223 dbus_mutex_free (static_locks[i].mutex);
233 * Initializes threads. If this function is not called,
234 * the D-BUS library will not lock any data structures.
235 * If it is called, D-BUS will do locking, at some cost
236 * in efficiency. Note that this function must be called
237 * BEFORE using any other D-BUS functions.
239 * @todo right now this function can only be called once,
240 * maybe we should instead silently ignore multiple calls.
242 * @param functions functions for using threads
243 * @returns #TRUE on success, #FALSE if no memory
246 dbus_threads_init (const DBusThreadFunctions *functions)
248 _dbus_assert (functions != NULL);
250 /* these base functions are required. Future additions to
251 * DBusThreadFunctions may be optional.
253 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK);
254 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK);
255 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK);
256 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK);
257 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK);
258 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK);
259 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK);
260 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK);
261 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK);
262 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK);
263 _dbus_assert (functions->mutex_new != NULL);
264 _dbus_assert (functions->mutex_free != NULL);
265 _dbus_assert (functions->mutex_lock != NULL);
266 _dbus_assert (functions->mutex_unlock != NULL);
267 _dbus_assert (functions->condvar_new != NULL);
268 _dbus_assert (functions->condvar_free != NULL);
269 _dbus_assert (functions->condvar_wait != NULL);
270 _dbus_assert (functions->condvar_wait_timeout != NULL);
271 _dbus_assert (functions->condvar_wake_one != NULL);
272 _dbus_assert (functions->condvar_wake_all != NULL);
274 /* Check that all bits in the mask actually are valid mask bits.
275 * ensures people won't write code that breaks when we add
278 _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
280 if (thread_functions.mask != 0)
282 _dbus_warn ("dbus_threads_init() may only be called one time\n");
286 thread_functions.mutex_new = functions->mutex_new;
287 thread_functions.mutex_free = functions->mutex_free;
288 thread_functions.mutex_lock = functions->mutex_lock;
289 thread_functions.mutex_unlock = functions->mutex_unlock;
291 thread_functions.condvar_new = functions->condvar_new;
292 thread_functions.condvar_free = functions->condvar_free;
293 thread_functions.condvar_wait = functions->condvar_wait;
294 thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
295 thread_functions.condvar_wake_one = functions->condvar_wake_one;
296 thread_functions.condvar_wake_all = functions->condvar_wake_all;
298 thread_functions.mask = functions->mask;
300 if (!init_static_locks ())