D-Bus
1.4.10
|
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 <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 /* end of internals */ 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 /* these base functions are required. Future additions to 00556 * DBusThreadFunctions may be optional. 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 /* Either the mutex function set or recursive mutex set needs 00572 * to be available but not both 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 /* Check that all bits in the mask actually are valid mask bits. 00606 * ensures people won't write code that breaks when we add 00607 * new bits. 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; /* allow re-init in new generation */ 00613 00614 /* Silently allow multiple init 00615 * First init wins and D-Bus will always use its threading system 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 /* Default thread implemenation */ 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 /* DBUS_BUILD_TESTS */