1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-threads.h D-Bus threads handling
4 * Copyright (C) 2002, 2003 Red Hat Inc.
6 * Licensed under the Academic Free License version 2.1
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "dbus-threads.h"
24 #include "dbus-internals.h"
25 #include "dbus-threads-internal.h"
26 #include "dbus-list.h"
28 #if defined(__WIN32) || defined(__CYGWIN__)
29 #define USE_WIN32_THREADS
32 #ifdef USE_WIN32_THREADS
39 static DBusThreadFunctions thread_functions =
42 NULL, NULL, NULL, NULL, NULL,
43 NULL, NULL, NULL, NULL, NULL,
44 NULL, NULL, NULL, NULL,
46 NULL, NULL, NULL, NULL
49 #ifdef USE_WIN32_THREADS
52 CRITICAL_SECTION lock;
55 static DWORD dbus_cond_event_tls = TLS_OUT_OF_INDEXES;
58 static int thread_init_generation = 0;
60 static DBusList *uninitialized_mutex_list = NULL;
61 static DBusList *uninitialized_condvar_list = NULL;
63 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
64 #define _DBUS_DUMMY_MUTEX ((DBusMutex*)0xABCDEF)
66 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
67 #define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2)
70 * @defgroup DBusThreadsInternals Thread functions
71 * @ingroup DBusInternals
72 * @brief _dbus_mutex_lock(), etc.
74 * Functions and macros related to threads and thread locks.
80 * Creates a new mutex using the function supplied to dbus_threads_init(),
81 * or creates a no-op mutex if threads are not initialized.
82 * May return #NULL even if threads are initialized, indicating
85 * @returns new mutex or #NULL
88 _dbus_mutex_new (void)
90 if (thread_functions.recursive_mutex_new)
91 return (* thread_functions.recursive_mutex_new) ();
92 else if (thread_functions.mutex_new)
93 return (* thread_functions.mutex_new) ();
95 return _DBUS_DUMMY_MUTEX;
99 * This does the same thing as _dbus_mutex_new. It however
100 * gives another level of indirection by allocating a pointer
101 * to point to the mutex location. This allows the threading
102 * module to swap out dummy mutexes for real a real mutex so libraries
103 * can initialize threads even after the D-Bus API has been used.
105 * @param location_p the location of the new mutex, can return #NULL on OOM
108 _dbus_mutex_new_at_location (DBusMutex **location_p)
110 _dbus_assert (location_p != NULL);
112 *location_p = _dbus_mutex_new();
114 if (thread_init_generation != _dbus_current_generation && *location_p)
116 if (!_dbus_list_append (&uninitialized_mutex_list, location_p))
118 _dbus_mutex_free (*location_p);
125 * Frees a mutex created with dbus_mutex_new(); does
126 * nothing if passed a #NULL pointer.
129 _dbus_mutex_free (DBusMutex *mutex)
133 if (mutex && thread_functions.recursive_mutex_free)
134 (* thread_functions.recursive_mutex_free) (mutex);
135 else if (mutex && thread_functions.mutex_free)
136 (* thread_functions.mutex_free) (mutex);
141 * Frees a mutex and removes it from the
142 * uninitialized_mutex_list;
143 * does nothing if passed a #NULL pointer.
146 _dbus_mutex_free_at_location (DBusMutex **location_p)
150 if (thread_init_generation != _dbus_current_generation)
151 _dbus_list_remove (&uninitialized_mutex_list, location_p);
153 _dbus_mutex_free (*location_p);
158 * Locks a mutex. Does nothing if passed a #NULL pointer.
159 * Locks may be recursive if threading implementation initialized
163 _dbus_mutex_lock (DBusMutex *mutex)
167 if (thread_functions.recursive_mutex_lock)
168 (* thread_functions.recursive_mutex_lock) (mutex);
169 else if (thread_functions.mutex_lock)
170 (* thread_functions.mutex_lock) (mutex);
175 * Unlocks a mutex. Does nothing if passed a #NULL pointer.
177 * @returns #TRUE on success
180 _dbus_mutex_unlock (DBusMutex *mutex)
184 if (thread_functions.recursive_mutex_unlock)
185 (* thread_functions.recursive_mutex_unlock) (mutex);
186 else if (thread_functions.mutex_unlock)
187 (* thread_functions.mutex_unlock) (mutex);
192 * Creates a new condition variable using the function supplied
193 * to dbus_threads_init(), or creates a no-op condition variable
194 * if threads are not initialized. May return #NULL even if
195 * threads are initialized, indicating out-of-memory.
197 * @returns new mutex or #NULL
200 _dbus_condvar_new (void)
202 if (thread_functions.condvar_new)
203 return (* thread_functions.condvar_new) ();
205 return _DBUS_DUMMY_CONDVAR;
210 * This does the same thing as _dbus_condvar_new. It however
211 * gives another level of indirection by allocating a pointer
212 * to point to the condvar location. This allows the threading
213 * module to swap out dummy condvars for real a real condvar so libraries
214 * can initialize threads even after the D-Bus API has been used.
216 * @returns the location of a new condvar or #NULL on OOM
220 _dbus_condvar_new_at_location (DBusCondVar **location_p)
222 *location_p = _dbus_condvar_new();
224 if (thread_init_generation != _dbus_current_generation && *location_p)
226 if (!_dbus_list_append (&uninitialized_condvar_list, location_p))
228 _dbus_condvar_free (*location_p);
236 * Frees a conditional variable created with dbus_condvar_new(); does
237 * nothing if passed a #NULL pointer.
240 _dbus_condvar_free (DBusCondVar *cond)
242 if (cond && thread_functions.condvar_free)
243 (* thread_functions.condvar_free) (cond);
247 * Frees a conditional variable and removes it from the
248 * uninitialized_condvar_list;
249 * does nothing if passed a #NULL pointer.
252 _dbus_condvar_free_at_location (DBusCondVar **location_p)
256 if (thread_init_generation != _dbus_current_generation)
257 _dbus_list_remove (&uninitialized_condvar_list, location_p);
259 _dbus_condvar_free (*location_p);
264 * Atomically unlocks the mutex and waits for the conditions
265 * variable to be signalled. Locks the mutex again before
267 * Does nothing if passed a #NULL pointer.
270 _dbus_condvar_wait (DBusCondVar *cond,
273 if (cond && mutex && thread_functions.condvar_wait)
274 (* thread_functions.condvar_wait) (cond, mutex);
278 * Atomically unlocks the mutex and waits for the conditions
279 * variable to be signalled, or for a timeout. Locks the
280 * mutex again before returning.
281 * Does nothing if passed a #NULL pointer.
283 * @param cond the condition variable
284 * @param mutex the mutex
285 * @param timeout_milliseconds the maximum time to wait
286 * @returns TRUE if the condition was reached, or FALSE if the
287 * timeout was reached.
290 _dbus_condvar_wait_timeout (DBusCondVar *cond,
292 int timeout_milliseconds)
294 if (cond && mutex && thread_functions.condvar_wait)
295 return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds);
301 * If there are threads waiting on the condition variable, wake
303 * Does nothing if passed a #NULL pointer.
306 _dbus_condvar_wake_one (DBusCondVar *cond)
308 if (cond && thread_functions.condvar_wake_one)
309 (* thread_functions.condvar_wake_one) (cond);
313 * If there are threads waiting on the condition variable, wake
315 * Does nothing if passed a #NULL pointer.
318 _dbus_condvar_wake_all (DBusCondVar *cond)
320 if (cond && thread_functions.condvar_wake_all)
321 (* thread_functions.condvar_wake_all) (cond);
325 shutdown_global_locks (void *data)
327 DBusMutex ***locks = data;
331 while (i < _DBUS_N_GLOBAL_LOCKS)
333 _dbus_mutex_free (*(locks[i]));
342 shutdown_uninitialized_locks (void *data)
344 _dbus_list_clear (&uninitialized_mutex_list);
345 _dbus_list_clear (&uninitialized_condvar_list);
349 init_uninitialized_locks (void)
353 _dbus_assert (thread_init_generation == 0);
355 link = uninitialized_mutex_list;
360 mp = (DBusMutex **)link->data;
361 _dbus_assert (*mp == _DBUS_DUMMY_MUTEX);
363 *mp = _dbus_mutex_new ();
367 link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
370 link = uninitialized_condvar_list;
375 cp = (DBusCondVar **)link->data;
376 _dbus_assert (*cp == _DBUS_DUMMY_CONDVAR);
378 *cp = _dbus_condvar_new ();
382 link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
385 _dbus_list_clear (&uninitialized_mutex_list);
386 _dbus_list_clear (&uninitialized_condvar_list);
388 if (!_dbus_register_shutdown_func (shutdown_uninitialized_locks,
395 link = uninitialized_condvar_list;
400 cp = (DBusCondVar **)link->data;
402 if (*cp != _DBUS_DUMMY_CONDVAR)
403 _dbus_condvar_free (*cp);
407 *cp = _DBUS_DUMMY_CONDVAR;
409 link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
413 link = uninitialized_mutex_list;
418 mp = (DBusMutex **)link->data;
420 if (*mp != _DBUS_DUMMY_MUTEX)
421 _dbus_mutex_free (*mp);
425 *mp = _DBUS_DUMMY_MUTEX;
427 link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
437 DBusMutex ***dynamic_global_locks;
439 DBusMutex **global_locks[] = {
440 #define LOCK_ADDR(name) (& _dbus_lock_##name)
442 LOCK_ADDR (sid_atom_cache),
444 LOCK_ADDR (connection_slots),
445 LOCK_ADDR (pending_call_slots),
446 LOCK_ADDR (server_slots),
447 LOCK_ADDR (message_slots),
450 LOCK_ADDR (shutdown_funcs),
451 LOCK_ADDR (system_users),
452 LOCK_ADDR (message_cache),
453 LOCK_ADDR (shared_connections)
457 _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
458 _DBUS_N_GLOBAL_LOCKS);
462 dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
463 if (dynamic_global_locks == NULL)
466 while (i < _DBUS_N_ELEMENTS (global_locks))
468 *global_locks[i] = _dbus_mutex_new ();
470 if (*global_locks[i] == NULL)
473 dynamic_global_locks[i] = global_locks[i];
478 if (!_dbus_register_shutdown_func (shutdown_global_locks,
479 dynamic_global_locks))
482 if (!init_uninitialized_locks ())
488 dbus_free (dynamic_global_locks);
490 for (i = i - 1; i >= 0; i--)
492 _dbus_mutex_free (*global_locks[i]);
493 *global_locks[i] = NULL;
498 /** @} */ /* end of internals */
501 * @defgroup DBusThreads Thread functions
503 * @brief dbus_threads_init()
505 * Functions and macros related to threads and thread locks.
512 * Initializes threads. If this function is not called,
513 * the D-Bus library will not lock any data structures.
514 * If it is called, D-Bus will do locking, at some cost
515 * in efficiency. Note that this function must be called
516 * BEFORE the second thread is started.
518 * Use dbus_threads_init_default() if you don't need a
519 * particular thread implementation.
521 * This function may be called more than once. The first
524 * @param functions functions for using threads
525 * @returns #TRUE on success, #FALSE if no memory
528 dbus_threads_init (const DBusThreadFunctions *functions)
530 dbus_bool_t mutex_set;
531 dbus_bool_t recursive_mutex_set;
533 _dbus_assert (functions != NULL);
535 /* these base functions are required. Future additions to
536 * DBusThreadFunctions may be optional.
538 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK);
539 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK);
540 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK);
541 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK);
542 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK);
543 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK);
544 _dbus_assert (functions->condvar_new != NULL);
545 _dbus_assert (functions->condvar_free != NULL);
546 _dbus_assert (functions->condvar_wait != NULL);
547 _dbus_assert (functions->condvar_wait_timeout != NULL);
548 _dbus_assert (functions->condvar_wake_one != NULL);
549 _dbus_assert (functions->condvar_wake_all != NULL);
551 /* Either the mutex function set or recursive mutex set needs
552 * to be available but not both
554 mutex_set = (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK) &&
555 (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK) &&
556 (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK) &&
557 (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK) &&
558 functions->mutex_new &&
559 functions->mutex_free &&
560 functions->mutex_lock &&
561 functions->mutex_unlock;
563 recursive_mutex_set =
564 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK) &&
565 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK) &&
566 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK) &&
567 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK) &&
568 functions->recursive_mutex_new &&
569 functions->recursive_mutex_free &&
570 functions->recursive_mutex_lock &&
571 functions->recursive_mutex_unlock;
573 if (!(mutex_set || recursive_mutex_set))
574 _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex "
575 "functions sets should be passed into "
576 "dbus_threads_init. Neither sets were passed.");
578 if (mutex_set && recursive_mutex_set)
579 _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex "
580 "functions sets should be passed into "
581 "dbus_threads_init. Both sets were passed. "
582 "You most likely just want to set the recursive "
583 "mutex functions to avoid deadlocks in D-Bus.");
585 /* Check that all bits in the mask actually are valid mask bits.
586 * ensures people won't write code that breaks when we add
589 _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
591 if (thread_init_generation != _dbus_current_generation)
592 thread_functions.mask = 0; /* allow re-init in new generation */
594 /* Silently allow multiple init
595 * First init wins and D-Bus will always use its threading system
597 if (thread_functions.mask != 0)
600 thread_functions.mutex_new = functions->mutex_new;
601 thread_functions.mutex_free = functions->mutex_free;
602 thread_functions.mutex_lock = functions->mutex_lock;
603 thread_functions.mutex_unlock = functions->mutex_unlock;
605 thread_functions.condvar_new = functions->condvar_new;
606 thread_functions.condvar_free = functions->condvar_free;
607 thread_functions.condvar_wait = functions->condvar_wait;
608 thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
609 thread_functions.condvar_wake_one = functions->condvar_wake_one;
610 thread_functions.condvar_wake_all = functions->condvar_wake_all;
612 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK)
613 thread_functions.recursive_mutex_new = functions->recursive_mutex_new;
615 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK)
616 thread_functions.recursive_mutex_free = functions->recursive_mutex_free;
618 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK)
619 thread_functions.recursive_mutex_lock = functions->recursive_mutex_lock;
621 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK)
622 thread_functions.recursive_mutex_unlock = functions->recursive_mutex_unlock;
624 thread_functions.mask = functions->mask;
629 thread_init_generation = _dbus_current_generation;
636 /* Default thread implemenation */
638 static DBusMutex* _dbus_internal_mutex_new (void);
639 static void _dbus_internal_mutex_free (DBusMutex *mutex);
640 static dbus_bool_t _dbus_internal_mutex_lock (DBusMutex *mutex);
641 static dbus_bool_t _dbus_internal_mutex_unlock (DBusMutex *mutex);
642 static DBusCondVar *_dbus_internal_condvar_new (void);
643 static void _dbus_internal_condvar_free (DBusCondVar *cond);
644 static void _dbus_internal_condvar_wait (DBusCondVar *cond,
646 static dbus_bool_t _dbus_internal_condvar_wait_timeout (DBusCondVar *cond,
648 int timeout_milliseconds);
649 static void _dbus_internal_condvar_wake_one (DBusCondVar *cond);
650 static void _dbus_internal_condvar_wake_all (DBusCondVar *cond);
652 #ifdef USE_WIN32_THREADS
654 BOOL WINAPI DllMain (HINSTANCE hinstDLL,
658 /* We need this to free the TLS events on thread exit */
660 DllMain (HINSTANCE hinstDLL,
667 case DLL_THREAD_DETACH:
668 if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
670 event = TlsGetValue(dbus_cond_event_tls);
672 TlsSetValue(dbus_cond_event_tls, NULL);
675 case DLL_PROCESS_DETACH:
676 if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
678 event = TlsGetValue(dbus_cond_event_tls);
680 TlsSetValue(dbus_cond_event_tls, NULL);
682 TlsFree(dbus_cond_event_tls);
692 _dbus_internal_mutex_new (void)
695 handle = CreateMutex (NULL, FALSE, NULL);
696 return (DBusMutex *) handle;
700 _dbus_internal_mutex_free (DBusMutex *mutex)
702 CloseHandle ((HANDLE *) mutex);
706 _dbus_internal_mutex_lock (DBusMutex *mutex)
708 return WaitForSingleObject ((HANDLE *) mutex, INFINITE) != WAIT_FAILED;
712 _dbus_internal_mutex_unlock (DBusMutex *mutex)
714 return ReleaseMutex ((HANDLE *) mutex) != 0;
718 _dbus_internal_condvar_new (void)
722 cond = dbus_new (DBusCondVar, 1);
728 InitializeCriticalSection (&cond->lock);
729 return (DBusCondVar *) cond;
733 _dbus_internal_condvar_free (DBusCondVar *cond)
735 DeleteCriticalSection (&cond->lock);
736 _dbus_list_clear (&cond->list);
741 _dbus_condvar_wait_win32 (DBusCondVar *cond,
747 HANDLE event = TlsGetValue (dbus_cond_event_tls);
751 event = CreateEvent (0, FALSE, FALSE, NULL);
754 TlsSetValue (dbus_cond_event_tls, event);
757 EnterCriticalSection (&cond->lock);
759 /* The event must not be signaled. Check this */
760 _dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT);
762 ret = _dbus_list_append (&cond->list, event);
764 LeaveCriticalSection (&cond->lock);
767 return FALSE; /* Prepend failed */
769 _dbus_mutex_unlock (mutex);
770 retval = WaitForSingleObject (event, milliseconds);
771 _dbus_mutex_lock (mutex);
773 if (retval == WAIT_TIMEOUT)
775 EnterCriticalSection (&cond->lock);
776 _dbus_list_remove (&cond->list, event);
778 /* In the meantime we could have been signaled, so we must again
779 * wait for the signal, this time with no timeout, to reset
780 * it. retval is set again to honour the late arrival of the
782 retval = WaitForSingleObject (event, 0);
784 LeaveCriticalSection (&cond->lock);
787 #ifndef DBUS_DISABLE_ASSERT
788 EnterCriticalSection (&cond->lock);
790 /* Now event must not be inside the array, check this */
791 _dbus_assert (_dbus_list_remove (cond->list, event) == FALSE);
793 LeaveCriticalSection (&cond->lock);
794 #endif /* !G_DISABLE_ASSERT */
796 return retval != WAIT_TIMEOUT;
800 _dbus_internal_condvar_wait (DBusCondVar *cond,
803 _dbus_condvar_wait_win32 (cond, mutex, INFINITE);
807 _dbus_internal_condvar_wait_timeout (DBusCondVar *cond,
809 int timeout_milliseconds)
811 return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds);
815 _dbus_internal_condvar_wake_one (DBusCondVar *cond)
817 EnterCriticalSection (&cond->lock);
819 if (cond->list != NULL)
820 SetEvent (_dbus_list_pop_first (&cond->list));
822 LeaveCriticalSection (&cond->lock);
826 _dbus_internal_condvar_wake_all (DBusCondVar *cond)
828 EnterCriticalSection (&cond->lock);
830 while (cond->list != NULL)
831 SetEvent (_dbus_list_pop_first (&cond->list));
833 LeaveCriticalSection (&cond->lock);
837 #else /* Posix threads */
840 _dbus_internal_mutex_new (void)
842 pthread_mutex_t *retval;
844 retval = dbus_new (pthread_mutex_t, 1);
848 if (pthread_mutex_init (retval, NULL))
853 return (DBusMutex *) retval;
857 _dbus_internal_mutex_free (DBusMutex *mutex)
859 pthread_mutex_destroy ((pthread_mutex_t *) mutex);
864 _dbus_internal_mutex_lock (DBusMutex *mutex)
866 return pthread_mutex_lock ((pthread_mutex_t *) mutex) == 0;
870 _dbus_internal_mutex_unlock (DBusMutex *mutex)
872 return pthread_mutex_unlock ((pthread_mutex_t *) mutex) == 0;
876 _dbus_internal_condvar_new (void)
878 pthread_cond_t *retval;
880 retval = dbus_new (pthread_cond_t, 1);
884 if (pthread_cond_init (retval, NULL))
889 return (DBusCondVar *) retval;
893 _dbus_internal_condvar_free (DBusCondVar *cond)
895 pthread_cond_destroy ((pthread_cond_t *) cond);
900 _dbus_internal_condvar_wait (DBusCondVar *cond,
903 pthread_cond_wait ((pthread_cond_t *)cond,
904 (pthread_mutex_t *) mutex);
908 _dbus_internal_condvar_wait_timeout (DBusCondVar *cond,
910 int timeout_milliseconds)
912 struct timeval time_now;
913 struct timespec end_time;
916 gettimeofday (&time_now, NULL);
918 end_time.tv_sec = time_now.tv_sec + timeout_milliseconds / 1000;
919 end_time.tv_nsec = (time_now.tv_usec + (timeout_milliseconds % 1000) * 1000) * 1000;
920 if (end_time.tv_nsec > 1000*1000*1000)
922 end_time.tv_sec += 1;
923 end_time.tv_nsec -= 1000*1000*1000;
926 result = pthread_cond_timedwait ((pthread_cond_t *) cond,
927 (pthread_mutex_t *) mutex,
929 return result == ETIMEDOUT;
933 _dbus_internal_condvar_wake_one (DBusCondVar *cond)
935 pthread_cond_signal ((pthread_cond_t *)cond);
939 _dbus_internal_condvar_wake_all (DBusCondVar *cond)
941 pthread_cond_broadcast ((pthread_cond_t *)cond);
946 static const DBusThreadFunctions internal_functions =
948 DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
949 DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
950 DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
951 DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
952 DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
953 DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
954 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
955 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
956 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
957 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
958 _dbus_internal_mutex_new,
959 _dbus_internal_mutex_free,
960 _dbus_internal_mutex_lock,
961 _dbus_internal_mutex_unlock,
962 _dbus_internal_condvar_new,
963 _dbus_internal_condvar_free,
964 _dbus_internal_condvar_wait,
965 _dbus_internal_condvar_wait_timeout,
966 _dbus_internal_condvar_wake_one,
967 _dbus_internal_condvar_wake_all
972 * Initializes threads. If this function is not called,
973 * the D-Bus library will not lock any data structures.
974 * If it is called, D-Bus will do locking, at some cost
975 * in efficiency. Note that this function must be called
976 * BEFORE the second thread is started.
978 * This function may be called more than once. The first
981 * @returns #TRUE on success, #FALSE if no memory
984 dbus_threads_init_default (void)
986 #ifdef USE_WIN32_THREADS
987 /* We reuse this over several generations, because we can't
988 * free the events once they are in use
990 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
992 dbus_cond_event_tls = TlsAlloc ();
993 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
998 return dbus_threads_init (&internal_functions);
1004 #ifdef DBUS_BUILD_TESTS
1005 /** Fake mutex used for debugging */
1006 typedef struct DBusFakeMutex DBusFakeMutex;
1007 /** Fake mutex used for debugging */
1008 struct DBusFakeMutex
1010 dbus_bool_t locked; /**< Mutex is "locked" */
1013 static DBusMutex * dbus_fake_mutex_new (void);
1014 static void dbus_fake_mutex_free (DBusMutex *mutex);
1015 static dbus_bool_t dbus_fake_mutex_lock (DBusMutex *mutex);
1016 static dbus_bool_t dbus_fake_mutex_unlock (DBusMutex *mutex);
1017 static DBusCondVar* dbus_fake_condvar_new (void);
1018 static void dbus_fake_condvar_free (DBusCondVar *cond);
1019 static void dbus_fake_condvar_wait (DBusCondVar *cond,
1021 static dbus_bool_t dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
1024 static void dbus_fake_condvar_wake_one (DBusCondVar *cond);
1025 static void dbus_fake_condvar_wake_all (DBusCondVar *cond);
1028 static const DBusThreadFunctions fake_functions =
1030 DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
1031 DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
1032 DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
1033 DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
1034 DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
1035 DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
1036 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
1037 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
1038 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
1039 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
1040 dbus_fake_mutex_new,
1041 dbus_fake_mutex_free,
1042 dbus_fake_mutex_lock,
1043 dbus_fake_mutex_unlock,
1044 dbus_fake_condvar_new,
1045 dbus_fake_condvar_free,
1046 dbus_fake_condvar_wait,
1047 dbus_fake_condvar_wait_timeout,
1048 dbus_fake_condvar_wake_one,
1049 dbus_fake_condvar_wake_all
1053 dbus_fake_mutex_new (void)
1055 DBusFakeMutex *mutex;
1057 mutex = dbus_new0 (DBusFakeMutex, 1);
1059 return (DBusMutex *)mutex;
1063 dbus_fake_mutex_free (DBusMutex *mutex)
1065 DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
1067 _dbus_assert (!fake->locked);
1073 dbus_fake_mutex_lock (DBusMutex *mutex)
1075 DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
1077 _dbus_assert (!fake->locked);
1079 fake->locked = TRUE;
1085 dbus_fake_mutex_unlock (DBusMutex *mutex)
1087 DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
1089 _dbus_assert (fake->locked);
1091 fake->locked = FALSE;
1097 dbus_fake_condvar_new (void)
1099 return (DBusCondVar*) _dbus_strdup ("FakeCondvar");
1103 dbus_fake_condvar_free (DBusCondVar *cond)
1109 dbus_fake_condvar_wait (DBusCondVar *cond,
1116 dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
1124 dbus_fake_condvar_wake_one (DBusCondVar *cond)
1130 dbus_fake_condvar_wake_all (DBusCondVar *cond)
1136 _dbus_threads_init_debug (void)
1138 return dbus_threads_init (&fake_functions);
1141 #endif /* DBUS_BUILD_TESTS */