1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 2 /* dbus-threads.h D-Bus threads handling 3 * 4 * Copyright (C) 2002, 2003, 2006 Red Hat Inc. 5 * 6 * Licensed under the Academic Free License version 2.1 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 #include <config.h> 24 #include "dbus-threads.h" 25 #include "dbus-internals.h" 26 #include "dbus-threads-internal.h" 27 #include "dbus-list.h" 28 29 static DBusThreadFunctions thread_functions = 30 { 31 0, 32 NULL, NULL, NULL, NULL, NULL, 33 NULL, NULL, NULL, NULL, NULL, 34 NULL, NULL, NULL, NULL, 35 36 NULL, NULL, NULL, NULL 37 }; 38 39 static int thread_init_generation = 0; 40 41 static DBusList *uninitialized_mutex_list = NULL; 42 static DBusList *uninitialized_condvar_list = NULL; 43 44 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */ 45 #define _DBUS_DUMMY_MUTEX ((DBusMutex*)0xABCDEF) 46 47 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */ 48 #define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2) 49 50 /** 51 * @defgroup DBusThreadsInternals Thread functions 52 * @ingroup DBusInternals 53 * @brief _dbus_mutex_lock(), etc. 54 * 55 * Functions and macros related to threads and thread locks. 56 * 57 * @{ 58 */ 59 60 /** 61 * Creates a new mutex using the function supplied to dbus_threads_init(), 62 * or creates a no-op mutex if threads are not initialized. 63 * May return #NULL even if threads are initialized, indicating 64 * out-of-memory. 65 * 66 * @returns new mutex or #NULL 67 */ 68 DBusMutex* 69 _dbus_mutex_new (void) 70 { 71 if (thread_functions.recursive_mutex_new) 72 return (* thread_functions.recursive_mutex_new) (); 73 else if (thread_functions.mutex_new) 74 return (* thread_functions.mutex_new) (); 75 else 76 return _DBUS_DUMMY_MUTEX; 77 } 78 79 /** 80 * This does the same thing as _dbus_mutex_new. It however 81 * gives another level of indirection by allocating a pointer 82 * to point to the mutex location. This allows the threading 83 * module to swap out dummy mutexes for real a real mutex so libraries 84 * can initialize threads even after the D-Bus API has been used. 85 * 86 * @param location_p the location of the new mutex, can return #NULL on OOM 87 */ 88 void 89 _dbus_mutex_new_at_location (DBusMutex **location_p) 90 { 91 _dbus_assert (location_p != NULL); 92 93 *location_p = _dbus_mutex_new(); 94 95 if (thread_init_generation != _dbus_current_generation && *location_p) 96 { 97 if (!_dbus_list_append (&uninitialized_mutex_list, location_p)) 98 { 99 _dbus_mutex_free (*location_p); 100 *location_p = NULL; 101 } 102 } 103 } 104 105 /** 106 * Frees a mutex created with dbus_mutex_new(); does 107 * nothing if passed a #NULL pointer. 108 */ 109 void 110 _dbus_mutex_free (DBusMutex *mutex) 111 { 112 if (mutex) 113 { 114 if (mutex && thread_functions.recursive_mutex_free) 115 (* thread_functions.recursive_mutex_free) (mutex); 116 else if (mutex && thread_functions.mutex_free) 117 (* thread_functions.mutex_free) (mutex); 118 } 119 } 120 121 /** 122 * Frees a mutex and removes it from the 123 * uninitialized_mutex_list; 124 * does nothing if passed a #NULL pointer. 125 */ 126 void 127 _dbus_mutex_free_at_location (DBusMutex **location_p) 128 { 129 if (location_p) 130 { 131 if (thread_init_generation != _dbus_current_generation) 132 _dbus_list_remove (&uninitialized_mutex_list, location_p); 133 134 _dbus_mutex_free (*location_p); 135 } 136 } 137 138 /** 139 * Locks a mutex. Does nothing if passed a #NULL pointer. 140 * Locks may be recursive if threading implementation initialized 141 * recursive locks. 142 */ 143 void 144 _dbus_mutex_lock (DBusMutex *mutex) 145 { 146 if (mutex) 147 { 148 if (thread_functions.recursive_mutex_lock) 149 (* thread_functions.recursive_mutex_lock) (mutex); 150 else if (thread_functions.mutex_lock) 151 (* thread_functions.mutex_lock) (mutex); 152 } 153 } 154 155 /** 156 * Unlocks a mutex. Does nothing if passed a #NULL pointer. 157 * 158 * @returns #TRUE on success 159 */ 160 void 161 _dbus_mutex_unlock (DBusMutex *mutex) 162 { 163 if (mutex) 164 { 165 if (thread_functions.recursive_mutex_unlock) 166 (* thread_functions.recursive_mutex_unlock) (mutex); 167 else if (thread_functions.mutex_unlock) 168 (* thread_functions.mutex_unlock) (mutex); 169 } 170 } 171 172 /** 173 * Creates a new condition variable using the function supplied 174 * to dbus_threads_init(), or creates a no-op condition variable 175 * if threads are not initialized. May return #NULL even if 176 * threads are initialized, indicating out-of-memory. 177 * 178 * @returns new mutex or #NULL 179 */ 180 DBusCondVar * 181 _dbus_condvar_new (void) 182 { 183 if (thread_functions.condvar_new) 184 return (* thread_functions.condvar_new) (); 185 else 186 return _DBUS_DUMMY_CONDVAR; 187 } 188 189 190 /** 191 * This does the same thing as _dbus_condvar_new. It however 192 * gives another level of indirection by allocating a pointer 193 * to point to the condvar location. This allows the threading 194 * module to swap out dummy condvars for real a real condvar so libraries 195 * can initialize threads even after the D-Bus API has been used. 196 * 197 * @returns the location of a new condvar or #NULL on OOM 198 */ 199 200 void 201 _dbus_condvar_new_at_location (DBusCondVar **location_p) 202 { 203 *location_p = _dbus_condvar_new(); 204 205 if (thread_init_generation != _dbus_current_generation && *location_p) 206 { 207 if (!_dbus_list_append (&uninitialized_condvar_list, location_p)) 208 { 209 _dbus_condvar_free (*location_p); 210 *location_p = NULL; 211 } 212 } 213 } 214 215 216 /** 217 * Frees a conditional variable created with dbus_condvar_new(); does 218 * nothing if passed a #NULL pointer. 219 */ 220 void 221 _dbus_condvar_free (DBusCondVar *cond) 222 { 223 if (cond && thread_functions.condvar_free) 224 (* thread_functions.condvar_free) (cond); 225 } 226 227 /** 228 * Frees a conditional variable and removes it from the 229 * uninitialized_condvar_list; 230 * does nothing if passed a #NULL pointer. 231 */ 232 void 233 _dbus_condvar_free_at_location (DBusCondVar **location_p) 234 { 235 if (location_p) 236 { 237 if (thread_init_generation != _dbus_current_generation) 238 _dbus_list_remove (&uninitialized_condvar_list, location_p); 239 240 _dbus_condvar_free (*location_p); 241 } 242 } 243 244 /** 245 * Atomically unlocks the mutex and waits for the conditions 246 * variable to be signalled. Locks the mutex again before 247 * returning. 248 * Does nothing if passed a #NULL pointer. 249 */ 250 void 251 _dbus_condvar_wait (DBusCondVar *cond, 252 DBusMutex *mutex) 253 { 254 if (cond && mutex && thread_functions.condvar_wait) 255 (* thread_functions.condvar_wait) (cond, mutex); 256 } 257 258 /** 259 * Atomically unlocks the mutex and waits for the conditions variable 260 * to be signalled, or for a timeout. Locks the mutex again before 261 * returning. Does nothing if passed a #NULL pointer. Return value 262 * is #FALSE if we timed out, #TRUE otherwise. 263 * 264 * @param cond the condition variable 265 * @param mutex the mutex 266 * @param timeout_milliseconds the maximum time to wait 267 * @returns #FALSE if the timeout occurred, #TRUE if not 268 */ 269 dbus_bool_t 270 _dbus_condvar_wait_timeout (DBusCondVar *cond, 271 DBusMutex *mutex, 272 int timeout_milliseconds) 273 { 274 if (cond && mutex && thread_functions.condvar_wait) 275 return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds); 276 else 277 return TRUE; 278 } 279 280 /** 281 * If there are threads waiting on the condition variable, wake 282 * up exactly one. 283 * Does nothing if passed a #NULL pointer. 284 */ 285 void 286 _dbus_condvar_wake_one (DBusCondVar *cond) 287 { 288 if (cond && thread_functions.condvar_wake_one) 289 (* thread_functions.condvar_wake_one) (cond); 290 } 291 292 /** 293 * If there are threads waiting on the condition variable, wake 294 * up all of them. 295 * Does nothing if passed a #NULL pointer. 296 */ 297 void 298 _dbus_condvar_wake_all (DBusCondVar *cond) 299 { 300 if (cond && thread_functions.condvar_wake_all) 301 (* thread_functions.condvar_wake_all) (cond); 302 } 303 304 static void 305 shutdown_global_locks (void *data) 306 { 307 DBusMutex ***locks = data; 308 int i; 309 310 i = 0; 311 while (i < _DBUS_N_GLOBAL_LOCKS) 312 { 313 _dbus_mutex_free (*(locks[i])); 314 *(locks[i]) = NULL; 315 ++i; 316 } 317 318 dbus_free (locks); 319 } 320 321 static void 322 shutdown_uninitialized_locks (void *data) 323 { 324 _dbus_list_clear (&uninitialized_mutex_list); 325 _dbus_list_clear (&uninitialized_condvar_list); 326 } 327 328 static dbus_bool_t 329 init_uninitialized_locks (void) 330 { 331 DBusList *link; 332 333 _dbus_assert (thread_init_generation != _dbus_current_generation); 334 335 link = uninitialized_mutex_list; 336 while (link != NULL) 337 { 338 DBusMutex **mp; 339 340 mp = (DBusMutex **)link->data; 341 _dbus_assert (*mp == _DBUS_DUMMY_MUTEX); 342 343 *mp = _dbus_mutex_new (); 344 if (*mp == NULL) 345 goto fail_mutex; 346 347 link = _dbus_list_get_next_link (&uninitialized_mutex_list, link); 348 } 349 350 link = uninitialized_condvar_list; 351 while (link != NULL) 352 { 353 DBusCondVar **cp; 354 355 cp = (DBusCondVar **)link->data; 356 _dbus_assert (*cp == _DBUS_DUMMY_CONDVAR); 357 358 *cp = _dbus_condvar_new (); 359 if (*cp == NULL) 360 goto fail_condvar; 361 362 link = _dbus_list_get_next_link (&uninitialized_condvar_list, link); 363 } 364 365 _dbus_list_clear (&uninitialized_mutex_list); 366 _dbus_list_clear (&uninitialized_condvar_list); 367 368 if (!_dbus_register_shutdown_func (shutdown_uninitialized_locks, 369 NULL)) 370 goto fail_condvar; 371 372 return TRUE; 373 374 fail_condvar: 375 link = uninitialized_condvar_list; 376 while (link != NULL) 377 { 378 DBusCondVar **cp; 379 380 cp = (DBusCondVar **)link->data; 381 382 if (*cp != _DBUS_DUMMY_CONDVAR) 383 _dbus_condvar_free (*cp); 384 else 385 break; 386 387 *cp = _DBUS_DUMMY_CONDVAR; 388 389 link = _dbus_list_get_next_link (&uninitialized_condvar_list, link); 390 } 391 392 fail_mutex: 393 link = uninitialized_mutex_list; 394 while (link != NULL) 395 { 396 DBusMutex **mp; 397 398 mp = (DBusMutex **)link->data; 399 400 if (*mp != _DBUS_DUMMY_MUTEX) 401 _dbus_mutex_free (*mp); 402 else 403 break; 404 405 *mp = _DBUS_DUMMY_MUTEX; 406 407 link = _dbus_list_get_next_link (&uninitialized_mutex_list, link); 408 } 409 410 return FALSE; 411 } 412 413 static dbus_bool_t 414 init_locks (void) 415 { 416 int i; 417 DBusMutex ***dynamic_global_locks; 418 419 DBusMutex **global_locks[] = { 420 #define LOCK_ADDR(name) (& _dbus_lock_##name) 421 LOCK_ADDR (win_fds), 422 LOCK_ADDR (sid_atom_cache), 423 LOCK_ADDR (list), 424 LOCK_ADDR (connection_slots), 425 LOCK_ADDR (pending_call_slots), 426 LOCK_ADDR (server_slots), 427 LOCK_ADDR (message_slots), 428 #if !DBUS_USE_SYNC 429 LOCK_ADDR (atomic), 430 #endif 431 LOCK_ADDR (bus), 432 LOCK_ADDR (bus_datas), 433 LOCK_ADDR (shutdown_funcs), 434 LOCK_ADDR (system_users), 435 LOCK_ADDR (message_cache), 436 LOCK_ADDR (shared_connections), 437 LOCK_ADDR (machine_uuid) 438 #undef LOCK_ADDR 439 }; 440 441 _dbus_assert (_DBUS_N_ELEMENTS (global_locks) == 442 _DBUS_N_GLOBAL_LOCKS); 443 444 i = 0; 445 446 dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS); 447 if (dynamic_global_locks == NULL) 448 goto failed; 449 450 while (i < _DBUS_N_ELEMENTS (global_locks)) 451 { 452 *global_locks[i] = _dbus_mutex_new (); 453 454 if (*global_locks[i] == NULL) 455 goto failed; 456 457 dynamic_global_locks[i] = global_locks[i]; 458 459 ++i; 460 } 461 462 if (!_dbus_register_shutdown_func (shutdown_global_locks, 463 dynamic_global_locks)) 464 goto failed; 465 466 if (!init_uninitialized_locks ()) 467 goto failed; 468 469 return TRUE; 470 471 failed: 472 dbus_free (dynamic_global_locks); 473 474 for (i = i - 1; i >= 0; i--) 475 { 476 _dbus_mutex_free (*global_locks[i]); 477 *global_locks[i] = NULL; 478 } 479 return FALSE; 480 } 481 482 /** @} */ /* end of internals */ 483 484 /** 485 * @defgroup DBusThreads Thread functions 486 * @ingroup DBus 487 * @brief dbus_threads_init() and dbus_threads_init_default() 488 * 489 * Functions and macros related to threads and thread locks. 490 * 491 * If threads are initialized, the D-Bus library has locks on all 492 * global data structures. In addition, each #DBusConnection has a 493 * lock, so only one thread at a time can touch the connection. (See 494 * @ref DBusConnection for more on connection locking.) 495 * 496 * Most other objects, however, do not have locks - they can only be 497 * used from a single thread at a time, unless you lock them yourself. 498 * For example, a #DBusMessage can't be modified from two threads 499 * at once. 500 * 501 * @{ 502 */ 503 504 /** 505 * 506 * Initializes threads. If this function is not called, the D-Bus 507 * library will not lock any data structures. If it is called, D-Bus 508 * will do locking, at some cost in efficiency. Note that this 509 * function must be called BEFORE the second thread is started. 510 * 511 * Almost always, you should use dbus_threads_init_default() instead. 512 * The raw dbus_threads_init() is only useful if you require a 513 * particular thread implementation for some reason. 514 * 515 * A possible reason to use dbus_threads_init() rather than 516 * dbus_threads_init_default() is to insert debugging checks or print 517 * statements. 518 * 519 * dbus_threads_init() may be called more than once. The first one 520 * wins and subsequent calls are ignored. (Unless you use 521 * dbus_shutdown() to reset libdbus, which will let you re-init 522 * threads.) 523 * 524 * Either recursive or nonrecursive mutex functions must be specified, 525 * but not both. New code should provide only the recursive functions 526 * - specifying the nonrecursive ones is deprecated. 527 * 528 * Because this function effectively sets global state, all code 529 * running in a given application must agree on the thread 530 * implementation. Most code won't care which thread implementation is 531 * used, so there's no problem. However, usually libraries should not 532 * call dbus_threads_init() or dbus_threads_init_default(), instead 533 * leaving this policy choice to applications. 534 * 535 * The exception is for application frameworks (GLib, Qt, etc.) and 536 * D-Bus bindings based on application frameworks. These frameworks 537 * define a cross-platform thread abstraction and can assume 538 * applications using the framework are OK with using that thread 539 * abstraction. 540 * 541 * However, even these app frameworks may find it easier to simply call 542 * dbus_threads_init_default(), and there's no reason they shouldn't. 543 * 544 * @param functions functions for using threads 545 * @returns #TRUE on success, #FALSE if no memory 546 */ 547 dbus_bool_t 548 dbus_threads_init (const DBusThreadFunctions *functions) 549 { 550 dbus_bool_t mutex_set; 551 dbus_bool_t recursive_mutex_set; 552 553 _dbus_assert (functions != NULL); 554 555 /* these base functions are required. Future additions to 556 * DBusThreadFunctions may be optional. 557 */ 558 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK); 559 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK); 560 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK); 561 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK); 562 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK); 563 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK); 564 _dbus_assert (functions->condvar_new != NULL); 565 _dbus_assert (functions->condvar_free != NULL); 566 _dbus_assert (functions->condvar_wait != NULL); 567 _dbus_assert (functions->condvar_wait_timeout != NULL); 568 _dbus_assert (functions->condvar_wake_one != NULL); 569 _dbus_assert (functions->condvar_wake_all != NULL); 570 571 /* Either the mutex function set or recursive mutex set needs 572 * to be available but not both 573 */ 574 mutex_set = (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK) && 575 (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK) && 576 (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK) && 577 (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK) && 578 functions->mutex_new && 579 functions->mutex_free && 580 functions->mutex_lock && 581 functions->mutex_unlock; 582 583 recursive_mutex_set = 584 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK) && 585 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK) && 586 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK) && 587 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK) && 588 functions->recursive_mutex_new && 589 functions->recursive_mutex_free && 590 functions->recursive_mutex_lock && 591 functions->recursive_mutex_unlock; 592 593 if (!(mutex_set || recursive_mutex_set)) 594 _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex " 595 "functions sets should be passed into " 596 "dbus_threads_init. Neither sets were passed."); 597 598 if (mutex_set && recursive_mutex_set) 599 _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex " 600 "functions sets should be passed into " 601 "dbus_threads_init. Both sets were passed. " 602 "You most likely just want to set the recursive " 603 "mutex functions to avoid deadlocks in D-Bus."); 604 605 /* Check that all bits in the mask actually are valid mask bits. 606 * ensures people won't write code that breaks when we add 607 * new bits. 608 */ 609 _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0); 610 611 if (thread_init_generation != _dbus_current_generation) 612 thread_functions.mask = 0; /* allow re-init in new generation */ 613 614 /* Silently allow multiple init 615 * First init wins and D-Bus will always use its threading system 616 */ 617 if (thread_functions.mask != 0) 618 return TRUE; 619 620 thread_functions.mutex_new = functions->mutex_new; 621 thread_functions.mutex_free = functions->mutex_free; 622 thread_functions.mutex_lock = functions->mutex_lock; 623 thread_functions.mutex_unlock = functions->mutex_unlock; 624 625 thread_functions.condvar_new = functions->condvar_new; 626 thread_functions.condvar_free = functions->condvar_free; 627 thread_functions.condvar_wait = functions->condvar_wait; 628 thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout; 629 thread_functions.condvar_wake_one = functions->condvar_wake_one; 630 thread_functions.condvar_wake_all = functions->condvar_wake_all; 631 632 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK) 633 thread_functions.recursive_mutex_new = functions->recursive_mutex_new; 634 635 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK) 636 thread_functions.recursive_mutex_free = functions->recursive_mutex_free; 637 638 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK) 639 thread_functions.recursive_mutex_lock = functions->recursive_mutex_lock; 640 641 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK) 642 thread_functions.recursive_mutex_unlock = functions->recursive_mutex_unlock; 643 644 thread_functions.mask = functions->mask; 645 646 if (!init_locks ()) 647 return FALSE; 648 649 thread_init_generation = _dbus_current_generation; 650 651 return TRUE; 652 } 653 654 655 656 /* Default thread implemenation */ 657 658 /** 659 * 660 * Calls dbus_threads_init() with a default set of 661 * #DBusThreadFunctions appropriate for the platform. 662 * 663 * Most applications should use this rather than dbus_threads_init(). 664 * 665 * It's safe to call dbus_threads_init_default() as many times as you 666 * want, but only the first time will have an effect. 667 * 668 * dbus_shutdown() reverses the effects of this function when it 669 * resets all global state in libdbus. 670 * 671 * @returns #TRUE on success, #FALSE if not enough memory 672 */ 673 dbus_bool_t 674 dbus_threads_init_default (void) 675 { 676 return _dbus_threads_init_platform_specific (); 677 } 678 679 680 /** @} */ 681 682 #ifdef DBUS_BUILD_TESTS 683 /** Fake mutex used for debugging */ 684 typedef struct DBusFakeMutex DBusFakeMutex; 685 /** Fake mutex used for debugging */ 686 struct DBusFakeMutex 687 { 688 dbus_bool_t locked; /**< Mutex is "locked" */ 689 }; 690 691 static DBusMutex * dbus_fake_mutex_new (void); 692 static void dbus_fake_mutex_free (DBusMutex *mutex); 693 static dbus_bool_t dbus_fake_mutex_lock (DBusMutex *mutex); 694 static dbus_bool_t dbus_fake_mutex_unlock (DBusMutex *mutex); 695 static DBusCondVar* dbus_fake_condvar_new (void); 696 static void dbus_fake_condvar_free (DBusCondVar *cond); 697 static void dbus_fake_condvar_wait (DBusCondVar *cond, 698 DBusMutex *mutex); 699 static dbus_bool_t dbus_fake_condvar_wait_timeout (DBusCondVar *cond, 700 DBusMutex *mutex, 701 int timeout_msec); 702 static void dbus_fake_condvar_wake_one (DBusCondVar *cond); 703 static void dbus_fake_condvar_wake_all (DBusCondVar *cond); 704 705 706 static const DBusThreadFunctions fake_functions = 707 { 708 DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK | 709 DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK | 710 DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK | 711 DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK | 712 DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK | 713 DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK | 714 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK | 715 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK | 716 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK| 717 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK, 718 dbus_fake_mutex_new, 719 dbus_fake_mutex_free, 720 dbus_fake_mutex_lock, 721 dbus_fake_mutex_unlock, 722 dbus_fake_condvar_new, 723 dbus_fake_condvar_free, 724 dbus_fake_condvar_wait, 725 dbus_fake_condvar_wait_timeout, 726 dbus_fake_condvar_wake_one, 727 dbus_fake_condvar_wake_all 728 }; 729 730 static DBusMutex * 731 dbus_fake_mutex_new (void) 732 { 733 DBusFakeMutex *mutex; 734 735 mutex = dbus_new0 (DBusFakeMutex, 1); 736 737 return (DBusMutex *)mutex; 738 } 739 740 static void 741 dbus_fake_mutex_free (DBusMutex *mutex) 742 { 743 DBusFakeMutex *fake = (DBusFakeMutex*) mutex; 744 745 _dbus_assert (!fake->locked); 746 747 dbus_free (fake); 748 } 749 750 static dbus_bool_t 751 dbus_fake_mutex_lock (DBusMutex *mutex) 752 { 753 DBusFakeMutex *fake = (DBusFakeMutex*) mutex; 754 755 _dbus_assert (!fake->locked); 756 757 fake->locked = TRUE; 758 759 return TRUE; 760 } 761 762 static dbus_bool_t 763 dbus_fake_mutex_unlock (DBusMutex *mutex) 764 { 765 DBusFakeMutex *fake = (DBusFakeMutex*) mutex; 766 767 _dbus_assert (fake->locked); 768 769 fake->locked = FALSE; 770 771 return TRUE; 772 } 773 774 static DBusCondVar* 775 dbus_fake_condvar_new (void) 776 { 777 return (DBusCondVar*) _dbus_strdup ("FakeCondvar"); 778 } 779 780 static void 781 dbus_fake_condvar_free (DBusCondVar *cond) 782 { 783 dbus_free (cond); 784 } 785 786 static void 787 dbus_fake_condvar_wait (DBusCondVar *cond, 788 DBusMutex *mutex) 789 { 790 791 } 792 793 static dbus_bool_t 794 dbus_fake_condvar_wait_timeout (DBusCondVar *cond, 795 DBusMutex *mutex, 796 int timeout_msec) 797 { 798 return TRUE; 799 } 800 801 static void 802 dbus_fake_condvar_wake_one (DBusCondVar *cond) 803 { 804 805 } 806 807 static void 808 dbus_fake_condvar_wake_all (DBusCondVar *cond) 809 { 810 811 } 812 813 dbus_bool_t 814 _dbus_threads_init_debug (void) 815 { 816 #ifdef DBUS_WIN 817 return _dbus_threads_init_platform_specific(); 818 #else 819 return dbus_threads_init (&fake_functions); 820 #endif 821 } 822 823 #endif /* DBUS_BUILD_TESTS */ 824