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,
31 NULL, NULL, NULL, NULL,
32 NULL, NULL, NULL, NULL
35 static DBusMutex *static_mutex_init_lock = NULL;
37 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
38 #define _DBUS_DUMMY_MUTEX ((void*)0xABCDEF)
41 * @defgroup DBusThreads Thread functions
43 * @brief dbus_threads_init(), dbus_mutex_lock(), etc.
45 * Functions and macros related to threads and thread locks.
51 * Creates a new mutex using the function supplied to dbus_threads_init(),
52 * or creates a no-op mutex if threads are not initialized.
53 * May return #NULL even if threads are initialized, indicating
56 * @returns new mutex or #NULL
61 if (thread_functions.mutex_new)
62 return (* thread_functions.mutex_new) ();
64 return _DBUS_DUMMY_MUTEX;
68 * Frees a mutex created with dbus_mutex_new(); does
69 * nothing if passed a #NULL pointer.
72 dbus_mutex_free (DBusMutex *mutex)
74 if (mutex && thread_functions.mutex_free)
75 (* thread_functions.mutex_free) (mutex);
79 * Locks a mutex. Does nothing if passed a #NULL pointer.
80 * Locks are not recursive.
82 * @returns #TRUE on success
85 dbus_mutex_lock (DBusMutex *mutex)
87 if (mutex && thread_functions.mutex_lock)
88 return (* thread_functions.mutex_lock) (mutex);
94 * Unlocks a mutex. Does nothing if passed a #NULL pointer.
96 * @returns #TRUE on success
99 dbus_mutex_unlock (DBusMutex *mutex)
101 if (mutex && thread_functions.mutex_unlock)
102 return (* thread_functions.mutex_unlock) (mutex);
108 * Initializes threads. If this function is not called,
109 * the D-BUS library will not lock any data structures.
110 * If it is called, D-BUS will do locking, at some cost
111 * in efficiency. Note that this function must be called
112 * BEFORE using any other D-BUS functions.
114 * @todo right now this function can only be called once,
115 * maybe we should instead silently ignore multiple calls.
117 * @param functions functions for using threads
118 * @returns #TRUE on success, #FALSE if no memory
121 dbus_threads_init (const DBusThreadFunctions *functions)
123 _dbus_assert (functions != NULL);
125 /* these base functions are required. Future additions to
126 * DBusThreadFunctions may be optional.
128 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_NEW_MASK);
129 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_FREE_MASK);
130 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_LOCK_MASK);
131 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_UNLOCK_MASK);
132 _dbus_assert (functions->mutex_new != NULL);
133 _dbus_assert (functions->mutex_free != NULL);
134 _dbus_assert (functions->mutex_lock != NULL);
135 _dbus_assert (functions->mutex_unlock != NULL);
137 /* Check that all bits in the mask actually are valid mask bits.
138 * ensures people won't write code that breaks when we add
141 _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
143 if (thread_functions.mask != 0)
145 _dbus_warn ("dbus_threads_init() may only be called one time\n");
149 thread_functions.mutex_new = functions->mutex_new;
150 thread_functions.mutex_free = functions->mutex_free;
151 thread_functions.mutex_lock = functions->mutex_lock;
152 thread_functions.mutex_unlock = functions->mutex_unlock;
154 thread_functions.mask = functions->mask;
156 static_mutex_init_lock = dbus_mutex_new ();
158 if (static_mutex_init_lock == NULL)
160 thread_functions.mask = 0;
167 /** Accesses the field of DBusStaticMutex that
168 * stores the DBusMutex used to implement.
170 #define _DBUS_STATIC_MUTEX_IMPL(mutex) ((mutex)->pad1)
173 * Lock a static mutex
175 * @todo currently broken on some platforms due to
176 * non-workingness of "double checked locking"
177 * see http://bugzilla.gnome.org/show_bug.cgi?id=69668
178 * and http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
181 * @param mutex the mutex to lock
182 * @returns #TRUE on success
185 dbus_static_mutex_lock (DBusStaticMutex *mutex)
187 if (_DBUS_STATIC_MUTEX_IMPL (mutex))
188 return dbus_mutex_lock (_DBUS_STATIC_MUTEX_IMPL (mutex));
190 if (!dbus_mutex_lock (static_mutex_init_lock))
193 if (_DBUS_STATIC_MUTEX_IMPL (mutex) == NULL)
194 _DBUS_STATIC_MUTEX_IMPL (mutex) = dbus_mutex_new ();
196 dbus_mutex_unlock (static_mutex_init_lock);
198 if (_DBUS_STATIC_MUTEX_IMPL (mutex))
199 return dbus_mutex_lock (_DBUS_STATIC_MUTEX_IMPL (mutex));
205 * Unlock a static mutex
206 * @param mutex the mutex to lock
207 * @returns #TRUE on success
210 dbus_static_mutex_unlock (DBusStaticMutex *mutex)
212 _dbus_assert (_DBUS_STATIC_MUTEX_IMPL (mutex) != NULL);
214 return dbus_mutex_unlock (_DBUS_STATIC_MUTEX_IMPL (mutex));