D-Bus 1.2.24
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-threads.h D-Bus threads handling 00003 * 00004 * Copyright (C) 2002, 2003, 2006 Red Hat Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 /* end of internals */ 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 /* these base functions are required. Future additions to 00553 * DBusThreadFunctions may be optional. 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 /* Either the mutex function set or recursive mutex set needs 00569 * to be available but not both 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 /* Check that all bits in the mask actually are valid mask bits. 00603 * ensures people won't write code that breaks when we add 00604 * new bits. 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; /* allow re-init in new generation */ 00610 00611 /* Silently allow multiple init 00612 * First init wins and D-Bus will always use its threading system 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 /* Default thread implemenation */ 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 /* DBUS_BUILD_TESTS */