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