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),
454 LOCK_ADDR (machine_uuid)
458 _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
459 _DBUS_N_GLOBAL_LOCKS);
463 dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
464 if (dynamic_global_locks == NULL)
467 while (i < _DBUS_N_ELEMENTS (global_locks))
469 *global_locks[i] = _dbus_mutex_new ();
471 if (*global_locks[i] == NULL)
474 dynamic_global_locks[i] = global_locks[i];
479 if (!_dbus_register_shutdown_func (shutdown_global_locks,
480 dynamic_global_locks))
483 if (!init_uninitialized_locks ())
489 dbus_free (dynamic_global_locks);
491 for (i = i - 1; i >= 0; i--)
493 _dbus_mutex_free (*global_locks[i]);
494 *global_locks[i] = NULL;
499 /** @} */ /* end of internals */
502 * @defgroup DBusThreads Thread functions
504 * @brief dbus_threads_init() and dbus_threads_init_default()
506 * Functions and macros related to threads and thread locks.
508 * If threads are initialized, the D-Bus library has locks on all
509 * global data structures. In addition, each #DBusConnection has a
510 * lock, so only one thread at a time can touch the connection. (See
511 * @ref DBusConnection for more on connection locking.)
513 * Most other objects, however, do not have locks - they can only be
514 * used from a single thread at a time, unless you lock them yourself.
515 * For example, a #DBusMessage can't be modified from two threads
523 * Initializes threads. If this function is not called,
524 * the D-Bus library will not lock any data structures.
525 * If it is called, D-Bus will do locking, at some cost
526 * in efficiency. Note that this function must be called
527 * BEFORE the second thread is started.
529 * Use dbus_threads_init_default() if you don't need a
530 * particular thread implementation.
532 * This function may be called more than once. The first
535 * @param functions functions for using threads
536 * @returns #TRUE on success, #FALSE if no memory
539 dbus_threads_init (const DBusThreadFunctions *functions)
541 dbus_bool_t mutex_set;
542 dbus_bool_t recursive_mutex_set;
544 _dbus_assert (functions != NULL);
546 /* these base functions are required. Future additions to
547 * DBusThreadFunctions may be optional.
549 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK);
550 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK);
551 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK);
552 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK);
553 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK);
554 _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK);
555 _dbus_assert (functions->condvar_new != NULL);
556 _dbus_assert (functions->condvar_free != NULL);
557 _dbus_assert (functions->condvar_wait != NULL);
558 _dbus_assert (functions->condvar_wait_timeout != NULL);
559 _dbus_assert (functions->condvar_wake_one != NULL);
560 _dbus_assert (functions->condvar_wake_all != NULL);
562 /* Either the mutex function set or recursive mutex set needs
563 * to be available but not both
565 mutex_set = (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK) &&
566 (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK) &&
567 (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK) &&
568 (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK) &&
569 functions->mutex_new &&
570 functions->mutex_free &&
571 functions->mutex_lock &&
572 functions->mutex_unlock;
574 recursive_mutex_set =
575 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK) &&
576 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK) &&
577 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK) &&
578 (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK) &&
579 functions->recursive_mutex_new &&
580 functions->recursive_mutex_free &&
581 functions->recursive_mutex_lock &&
582 functions->recursive_mutex_unlock;
584 if (!(mutex_set || recursive_mutex_set))
585 _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex "
586 "functions sets should be passed into "
587 "dbus_threads_init. Neither sets were passed.");
589 if (mutex_set && recursive_mutex_set)
590 _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex "
591 "functions sets should be passed into "
592 "dbus_threads_init. Both sets were passed. "
593 "You most likely just want to set the recursive "
594 "mutex functions to avoid deadlocks in D-Bus.");
596 /* Check that all bits in the mask actually are valid mask bits.
597 * ensures people won't write code that breaks when we add
600 _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
602 if (thread_init_generation != _dbus_current_generation)
603 thread_functions.mask = 0; /* allow re-init in new generation */
605 /* Silently allow multiple init
606 * First init wins and D-Bus will always use its threading system
608 if (thread_functions.mask != 0)
611 thread_functions.mutex_new = functions->mutex_new;
612 thread_functions.mutex_free = functions->mutex_free;
613 thread_functions.mutex_lock = functions->mutex_lock;
614 thread_functions.mutex_unlock = functions->mutex_unlock;
616 thread_functions.condvar_new = functions->condvar_new;
617 thread_functions.condvar_free = functions->condvar_free;
618 thread_functions.condvar_wait = functions->condvar_wait;
619 thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
620 thread_functions.condvar_wake_one = functions->condvar_wake_one;
621 thread_functions.condvar_wake_all = functions->condvar_wake_all;
623 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK)
624 thread_functions.recursive_mutex_new = functions->recursive_mutex_new;
626 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK)
627 thread_functions.recursive_mutex_free = functions->recursive_mutex_free;
629 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK)
630 thread_functions.recursive_mutex_lock = functions->recursive_mutex_lock;
632 if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK)
633 thread_functions.recursive_mutex_unlock = functions->recursive_mutex_unlock;
635 thread_functions.mask = functions->mask;
640 thread_init_generation = _dbus_current_generation;
647 /* Default thread implemenation */
649 static DBusMutex* _dbus_internal_mutex_new (void);
650 static void _dbus_internal_mutex_free (DBusMutex *mutex);
651 static dbus_bool_t _dbus_internal_mutex_lock (DBusMutex *mutex);
652 static dbus_bool_t _dbus_internal_mutex_unlock (DBusMutex *mutex);
653 static DBusCondVar *_dbus_internal_condvar_new (void);
654 static void _dbus_internal_condvar_free (DBusCondVar *cond);
655 static void _dbus_internal_condvar_wait (DBusCondVar *cond,
657 static dbus_bool_t _dbus_internal_condvar_wait_timeout (DBusCondVar *cond,
659 int timeout_milliseconds);
660 static void _dbus_internal_condvar_wake_one (DBusCondVar *cond);
661 static void _dbus_internal_condvar_wake_all (DBusCondVar *cond);
663 #ifdef USE_WIN32_THREADS
665 BOOL WINAPI DllMain (HINSTANCE hinstDLL,
669 /* We need this to free the TLS events on thread exit */
671 DllMain (HINSTANCE hinstDLL,
678 case DLL_THREAD_DETACH:
679 if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
681 event = TlsGetValue(dbus_cond_event_tls);
683 TlsSetValue(dbus_cond_event_tls, NULL);
686 case DLL_PROCESS_DETACH:
687 if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
689 event = TlsGetValue(dbus_cond_event_tls);
691 TlsSetValue(dbus_cond_event_tls, NULL);
693 TlsFree(dbus_cond_event_tls);
703 _dbus_internal_mutex_new (void)
706 handle = CreateMutex (NULL, FALSE, NULL);
707 return (DBusMutex *) handle;
711 _dbus_internal_mutex_free (DBusMutex *mutex)
713 CloseHandle ((HANDLE *) mutex);
717 _dbus_internal_mutex_lock (DBusMutex *mutex)
719 return WaitForSingleObject ((HANDLE *) mutex, INFINITE) != WAIT_FAILED;
723 _dbus_internal_mutex_unlock (DBusMutex *mutex)
725 return ReleaseMutex ((HANDLE *) mutex) != 0;
729 _dbus_internal_condvar_new (void)
733 cond = dbus_new (DBusCondVar, 1);
739 InitializeCriticalSection (&cond->lock);
740 return (DBusCondVar *) cond;
744 _dbus_internal_condvar_free (DBusCondVar *cond)
746 DeleteCriticalSection (&cond->lock);
747 _dbus_list_clear (&cond->list);
752 _dbus_condvar_wait_win32 (DBusCondVar *cond,
758 HANDLE event = TlsGetValue (dbus_cond_event_tls);
762 event = CreateEvent (0, FALSE, FALSE, NULL);
765 TlsSetValue (dbus_cond_event_tls, event);
768 EnterCriticalSection (&cond->lock);
770 /* The event must not be signaled. Check this */
771 _dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT);
773 ret = _dbus_list_append (&cond->list, event);
775 LeaveCriticalSection (&cond->lock);
778 return FALSE; /* Prepend failed */
780 _dbus_mutex_unlock (mutex);
781 retval = WaitForSingleObject (event, milliseconds);
782 _dbus_mutex_lock (mutex);
784 if (retval == WAIT_TIMEOUT)
786 EnterCriticalSection (&cond->lock);
787 _dbus_list_remove (&cond->list, event);
789 /* In the meantime we could have been signaled, so we must again
790 * wait for the signal, this time with no timeout, to reset
791 * it. retval is set again to honour the late arrival of the
793 retval = WaitForSingleObject (event, 0);
795 LeaveCriticalSection (&cond->lock);
798 #ifndef DBUS_DISABLE_ASSERT
799 EnterCriticalSection (&cond->lock);
801 /* Now event must not be inside the array, check this */
802 _dbus_assert (_dbus_list_remove (cond->list, event) == FALSE);
804 LeaveCriticalSection (&cond->lock);
805 #endif /* !G_DISABLE_ASSERT */
807 return retval != WAIT_TIMEOUT;
811 _dbus_internal_condvar_wait (DBusCondVar *cond,
814 _dbus_condvar_wait_win32 (cond, mutex, INFINITE);
818 _dbus_internal_condvar_wait_timeout (DBusCondVar *cond,
820 int timeout_milliseconds)
822 return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds);
826 _dbus_internal_condvar_wake_one (DBusCondVar *cond)
828 EnterCriticalSection (&cond->lock);
830 if (cond->list != NULL)
831 SetEvent (_dbus_list_pop_first (&cond->list));
833 LeaveCriticalSection (&cond->lock);
837 _dbus_internal_condvar_wake_all (DBusCondVar *cond)
839 EnterCriticalSection (&cond->lock);
841 while (cond->list != NULL)
842 SetEvent (_dbus_list_pop_first (&cond->list));
844 LeaveCriticalSection (&cond->lock);
848 #else /* Posix threads */
851 _dbus_internal_mutex_new (void)
853 pthread_mutex_t *retval;
855 retval = dbus_new (pthread_mutex_t, 1);
859 if (pthread_mutex_init (retval, NULL))
864 return (DBusMutex *) retval;
868 _dbus_internal_mutex_free (DBusMutex *mutex)
870 pthread_mutex_destroy ((pthread_mutex_t *) mutex);
875 _dbus_internal_mutex_lock (DBusMutex *mutex)
877 return pthread_mutex_lock ((pthread_mutex_t *) mutex) == 0;
881 _dbus_internal_mutex_unlock (DBusMutex *mutex)
883 return pthread_mutex_unlock ((pthread_mutex_t *) mutex) == 0;
887 _dbus_internal_condvar_new (void)
889 pthread_cond_t *retval;
891 retval = dbus_new (pthread_cond_t, 1);
895 if (pthread_cond_init (retval, NULL))
900 return (DBusCondVar *) retval;
904 _dbus_internal_condvar_free (DBusCondVar *cond)
906 pthread_cond_destroy ((pthread_cond_t *) cond);
911 _dbus_internal_condvar_wait (DBusCondVar *cond,
914 pthread_cond_wait ((pthread_cond_t *)cond,
915 (pthread_mutex_t *) mutex);
919 _dbus_internal_condvar_wait_timeout (DBusCondVar *cond,
921 int timeout_milliseconds)
923 struct timeval time_now;
924 struct timespec end_time;
927 gettimeofday (&time_now, NULL);
929 end_time.tv_sec = time_now.tv_sec + timeout_milliseconds / 1000;
930 end_time.tv_nsec = (time_now.tv_usec + (timeout_milliseconds % 1000) * 1000) * 1000;
931 if (end_time.tv_nsec > 1000*1000*1000)
933 end_time.tv_sec += 1;
934 end_time.tv_nsec -= 1000*1000*1000;
937 result = pthread_cond_timedwait ((pthread_cond_t *) cond,
938 (pthread_mutex_t *) mutex,
940 return result == ETIMEDOUT;
944 _dbus_internal_condvar_wake_one (DBusCondVar *cond)
946 pthread_cond_signal ((pthread_cond_t *)cond);
950 _dbus_internal_condvar_wake_all (DBusCondVar *cond)
952 pthread_cond_broadcast ((pthread_cond_t *)cond);
957 static const DBusThreadFunctions internal_functions =
959 DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
960 DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
961 DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
962 DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
963 DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
964 DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
965 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
966 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
967 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
968 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
969 _dbus_internal_mutex_new,
970 _dbus_internal_mutex_free,
971 _dbus_internal_mutex_lock,
972 _dbus_internal_mutex_unlock,
973 _dbus_internal_condvar_new,
974 _dbus_internal_condvar_free,
975 _dbus_internal_condvar_wait,
976 _dbus_internal_condvar_wait_timeout,
977 _dbus_internal_condvar_wake_one,
978 _dbus_internal_condvar_wake_all
983 * Calls dbus_threads_init() with a default set of
984 * #DBusThreadFunctions appropriate for the platform.
986 * @returns #TRUE on success, #FALSE if not enough memory
989 dbus_threads_init_default (void)
991 #ifdef USE_WIN32_THREADS
992 /* We reuse this over several generations, because we can't
993 * free the events once they are in use
995 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
997 dbus_cond_event_tls = TlsAlloc ();
998 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
1003 return dbus_threads_init (&internal_functions);
1009 #ifdef DBUS_BUILD_TESTS
1010 /** Fake mutex used for debugging */
1011 typedef struct DBusFakeMutex DBusFakeMutex;
1012 /** Fake mutex used for debugging */
1013 struct DBusFakeMutex
1015 dbus_bool_t locked; /**< Mutex is "locked" */
1018 static DBusMutex * dbus_fake_mutex_new (void);
1019 static void dbus_fake_mutex_free (DBusMutex *mutex);
1020 static dbus_bool_t dbus_fake_mutex_lock (DBusMutex *mutex);
1021 static dbus_bool_t dbus_fake_mutex_unlock (DBusMutex *mutex);
1022 static DBusCondVar* dbus_fake_condvar_new (void);
1023 static void dbus_fake_condvar_free (DBusCondVar *cond);
1024 static void dbus_fake_condvar_wait (DBusCondVar *cond,
1026 static dbus_bool_t dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
1029 static void dbus_fake_condvar_wake_one (DBusCondVar *cond);
1030 static void dbus_fake_condvar_wake_all (DBusCondVar *cond);
1033 static const DBusThreadFunctions fake_functions =
1035 DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
1036 DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
1037 DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
1038 DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
1039 DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
1040 DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
1041 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
1042 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
1043 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
1044 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
1045 dbus_fake_mutex_new,
1046 dbus_fake_mutex_free,
1047 dbus_fake_mutex_lock,
1048 dbus_fake_mutex_unlock,
1049 dbus_fake_condvar_new,
1050 dbus_fake_condvar_free,
1051 dbus_fake_condvar_wait,
1052 dbus_fake_condvar_wait_timeout,
1053 dbus_fake_condvar_wake_one,
1054 dbus_fake_condvar_wake_all
1058 dbus_fake_mutex_new (void)
1060 DBusFakeMutex *mutex;
1062 mutex = dbus_new0 (DBusFakeMutex, 1);
1064 return (DBusMutex *)mutex;
1068 dbus_fake_mutex_free (DBusMutex *mutex)
1070 DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
1072 _dbus_assert (!fake->locked);
1078 dbus_fake_mutex_lock (DBusMutex *mutex)
1080 DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
1082 _dbus_assert (!fake->locked);
1084 fake->locked = TRUE;
1090 dbus_fake_mutex_unlock (DBusMutex *mutex)
1092 DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
1094 _dbus_assert (fake->locked);
1096 fake->locked = FALSE;
1102 dbus_fake_condvar_new (void)
1104 return (DBusCondVar*) _dbus_strdup ("FakeCondvar");
1108 dbus_fake_condvar_free (DBusCondVar *cond)
1114 dbus_fake_condvar_wait (DBusCondVar *cond,
1121 dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
1129 dbus_fake_condvar_wake_one (DBusCondVar *cond)
1135 dbus_fake_condvar_wake_all (DBusCondVar *cond)
1141 _dbus_threads_init_debug (void)
1143 return dbus_threads_init (&fake_functions);
1146 #endif /* DBUS_BUILD_TESTS */