00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <config.h>
00024 #include "dbus-threads.h"
00025 #include "dbus-internals.h"
00026 #include "dbus-threads-internal.h"
00027 #include "dbus-list.h"
00028
00029 static DBusThreadFunctions thread_functions =
00030 {
00031 0,
00032 NULL, NULL, NULL, NULL, NULL,
00033 NULL, NULL, NULL, NULL, NULL,
00034 NULL, NULL, NULL, NULL,
00035
00036 NULL, NULL, NULL, NULL
00037 };
00038
00039 static int thread_init_generation = 0;
00040
00041 static DBusList *uninitialized_mutex_list = NULL;
00042 static DBusList *uninitialized_condvar_list = NULL;
00043
00045 #define _DBUS_DUMMY_MUTEX ((DBusMutex*)0xABCDEF)
00046
00048 #define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2)
00049
00068 DBusMutex*
00069 _dbus_mutex_new (void)
00070 {
00071 if (thread_functions.recursive_mutex_new)
00072 return (* thread_functions.recursive_mutex_new) ();
00073 else if (thread_functions.mutex_new)
00074 return (* thread_functions.mutex_new) ();
00075 else
00076 return _DBUS_DUMMY_MUTEX;
00077 }
00078
00088 void
00089 _dbus_mutex_new_at_location (DBusMutex **location_p)
00090 {
00091 _dbus_assert (location_p != NULL);
00092
00093 *location_p = _dbus_mutex_new();
00094
00095 if (thread_init_generation != _dbus_current_generation && *location_p)
00096 {
00097 if (!_dbus_list_append (&uninitialized_mutex_list, location_p))
00098 {
00099 _dbus_mutex_free (*location_p);
00100 *location_p = NULL;
00101 }
00102 }
00103 }
00104
00109 void
00110 _dbus_mutex_free (DBusMutex *mutex)
00111 {
00112 if (mutex)
00113 {
00114 if (mutex && thread_functions.recursive_mutex_free)
00115 (* thread_functions.recursive_mutex_free) (mutex);
00116 else if (mutex && thread_functions.mutex_free)
00117 (* thread_functions.mutex_free) (mutex);
00118 }
00119 }
00120
00126 void
00127 _dbus_mutex_free_at_location (DBusMutex **location_p)
00128 {
00129 if (location_p)
00130 {
00131 if (thread_init_generation != _dbus_current_generation)
00132 _dbus_list_remove (&uninitialized_mutex_list, location_p);
00133
00134 _dbus_mutex_free (*location_p);
00135 }
00136 }
00137
00143 void
00144 _dbus_mutex_lock (DBusMutex *mutex)
00145 {
00146 if (mutex)
00147 {
00148 if (thread_functions.recursive_mutex_lock)
00149 (* thread_functions.recursive_mutex_lock) (mutex);
00150 else if (thread_functions.mutex_lock)
00151 (* thread_functions.mutex_lock) (mutex);
00152 }
00153 }
00154
00160 void
00161 _dbus_mutex_unlock (DBusMutex *mutex)
00162 {
00163 if (mutex)
00164 {
00165 if (thread_functions.recursive_mutex_unlock)
00166 (* thread_functions.recursive_mutex_unlock) (mutex);
00167 else if (thread_functions.mutex_unlock)
00168 (* thread_functions.mutex_unlock) (mutex);
00169 }
00170 }
00171
00180 DBusCondVar *
00181 _dbus_condvar_new (void)
00182 {
00183 if (thread_functions.condvar_new)
00184 return (* thread_functions.condvar_new) ();
00185 else
00186 return _DBUS_DUMMY_CONDVAR;
00187 }
00188
00189
00200 void
00201 _dbus_condvar_new_at_location (DBusCondVar **location_p)
00202 {
00203 *location_p = _dbus_condvar_new();
00204
00205 if (thread_init_generation != _dbus_current_generation && *location_p)
00206 {
00207 if (!_dbus_list_append (&uninitialized_condvar_list, location_p))
00208 {
00209 _dbus_condvar_free (*location_p);
00210 *location_p = NULL;
00211 }
00212 }
00213 }
00214
00215
00220 void
00221 _dbus_condvar_free (DBusCondVar *cond)
00222 {
00223 if (cond && thread_functions.condvar_free)
00224 (* thread_functions.condvar_free) (cond);
00225 }
00226
00232 void
00233 _dbus_condvar_free_at_location (DBusCondVar **location_p)
00234 {
00235 if (location_p)
00236 {
00237 if (thread_init_generation != _dbus_current_generation)
00238 _dbus_list_remove (&uninitialized_condvar_list, location_p);
00239
00240 _dbus_condvar_free (*location_p);
00241 }
00242 }
00243
00250 void
00251 _dbus_condvar_wait (DBusCondVar *cond,
00252 DBusMutex *mutex)
00253 {
00254 if (cond && mutex && thread_functions.condvar_wait)
00255 (* thread_functions.condvar_wait) (cond, mutex);
00256 }
00257
00269 dbus_bool_t
00270 _dbus_condvar_wait_timeout (DBusCondVar *cond,
00271 DBusMutex *mutex,
00272 int timeout_milliseconds)
00273 {
00274 if (cond && mutex && thread_functions.condvar_wait)
00275 return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds);
00276 else
00277 return TRUE;
00278 }
00279
00285 void
00286 _dbus_condvar_wake_one (DBusCondVar *cond)
00287 {
00288 if (cond && thread_functions.condvar_wake_one)
00289 (* thread_functions.condvar_wake_one) (cond);
00290 }
00291
00297 void
00298 _dbus_condvar_wake_all (DBusCondVar *cond)
00299 {
00300 if (cond && thread_functions.condvar_wake_all)
00301 (* thread_functions.condvar_wake_all) (cond);
00302 }
00303
00304 static void
00305 shutdown_global_locks (void *data)
00306 {
00307 DBusMutex ***locks = data;
00308 int i;
00309
00310 i = 0;
00311 while (i < _DBUS_N_GLOBAL_LOCKS)
00312 {
00313 _dbus_mutex_free (*(locks[i]));
00314 *(locks[i]) = NULL;
00315 ++i;
00316 }
00317
00318 dbus_free (locks);
00319 }
00320
00321 static void
00322 shutdown_uninitialized_locks (void *data)
00323 {
00324 _dbus_list_clear (&uninitialized_mutex_list);
00325 _dbus_list_clear (&uninitialized_condvar_list);
00326 }
00327
00328 static dbus_bool_t
00329 init_uninitialized_locks (void)
00330 {
00331 DBusList *link;
00332
00333 _dbus_assert (thread_init_generation != _dbus_current_generation);
00334
00335 link = uninitialized_mutex_list;
00336 while (link != NULL)
00337 {
00338 DBusMutex **mp;
00339
00340 mp = (DBusMutex **)link->data;
00341 _dbus_assert (*mp == _DBUS_DUMMY_MUTEX);
00342
00343 *mp = _dbus_mutex_new ();
00344 if (*mp == NULL)
00345 goto fail_mutex;
00346
00347 link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
00348 }
00349
00350 link = uninitialized_condvar_list;
00351 while (link != NULL)
00352 {
00353 DBusCondVar **cp;
00354
00355 cp = (DBusCondVar **)link->data;
00356 _dbus_assert (*cp == _DBUS_DUMMY_CONDVAR);
00357
00358 *cp = _dbus_condvar_new ();
00359 if (*cp == NULL)
00360 goto fail_condvar;
00361
00362 link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
00363 }
00364
00365 _dbus_list_clear (&uninitialized_mutex_list);
00366 _dbus_list_clear (&uninitialized_condvar_list);
00367
00368 if (!_dbus_register_shutdown_func (shutdown_uninitialized_locks,
00369 NULL))
00370 goto fail_condvar;
00371
00372 return TRUE;
00373
00374 fail_condvar:
00375 link = uninitialized_condvar_list;
00376 while (link != NULL)
00377 {
00378 DBusCondVar **cp;
00379
00380 cp = (DBusCondVar **)link->data;
00381
00382 if (*cp != _DBUS_DUMMY_CONDVAR)
00383 _dbus_condvar_free (*cp);
00384 else
00385 break;
00386
00387 *cp = _DBUS_DUMMY_CONDVAR;
00388
00389 link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
00390 }
00391
00392 fail_mutex:
00393 link = uninitialized_mutex_list;
00394 while (link != NULL)
00395 {
00396 DBusMutex **mp;
00397
00398 mp = (DBusMutex **)link->data;
00399
00400 if (*mp != _DBUS_DUMMY_MUTEX)
00401 _dbus_mutex_free (*mp);
00402 else
00403 break;
00404
00405 *mp = _DBUS_DUMMY_MUTEX;
00406
00407 link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
00408 }
00409
00410 return FALSE;
00411 }
00412
00413 static dbus_bool_t
00414 init_locks (void)
00415 {
00416 int i;
00417 DBusMutex ***dynamic_global_locks;
00418
00419 DBusMutex **global_locks[] = {
00420 #define LOCK_ADDR(name) (& _dbus_lock_##name)
00421 LOCK_ADDR (win_fds),
00422 LOCK_ADDR (sid_atom_cache),
00423 LOCK_ADDR (list),
00424 LOCK_ADDR (connection_slots),
00425 LOCK_ADDR (pending_call_slots),
00426 LOCK_ADDR (server_slots),
00427 LOCK_ADDR (message_slots),
00428 #if !DBUS_USE_SYNC
00429 LOCK_ADDR (atomic),
00430 #endif
00431 LOCK_ADDR (bus),
00432 LOCK_ADDR (bus_datas),
00433 LOCK_ADDR (shutdown_funcs),
00434 LOCK_ADDR (system_users),
00435 LOCK_ADDR (message_cache),
00436 LOCK_ADDR (shared_connections),
00437 LOCK_ADDR (machine_uuid)
00438 #undef LOCK_ADDR
00439 };
00440
00441 _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
00442 _DBUS_N_GLOBAL_LOCKS);
00443
00444 i = 0;
00445
00446 dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
00447 if (dynamic_global_locks == NULL)
00448 goto failed;
00449
00450 while (i < _DBUS_N_ELEMENTS (global_locks))
00451 {
00452 *global_locks[i] = _dbus_mutex_new ();
00453
00454 if (*global_locks[i] == NULL)
00455 goto failed;
00456
00457 dynamic_global_locks[i] = global_locks[i];
00458
00459 ++i;
00460 }
00461
00462 if (!_dbus_register_shutdown_func (shutdown_global_locks,
00463 dynamic_global_locks))
00464 goto failed;
00465
00466 if (!init_uninitialized_locks ())
00467 goto failed;
00468
00469 return TRUE;
00470
00471 failed:
00472 dbus_free (dynamic_global_locks);
00473
00474 for (i = i - 1; i >= 0; i--)
00475 {
00476 _dbus_mutex_free (*global_locks[i]);
00477 *global_locks[i] = NULL;
00478 }
00479 return FALSE;
00480 }
00481
00483
00547 dbus_bool_t
00548 dbus_threads_init (const DBusThreadFunctions *functions)
00549 {
00550 dbus_bool_t mutex_set;
00551 dbus_bool_t recursive_mutex_set;
00552
00553 _dbus_assert (functions != NULL);
00554
00555
00556
00557
00558 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK);
00559 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK);
00560 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK);
00561 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK);
00562 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK);
00563 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK);
00564 _dbus_assert (functions->condvar_new != NULL);
00565 _dbus_assert (functions->condvar_free != NULL);
00566 _dbus_assert (functions->condvar_wait != NULL);
00567 _dbus_assert (functions->condvar_wait_timeout != NULL);
00568 _dbus_assert (functions->condvar_wake_one != NULL);
00569 _dbus_assert (functions->condvar_wake_all != NULL);
00570
00571
00572
00573
00574 mutex_set = (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK) &&
00575 (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK) &&
00576 (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK) &&
00577 (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK) &&
00578 functions->mutex_new &&
00579 functions->mutex_free &&
00580 functions->mutex_lock &&
00581 functions->mutex_unlock;
00582
00583 recursive_mutex_set =
00584 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK) &&
00585 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK) &&
00586 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK) &&
00587 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK) &&
00588 functions->recursive_mutex_new &&
00589 functions->recursive_mutex_free &&
00590 functions->recursive_mutex_lock &&
00591 functions->recursive_mutex_unlock;
00592
00593 if (!(mutex_set || recursive_mutex_set))
00594 _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex "
00595 "functions sets should be passed into "
00596 "dbus_threads_init. Neither sets were passed.");
00597
00598 if (mutex_set && recursive_mutex_set)
00599 _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex "
00600 "functions sets should be passed into "
00601 "dbus_threads_init. Both sets were passed. "
00602 "You most likely just want to set the recursive "
00603 "mutex functions to avoid deadlocks in D-Bus.");
00604
00605
00606
00607
00608
00609 _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
00610
00611 if (thread_init_generation != _dbus_current_generation)
00612 thread_functions.mask = 0;
00613
00614
00615
00616
00617 if (thread_functions.mask != 0)
00618 return TRUE;
00619
00620 thread_functions.mutex_new = functions->mutex_new;
00621 thread_functions.mutex_free = functions->mutex_free;
00622 thread_functions.mutex_lock = functions->mutex_lock;
00623 thread_functions.mutex_unlock = functions->mutex_unlock;
00624
00625 thread_functions.condvar_new = functions->condvar_new;
00626 thread_functions.condvar_free = functions->condvar_free;
00627 thread_functions.condvar_wait = functions->condvar_wait;
00628 thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
00629 thread_functions.condvar_wake_one = functions->condvar_wake_one;
00630 thread_functions.condvar_wake_all = functions->condvar_wake_all;
00631
00632 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK)
00633 thread_functions.recursive_mutex_new = functions->recursive_mutex_new;
00634
00635 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK)
00636 thread_functions.recursive_mutex_free = functions->recursive_mutex_free;
00637
00638 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK)
00639 thread_functions.recursive_mutex_lock = functions->recursive_mutex_lock;
00640
00641 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK)
00642 thread_functions.recursive_mutex_unlock = functions->recursive_mutex_unlock;
00643
00644 thread_functions.mask = functions->mask;
00645
00646 if (!init_locks ())
00647 return FALSE;
00648
00649 thread_init_generation = _dbus_current_generation;
00650
00651 return TRUE;
00652 }
00653
00654
00655
00656
00657
00673 dbus_bool_t
00674 dbus_threads_init_default (void)
00675 {
00676 return _dbus_threads_init_platform_specific ();
00677 }
00678
00679
00682 #ifdef DBUS_BUILD_TESTS
00683
00684 typedef struct DBusFakeMutex DBusFakeMutex;
00686 struct DBusFakeMutex
00687 {
00688 dbus_bool_t locked;
00689 };
00690
00691 static DBusMutex * dbus_fake_mutex_new (void);
00692 static void dbus_fake_mutex_free (DBusMutex *mutex);
00693 static dbus_bool_t dbus_fake_mutex_lock (DBusMutex *mutex);
00694 static dbus_bool_t dbus_fake_mutex_unlock (DBusMutex *mutex);
00695 static DBusCondVar* dbus_fake_condvar_new (void);
00696 static void dbus_fake_condvar_free (DBusCondVar *cond);
00697 static void dbus_fake_condvar_wait (DBusCondVar *cond,
00698 DBusMutex *mutex);
00699 static dbus_bool_t dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
00700 DBusMutex *mutex,
00701 int timeout_msec);
00702 static void dbus_fake_condvar_wake_one (DBusCondVar *cond);
00703 static void dbus_fake_condvar_wake_all (DBusCondVar *cond);
00704
00705
00706 static const DBusThreadFunctions fake_functions =
00707 {
00708 DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
00709 DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
00710 DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
00711 DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
00712 DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
00713 DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
00714 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
00715 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
00716 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
00717 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
00718 dbus_fake_mutex_new,
00719 dbus_fake_mutex_free,
00720 dbus_fake_mutex_lock,
00721 dbus_fake_mutex_unlock,
00722 dbus_fake_condvar_new,
00723 dbus_fake_condvar_free,
00724 dbus_fake_condvar_wait,
00725 dbus_fake_condvar_wait_timeout,
00726 dbus_fake_condvar_wake_one,
00727 dbus_fake_condvar_wake_all
00728 };
00729
00730 static DBusMutex *
00731 dbus_fake_mutex_new (void)
00732 {
00733 DBusFakeMutex *mutex;
00734
00735 mutex = dbus_new0 (DBusFakeMutex, 1);
00736
00737 return (DBusMutex *)mutex;
00738 }
00739
00740 static void
00741 dbus_fake_mutex_free (DBusMutex *mutex)
00742 {
00743 DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
00744
00745 _dbus_assert (!fake->locked);
00746
00747 dbus_free (fake);
00748 }
00749
00750 static dbus_bool_t
00751 dbus_fake_mutex_lock (DBusMutex *mutex)
00752 {
00753 DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
00754
00755 _dbus_assert (!fake->locked);
00756
00757 fake->locked = TRUE;
00758
00759 return TRUE;
00760 }
00761
00762 static dbus_bool_t
00763 dbus_fake_mutex_unlock (DBusMutex *mutex)
00764 {
00765 DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
00766
00767 _dbus_assert (fake->locked);
00768
00769 fake->locked = FALSE;
00770
00771 return TRUE;
00772 }
00773
00774 static DBusCondVar*
00775 dbus_fake_condvar_new (void)
00776 {
00777 return (DBusCondVar*) _dbus_strdup ("FakeCondvar");
00778 }
00779
00780 static void
00781 dbus_fake_condvar_free (DBusCondVar *cond)
00782 {
00783 dbus_free (cond);
00784 }
00785
00786 static void
00787 dbus_fake_condvar_wait (DBusCondVar *cond,
00788 DBusMutex *mutex)
00789 {
00790
00791 }
00792
00793 static dbus_bool_t
00794 dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
00795 DBusMutex *mutex,
00796 int timeout_msec)
00797 {
00798 return TRUE;
00799 }
00800
00801 static void
00802 dbus_fake_condvar_wake_one (DBusCondVar *cond)
00803 {
00804
00805 }
00806
00807 static void
00808 dbus_fake_condvar_wake_all (DBusCondVar *cond)
00809 {
00810
00811 }
00812
00813 dbus_bool_t
00814 _dbus_threads_init_debug (void)
00815 {
00816 #ifdef DBUS_WIN
00817 return _dbus_threads_init_platform_specific();
00818 #else
00819 return dbus_threads_init (&fake_functions);
00820 #endif
00821 }
00822
00823 #endif