1 From: Simon McVittie <simon.mcvittie@collabora.co.uk>
2 Date: Tue, 16 Apr 2013 16:37:51 +0100
3 Subject: Always initialize threading before allocating a dynamic mutex
5 Dynamic allocation of mutexes can fail anyway, so this is easy.
7 Justification for not keeping the dummy mutex code-paths, even as an
8 opt-in thing for processes known to be high-performance and
9 single-threaded: real mutexes only cut the throughput of
10 test/dbus-daemon.c by a couple of percent on my laptop (from around
11 6700 to around 6600 messages per second), and libdbus crashes caused
12 by not calling dbus_threads_init_default() are sufficiently widespread
13 that they're wasting a lot of everyone's time.
15 Bug: https://bugs.freedesktop.org/show_bug.cgi?id=54972
16 Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
17 Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
18 Reviewed-by: Anas Nashif <anas.nashif@intel.com>
20 Applied-upstream: 1.7.6, commit:08391b14616c248458e838691d068aa48dc70d18
21 Change-Id: I62e4fc541f6868ef44dc0654337b895e5392c16e
23 dbus/dbus-threads.c | 300 ++++++++++------------------------------------------
24 1 file changed, 56 insertions(+), 244 deletions(-)
26 diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
27 index 2c2a816..29462eb 100644
28 --- a/dbus/dbus-threads.c
29 +++ b/dbus/dbus-threads.c
31 #include "dbus-list.h"
33 static int thread_init_generation = 0;
35 -static DBusList *uninitialized_rmutex_list = NULL;
36 -static DBusList *uninitialized_cmutex_list = NULL;
37 -static DBusList *uninitialized_condvar_list = NULL;
39 -/** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
40 -#define _DBUS_DUMMY_MUTEX ((DBusMutex*)0xABCDEF)
41 -#define _DBUS_DUMMY_RMUTEX ((DBusRMutex *) _DBUS_DUMMY_MUTEX)
42 -#define _DBUS_DUMMY_CMUTEX ((DBusCMutex *) _DBUS_DUMMY_MUTEX)
44 -/** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
45 -#define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2)
48 * @defgroup DBusThreadsInternals Thread functions
49 @@ -59,11 +47,6 @@ static DBusList *uninitialized_condvar_list = NULL;
50 * If possible, the mutex returned by this function is recursive, to
51 * avoid deadlocks. However, that cannot be relied on.
53 - * The extra level of indirection given by allocating a pointer
54 - * to point to the mutex location allows the threading
55 - * module to swap out dummy mutexes for a real mutex so libraries
56 - * can initialize threads even after the D-Bus API has been used.
58 * @param location_p the location of the new mutex, can return #NULL on OOM
61 @@ -71,17 +54,13 @@ _dbus_rmutex_new_at_location (DBusRMutex **location_p)
63 _dbus_assert (location_p != NULL);
65 - if (thread_init_generation == _dbus_current_generation)
66 + if (!dbus_threads_init_default ())
68 - *location_p = _dbus_platform_rmutex_new ();
74 - *location_p = _DBUS_DUMMY_RMUTEX;
76 - if (!_dbus_list_append (&uninitialized_rmutex_list, location_p))
79 + *location_p = _dbus_platform_rmutex_new ();
83 @@ -92,11 +71,6 @@ _dbus_rmutex_new_at_location (DBusRMutex **location_p)
85 * The returned mutex is suitable for use with condition variables.
87 - * The extra level of indirection given by allocating a pointer
88 - * to point to the mutex location allows the threading
89 - * module to swap out dummy mutexes for a real mutex so libraries
90 - * can initialize threads even after the D-Bus API has been used.
92 * @param location_p the location of the new mutex, can return #NULL on OOM
95 @@ -104,22 +78,17 @@ _dbus_cmutex_new_at_location (DBusCMutex **location_p)
97 _dbus_assert (location_p != NULL);
99 - if (thread_init_generation == _dbus_current_generation)
100 + if (!dbus_threads_init_default ())
102 - *location_p = _dbus_platform_cmutex_new ();
103 + *location_p = NULL;
108 - *location_p = _DBUS_DUMMY_CMUTEX;
110 - if (!_dbus_list_append (&uninitialized_cmutex_list, location_p))
111 - *location_p = NULL;
113 + *location_p = _dbus_platform_cmutex_new ();
117 - * Frees a DBusRMutex or removes it from the uninitialized mutex list;
118 - * does nothing if passed a #NULL pointer.
119 + * Frees a DBusRMutex; does nothing if passed a #NULL pointer.
122 _dbus_rmutex_free_at_location (DBusRMutex **location_p)
123 @@ -127,23 +96,12 @@ _dbus_rmutex_free_at_location (DBusRMutex **location_p)
124 if (location_p == NULL)
127 - if (thread_init_generation == _dbus_current_generation)
129 - if (*location_p != NULL)
130 - _dbus_platform_rmutex_free (*location_p);
134 - _dbus_assert (*location_p == NULL || *location_p == _DBUS_DUMMY_RMUTEX);
136 - _dbus_list_remove (&uninitialized_rmutex_list, location_p);
138 + if (*location_p != NULL)
139 + _dbus_platform_rmutex_free (*location_p);
143 - * Frees a DBusCMutex and removes it from the
144 - * uninitialized mutex list;
145 - * does nothing if passed a #NULL pointer.
146 + * Frees a DBusCMutex; does nothing if passed a #NULL pointer.
149 _dbus_cmutex_free_at_location (DBusCMutex **location_p)
150 @@ -151,17 +109,8 @@ _dbus_cmutex_free_at_location (DBusCMutex **location_p)
151 if (location_p == NULL)
154 - if (thread_init_generation == _dbus_current_generation)
156 - if (*location_p != NULL)
157 - _dbus_platform_cmutex_free (*location_p);
161 - _dbus_assert (*location_p == NULL || *location_p == _DBUS_DUMMY_CMUTEX);
163 - _dbus_list_remove (&uninitialized_cmutex_list, location_p);
165 + if (*location_p != NULL)
166 + _dbus_platform_cmutex_free (*location_p);
170 @@ -172,8 +121,10 @@ _dbus_cmutex_free_at_location (DBusCMutex **location_p)
172 _dbus_rmutex_lock (DBusRMutex *mutex)
174 - if (mutex && thread_init_generation == _dbus_current_generation)
175 - _dbus_platform_rmutex_lock (mutex);
179 + _dbus_platform_rmutex_lock (mutex);
183 @@ -184,8 +135,10 @@ _dbus_rmutex_lock (DBusRMutex *mutex)
185 _dbus_cmutex_lock (DBusCMutex *mutex)
187 - if (mutex && thread_init_generation == _dbus_current_generation)
188 - _dbus_platform_cmutex_lock (mutex);
192 + _dbus_platform_cmutex_lock (mutex);
196 @@ -196,8 +149,10 @@ _dbus_cmutex_lock (DBusCMutex *mutex)
198 _dbus_rmutex_unlock (DBusRMutex *mutex)
200 - if (mutex && thread_init_generation == _dbus_current_generation)
201 - _dbus_platform_rmutex_unlock (mutex);
205 + _dbus_platform_rmutex_unlock (mutex);
209 @@ -208,8 +163,10 @@ _dbus_rmutex_unlock (DBusRMutex *mutex)
211 _dbus_cmutex_unlock (DBusCMutex *mutex)
213 - if (mutex && thread_init_generation == _dbus_current_generation)
214 - _dbus_platform_cmutex_unlock (mutex);
218 + _dbus_platform_cmutex_unlock (mutex);
222 @@ -223,19 +180,17 @@ _dbus_cmutex_unlock (DBusCMutex *mutex)
224 _dbus_condvar_new (void)
226 - if (thread_init_generation == _dbus_current_generation)
227 - return _dbus_platform_condvar_new ();
229 - return _DBUS_DUMMY_CONDVAR;
230 + if (!dbus_threads_init_default ())
233 + return _dbus_platform_condvar_new ();
238 * This does the same thing as _dbus_condvar_new. It however
239 * gives another level of indirection by allocating a pointer
240 - * to point to the condvar location. This allows the threading
241 - * module to swap out dummy condvars for a real condvar so libraries
242 - * can initialize threads even after the D-Bus API has been used.
243 + * to point to the condvar location; this used to be useful.
245 * @returns the location of a new condvar or #NULL on OOM
247 @@ -245,17 +200,7 @@ _dbus_condvar_new_at_location (DBusCondVar **location_p)
249 _dbus_assert (location_p != NULL);
251 - if (thread_init_generation == _dbus_current_generation)
253 - *location_p = _dbus_condvar_new();
257 - *location_p = _DBUS_DUMMY_CONDVAR;
259 - if (!_dbus_list_append (&uninitialized_condvar_list, location_p))
260 - *location_p = NULL;
262 + *location_p = _dbus_condvar_new();
266 @@ -266,14 +211,14 @@ _dbus_condvar_new_at_location (DBusCondVar **location_p)
268 _dbus_condvar_free (DBusCondVar *cond)
270 - if (cond && thread_init_generation == _dbus_current_generation)
271 - _dbus_platform_condvar_free (cond);
275 + _dbus_platform_condvar_free (cond);
279 - * Frees a conditional variable and removes it from the
280 - * uninitialized_condvar_list;
281 - * does nothing if passed a #NULL pointer.
282 + * Frees a condition variable; does nothing if passed a #NULL pointer.
285 _dbus_condvar_free_at_location (DBusCondVar **location_p)
286 @@ -281,17 +226,8 @@ _dbus_condvar_free_at_location (DBusCondVar **location_p)
287 if (location_p == NULL)
290 - if (thread_init_generation == _dbus_current_generation)
292 - if (*location_p != NULL)
293 - _dbus_platform_condvar_free (*location_p);
297 - _dbus_assert (*location_p == NULL || *location_p == _DBUS_DUMMY_CONDVAR);
299 - _dbus_list_remove (&uninitialized_condvar_list, location_p);
301 + if (*location_p != NULL)
302 + _dbus_platform_condvar_free (*location_p);
306 @@ -304,8 +240,10 @@ void
307 _dbus_condvar_wait (DBusCondVar *cond,
310 - if (cond && mutex && thread_init_generation == _dbus_current_generation)
311 - _dbus_platform_condvar_wait (cond, mutex);
312 + if (cond == NULL || mutex == NULL)
315 + _dbus_platform_condvar_wait (cond, mutex);
319 @@ -324,11 +262,11 @@ _dbus_condvar_wait_timeout (DBusCondVar *cond,
321 int timeout_milliseconds)
323 - if (cond && mutex && thread_init_generation == _dbus_current_generation)
324 - return _dbus_platform_condvar_wait_timeout (cond, mutex,
325 - timeout_milliseconds);
327 + if (cond == NULL || mutex == NULL)
330 + return _dbus_platform_condvar_wait_timeout (cond, mutex,
331 + timeout_milliseconds);
335 @@ -339,8 +277,10 @@ _dbus_condvar_wait_timeout (DBusCondVar *cond,
337 _dbus_condvar_wake_one (DBusCondVar *cond)
339 - if (cond && thread_init_generation == _dbus_current_generation)
340 - _dbus_platform_condvar_wake_one (cond);
344 + _dbus_platform_condvar_wake_one (cond);
347 static DBusRMutex *global_locks[_DBUS_N_GLOBAL_LOCKS] = { NULL };
348 @@ -358,132 +298,6 @@ shutdown_global_locks (void *nil)
353 -shutdown_uninitialized_locks (void *data)
355 - _dbus_list_clear (&uninitialized_rmutex_list);
356 - _dbus_list_clear (&uninitialized_cmutex_list);
357 - _dbus_list_clear (&uninitialized_condvar_list);
360 -/* init_global_locks() must be called first. */
362 -init_uninitialized_locks (void)
367 - _dbus_assert (thread_init_generation != _dbus_current_generation);
369 - link = uninitialized_rmutex_list;
370 - while (link != NULL)
375 - _dbus_assert (*mp == _DBUS_DUMMY_RMUTEX);
377 - *mp = _dbus_platform_rmutex_new ();
381 - link = _dbus_list_get_next_link (&uninitialized_rmutex_list, link);
384 - link = uninitialized_cmutex_list;
385 - while (link != NULL)
390 - _dbus_assert (*mp == _DBUS_DUMMY_CMUTEX);
392 - *mp = _dbus_platform_cmutex_new ();
396 - link = _dbus_list_get_next_link (&uninitialized_cmutex_list, link);
399 - link = uninitialized_condvar_list;
400 - while (link != NULL)
404 - cp = (DBusCondVar **)link->data;
405 - _dbus_assert (*cp == _DBUS_DUMMY_CONDVAR);
407 - *cp = _dbus_platform_condvar_new ();
411 - link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
414 - _dbus_list_clear (&uninitialized_rmutex_list);
415 - _dbus_list_clear (&uninitialized_cmutex_list);
416 - _dbus_list_clear (&uninitialized_condvar_list);
418 - /* This assumes that init_global_locks() has already been called. */
419 - _dbus_platform_rmutex_lock (global_locks[_DBUS_LOCK_shutdown_funcs]);
420 - ok = _dbus_register_shutdown_func_unlocked (shutdown_uninitialized_locks, NULL);
421 - _dbus_platform_rmutex_unlock (global_locks[_DBUS_LOCK_shutdown_funcs]);
429 - link = uninitialized_condvar_list;
430 - while (link != NULL)
436 - if (*cp != _DBUS_DUMMY_CONDVAR && *cp != NULL)
437 - _dbus_platform_condvar_free (*cp);
439 - *cp = _DBUS_DUMMY_CONDVAR;
441 - link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
445 - link = uninitialized_rmutex_list;
446 - while (link != NULL)
452 - if (*mp != _DBUS_DUMMY_RMUTEX && *mp != NULL)
453 - _dbus_platform_rmutex_free (*mp);
455 - *mp = _DBUS_DUMMY_RMUTEX;
457 - link = _dbus_list_get_next_link (&uninitialized_rmutex_list, link);
460 - link = uninitialized_cmutex_list;
461 - while (link != NULL)
467 - if (*mp != _DBUS_DUMMY_CMUTEX && *mp != NULL)
468 - _dbus_platform_cmutex_free (*mp);
470 - *mp = _DBUS_DUMMY_CMUTEX;
472 - link = _dbus_list_get_next_link (&uninitialized_cmutex_list, link);
479 init_global_locks (void)
481 @@ -585,9 +399,7 @@ dbus_threads_init (const DBusThreadFunctions *functions)
484 if (!_dbus_threads_init_platform_specific() ||
485 - /* init_global_locks() must be called before init_uninitialized_locks. */
486 - !init_global_locks () ||
487 - !init_uninitialized_locks ())
488 + !init_global_locks ())
490 _dbus_threads_unlock_platform_specific ();