2006-10-26 Havoc Pennington <hp@redhat.com>

* dbus/dbus-threads.[hc]: Documentation improvements. Clarify how
	condition variables relate to recursive mutexes.

        * dbus/dbus-sysdeps-pthread.c, dbus/dbus-sysdeps-win-thread.c,
	dbus/dbus-threads.c: Split the platforms-specific thread
	implementations into their own files.

	* dbus/dbus-sysdeps-pthread.c
	(_dbus_pthread_condvar_wait_timeout): invert the return value, it
	was backward. Not that anything uses it.
This commit is contained in:
Havoc Pennington 2006-10-27 01:09:24 +00:00
parent caae991f97
commit 5886f5326d
9 changed files with 506 additions and 385 deletions

View file

@ -1,3 +1,16 @@
2006-10-26 Havoc Pennington <hp@redhat.com>
* dbus/dbus-threads.[hc]: Documentation improvements. Clarify how
condition variables relate to recursive mutexes.
* dbus/dbus-sysdeps-pthread.c, dbus/dbus-sysdeps-win-thread.c,
dbus/dbus-threads.c: Split the platforms-specific thread
implementations into their own files.
* dbus/dbus-sysdeps-pthread.c
(_dbus_pthread_condvar_wait_timeout): invert the return value, it
was backward. Not that anything uses it.
2006-10-26 John (J5) Palmieri <johnp@redhat.com>
* dbus-sysdeps-unix.c (_dbus_set_local_creds): Clean up the

View file

@ -113,6 +113,7 @@ DBUS_SHARED_SOURCES= \
dbus-string-private.h \
dbus-sysdeps.c \
dbus-sysdeps.h \
dbus-sysdeps-pthread.c \
dbus-sysdeps-unix.c \
dbus-sysdeps-unix.h \
dbus-userdb.c \

View file

@ -991,7 +991,7 @@ _dbus_connection_remove_pending_call (DBusConnection *connection,
*/
static dbus_bool_t
_dbus_connection_acquire_io_path (DBusConnection *connection,
int timeout_milliseconds)
int timeout_milliseconds)
{
dbus_bool_t we_acquired;
@ -1017,9 +1017,20 @@ _dbus_connection_acquire_io_path (DBusConnection *connection,
{
_dbus_verbose ("%s waiting %d for IO path to be acquirable\n",
_DBUS_FUNCTION_NAME, timeout_milliseconds);
_dbus_condvar_wait_timeout (connection->io_path_cond,
connection->io_path_mutex,
timeout_milliseconds);
if (!_dbus_condvar_wait_timeout (connection->io_path_cond,
connection->io_path_mutex,
timeout_milliseconds))
{
/* We timed out before anyone signaled. */
/* (writing the loop to handle the !timedout case by
* waiting longer if needed is a pain since dbus
* wraps pthread_cond_timedwait to take a relative
* time instead of absolute, something kind of stupid
* on our part. for now it doesn't matter, we will just
* end up back here eventually.)
*/
}
}
else
{

167
dbus/dbus-sysdeps-pthread.c Normal file
View file

@ -0,0 +1,167 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-sysdeps-pthread.c Implements threads using pthreads (internal to libdbus)
*
* Copyright (C) 2002, 2003, 2006 Red Hat, Inc.
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "dbus-internals.h"
#include "dbus-sysdeps.h"
#include "dbus-threads.h"
#include <sys/time.h>
#include <pthread.h>
static DBusMutex*
_dbus_pthread_mutex_new (void)
{
pthread_mutex_t *retval;
retval = dbus_new (pthread_mutex_t, 1);
if (retval == NULL)
return NULL;
if (pthread_mutex_init (retval, NULL))
{
dbus_free (retval);
return NULL;
}
return (DBusMutex *) retval;
}
static void
_dbus_pthread_mutex_free (DBusMutex *mutex)
{
pthread_mutex_destroy ((pthread_mutex_t *) mutex);
dbus_free (mutex);
}
static dbus_bool_t
_dbus_pthread_mutex_lock (DBusMutex *mutex)
{
return pthread_mutex_lock ((pthread_mutex_t *) mutex) == 0;
}
static dbus_bool_t
_dbus_pthread_mutex_unlock (DBusMutex *mutex)
{
return pthread_mutex_unlock ((pthread_mutex_t *) mutex) == 0;
}
static DBusCondVar *
_dbus_pthread_condvar_new (void)
{
pthread_cond_t *retval;
retval = dbus_new (pthread_cond_t, 1);
if (retval == NULL)
return NULL;
if (pthread_cond_init (retval, NULL))
{
dbus_free (retval);
return NULL;
}
return (DBusCondVar *) retval;
}
static void
_dbus_pthread_condvar_free (DBusCondVar *cond)
{
pthread_cond_destroy ((pthread_cond_t *) cond);
dbus_free (cond);
}
static void
_dbus_pthread_condvar_wait (DBusCondVar *cond,
DBusMutex *mutex)
{
pthread_cond_wait ((pthread_cond_t *)cond,
(pthread_mutex_t *) mutex);
}
static dbus_bool_t
_dbus_pthread_condvar_wait_timeout (DBusCondVar *cond,
DBusMutex *mutex,
int timeout_milliseconds)
{
struct timeval time_now;
struct timespec end_time;
int result;
gettimeofday (&time_now, NULL);
end_time.tv_sec = time_now.tv_sec + timeout_milliseconds / 1000;
end_time.tv_nsec = (time_now.tv_usec + (timeout_milliseconds % 1000) * 1000) * 1000;
if (end_time.tv_nsec > 1000*1000*1000)
{
end_time.tv_sec += 1;
end_time.tv_nsec -= 1000*1000*1000;
}
result = pthread_cond_timedwait ((pthread_cond_t *) cond,
(pthread_mutex_t *) mutex,
&end_time);
/* return true if we did not time out */
return result != ETIMEDOUT;
}
static void
_dbus_pthread_condvar_wake_one (DBusCondVar *cond)
{
pthread_cond_signal ((pthread_cond_t *)cond);
}
static void
_dbus_pthread_condvar_wake_all (DBusCondVar *cond)
{
pthread_cond_broadcast ((pthread_cond_t *)cond);
}
static const DBusThreadFunctions pthread_functions =
{
DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
_dbus_pthread_mutex_new,
_dbus_pthread_mutex_free,
_dbus_pthread_mutex_lock,
_dbus_pthread_mutex_unlock,
_dbus_pthread_condvar_new,
_dbus_pthread_condvar_free,
_dbus_pthread_condvar_wait,
_dbus_pthread_condvar_wait_timeout,
_dbus_pthread_condvar_wake_one,
_dbus_pthread_condvar_wake_all
};
dbus_bool_t
_dbus_threads_init_platform_specific (void)
{
return dbus_threads_init (&pthread_functions);
}

View file

@ -0,0 +1,259 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-sysdeps-pthread.c Implements threads using Windows threads (internal to libdbus)
*
* Copyright (C) 2006 Red Hat, Inc.
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "dbus-internals.h"
#include "dbus-sysdeps.h"
#include "dbus-threads.h"
#include <windows.h>
struct DBusCondVar {
DBusList *list; /**< list thread-local-stored events waiting on the cond variable */
CRITICAL_SECTION lock; /**< lock protecting the list */
};
static DWORD dbus_cond_event_tls = TLS_OUT_OF_INDEXES;
BOOL WINAPI DllMain (HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved);
/* We need this to free the TLS events on thread exit */
BOOL WINAPI
DllMain (HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
HANDLE event;
switch (fdwReason)
{
case DLL_THREAD_DETACH:
if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
{
event = TlsGetValue(dbus_cond_event_tls);
CloseHandle (event);
TlsSetValue(dbus_cond_event_tls, NULL);
}
break;
case DLL_PROCESS_DETACH:
if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
{
event = TlsGetValue(dbus_cond_event_tls);
CloseHandle (event);
TlsSetValue(dbus_cond_event_tls, NULL);
TlsFree(dbus_cond_event_tls);
}
break;
default:
break;
}
return TRUE;
}
static DBusMutex*
_dbus_windows_mutex_new (void)
{
HANDLE handle;
handle = CreateMutex (NULL, FALSE, NULL);
return (DBusMutex *) handle;
}
static void
_dbus_windows_mutex_free (DBusMutex *mutex)
{
CloseHandle ((HANDLE *) mutex);
}
static dbus_bool_t
_dbus_windows_mutex_lock (DBusMutex *mutex)
{
return WaitForSingleObject ((HANDLE *) mutex, INFINITE) != WAIT_FAILED;
}
static dbus_bool_t
_dbus_windows_mutex_unlock (DBusMutex *mutex)
{
return ReleaseMutex ((HANDLE *) mutex) != 0;
}
static DBusCondVar *
_dbus_windows_condvar_new (void)
{
DBusCondVar *cond;
cond = dbus_new (DBusCondVar, 1);
if (cond == NULL)
return NULL;
cond->list = NULL;
InitializeCriticalSection (&cond->lock);
return (DBusCondVar *) cond;
}
static void
_dbus_windows_condvar_free (DBusCondVar *cond)
{
DeleteCriticalSection (&cond->lock);
_dbus_list_clear (&cond->list);
dbus_free (cond);
}
static dbus_bool_t
_dbus_condvar_wait_win32 (DBusCondVar *cond,
DBusMutex *mutex,
int milliseconds)
{
DWORD retval;
dbus_bool_t ret;
HANDLE event = TlsGetValue (dbus_cond_event_tls);
if (!event)
{
event = CreateEvent (0, FALSE, FALSE, NULL);
if (event == 0)
return FALSE;
TlsSetValue (dbus_cond_event_tls, event);
}
EnterCriticalSection (&cond->lock);
/* The event must not be signaled. Check this */
_dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT);
ret = _dbus_list_append (&cond->list, event);
LeaveCriticalSection (&cond->lock);
if (!ret)
return FALSE; /* Prepend failed */
_dbus_mutex_unlock (mutex);
retval = WaitForSingleObject (event, milliseconds);
_dbus_mutex_lock (mutex);
if (retval == WAIT_TIMEOUT)
{
EnterCriticalSection (&cond->lock);
_dbus_list_remove (&cond->list, event);
/* In the meantime we could have been signaled, so we must again
* wait for the signal, this time with no timeout, to reset
* it. retval is set again to honour the late arrival of the
* signal */
retval = WaitForSingleObject (event, 0);
LeaveCriticalSection (&cond->lock);
}
#ifndef DBUS_DISABLE_ASSERT
EnterCriticalSection (&cond->lock);
/* Now event must not be inside the array, check this */
_dbus_assert (_dbus_list_remove (cond->list, event) == FALSE);
LeaveCriticalSection (&cond->lock);
#endif /* !G_DISABLE_ASSERT */
return retval != WAIT_TIMEOUT;
}
static void
_dbus_windows_condvar_wait (DBusCondVar *cond,
DBusMutex *mutex)
{
_dbus_condvar_wait_win32 (cond, mutex, INFINITE);
}
static dbus_bool_t
_dbus_windows_condvar_wait_timeout (DBusCondVar *cond,
DBusMutex *mutex,
int timeout_milliseconds)
{
return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds);
}
static void
_dbus_windows_condvar_wake_one (DBusCondVar *cond)
{
EnterCriticalSection (&cond->lock);
if (cond->list != NULL)
SetEvent (_dbus_list_pop_first (&cond->list));
LeaveCriticalSection (&cond->lock);
}
static void
_dbus_windows_condvar_wake_all (DBusCondVar *cond)
{
EnterCriticalSection (&cond->lock);
while (cond->list != NULL)
SetEvent (_dbus_list_pop_first (&cond->list));
LeaveCriticalSection (&cond->lock);
}
static const DBusThreadFunctions windows_functions =
{
DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
_dbus_windows_mutex_new,
_dbus_windows_mutex_free,
_dbus_windows_mutex_lock,
_dbus_windows_mutex_unlock,
_dbus_windows_condvar_new,
_dbus_windows_condvar_free,
_dbus_windows_condvar_wait,
_dbus_windows_condvar_wait_timeout,
_dbus_windows_condvar_wake_one,
_dbus_windows_condvar_wake_all
};
void
_dbus_threads_init_platform_specific (void)
{
/* We reuse this over several generations, because we can't
* free the events once they are in use
*/
if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
{
dbus_cond_event_tls = TlsAlloc ();
if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
return FALSE;
}
return dbus_threads_init (&windows_functions);
}

View file

@ -425,6 +425,12 @@ dbus_bool_t _dbus_read_local_machine_uuid (DBusGUID *machine_id,
dbus_bool_t create_if_not_found,
DBusError *error);
/**
* Initialize threads as in dbus_threads_init_default(), appropriately
* for the platform.
* @returns #FALSE if no memory
*/
dbus_bool_t _dbus_threads_init_platform_specific (void);
/** @} */

View file

@ -43,10 +43,10 @@ void _dbus_condvar_wait (DBusCondVar *cond,
dbus_bool_t _dbus_condvar_wait_timeout (DBusCondVar *cond,
DBusMutex *mutex,
int timeout_milliseconds);
void _dbus_condvar_wake_one (DBusCondVar *cond);
void _dbus_condvar_wake_all (DBusCondVar *cond);
void _dbus_condvar_new_at_location (DBusCondVar **location_p);
void _dbus_condvar_free_at_location (DBusCondVar **location_p);
void _dbus_condvar_wake_one (DBusCondVar *cond);
void _dbus_condvar_wake_all (DBusCondVar *cond);
void _dbus_condvar_new_at_location (DBusCondVar **location_p);
void _dbus_condvar_free_at_location (DBusCondVar **location_p);
DBUS_END_DECLS

View file

@ -1,7 +1,7 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-threads.h D-Bus threads handling
*
* Copyright (C) 2002, 2003 Red Hat Inc.
* Copyright (C) 2002, 2003, 2006 Red Hat Inc.
*
* Licensed under the Academic Free License version 2.1
*
@ -25,17 +25,6 @@
#include "dbus-threads-internal.h"
#include "dbus-list.h"
#if defined(__WIN32) || defined(__CYGWIN__)
#define USE_WIN32_THREADS
#endif
#ifdef USE_WIN32_THREADS
#include <windows.h>
#else
#include <sys/time.h>
#include <pthread.h>
#endif
static DBusThreadFunctions thread_functions =
{
0,
@ -46,15 +35,6 @@ static DBusThreadFunctions thread_functions =
NULL, NULL, NULL, NULL
};
#ifdef USE_WIN32_THREADS
struct DBusCondVar {
DBusList *list;
CRITICAL_SECTION lock;
};
static DWORD dbus_cond_event_tls = TLS_OUT_OF_INDEXES;
#endif
static int thread_init_generation = 0;
static DBusList *uninitialized_mutex_list = NULL;
@ -275,16 +255,15 @@ _dbus_condvar_wait (DBusCondVar *cond,
}
/**
* Atomically unlocks the mutex and waits for the conditions
* variable to be signalled, or for a timeout. Locks the
* mutex again before returning.
* Does nothing if passed a #NULL pointer.
* Atomically unlocks the mutex and waits for the conditions variable
* to be signalled, or for a timeout. Locks the mutex again before
* returning. Does nothing if passed a #NULL pointer. Return value
* is #FALSE if we timed out, #TRUE otherwise.
*
* @param cond the condition variable
* @param mutex the mutex
* @param timeout_milliseconds the maximum time to wait
* @returns TRUE if the condition was reached, or FALSE if the
* timeout was reached.
* @returns #FALSE if the timeout occurred, #TRUE if not
*/
dbus_bool_t
_dbus_condvar_wait_timeout (DBusCondVar *cond,
@ -672,338 +651,6 @@ dbus_threads_init (const DBusThreadFunctions *functions)
/* Default thread implemenation */
static DBusMutex* _dbus_internal_mutex_new (void);
static void _dbus_internal_mutex_free (DBusMutex *mutex);
static dbus_bool_t _dbus_internal_mutex_lock (DBusMutex *mutex);
static dbus_bool_t _dbus_internal_mutex_unlock (DBusMutex *mutex);
static DBusCondVar *_dbus_internal_condvar_new (void);
static void _dbus_internal_condvar_free (DBusCondVar *cond);
static void _dbus_internal_condvar_wait (DBusCondVar *cond,
DBusMutex *mutex);
static dbus_bool_t _dbus_internal_condvar_wait_timeout (DBusCondVar *cond,
DBusMutex *mutex,
int timeout_milliseconds);
static void _dbus_internal_condvar_wake_one (DBusCondVar *cond);
static void _dbus_internal_condvar_wake_all (DBusCondVar *cond);
#ifdef USE_WIN32_THREADS
BOOL WINAPI DllMain (HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved);
/* We need this to free the TLS events on thread exit */
BOOL WINAPI
DllMain (HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
HANDLE event;
switch (fdwReason)
{
case DLL_THREAD_DETACH:
if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
{
event = TlsGetValue(dbus_cond_event_tls);
CloseHandle (event);
TlsSetValue(dbus_cond_event_tls, NULL);
}
break;
case DLL_PROCESS_DETACH:
if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
{
event = TlsGetValue(dbus_cond_event_tls);
CloseHandle (event);
TlsSetValue(dbus_cond_event_tls, NULL);
TlsFree(dbus_cond_event_tls);
}
break;
default:
break;
}
return TRUE;
}
static DBusMutex*
_dbus_internal_mutex_new (void)
{
HANDLE handle;
handle = CreateMutex (NULL, FALSE, NULL);
return (DBusMutex *) handle;
}
static void
_dbus_internal_mutex_free (DBusMutex *mutex)
{
CloseHandle ((HANDLE *) mutex);
}
static dbus_bool_t
_dbus_internal_mutex_lock (DBusMutex *mutex)
{
return WaitForSingleObject ((HANDLE *) mutex, INFINITE) != WAIT_FAILED;
}
static dbus_bool_t
_dbus_internal_mutex_unlock (DBusMutex *mutex)
{
return ReleaseMutex ((HANDLE *) mutex) != 0;
}
static DBusCondVar *
_dbus_internal_condvar_new (void)
{
DBusCondVar *cond;
cond = dbus_new (DBusCondVar, 1);
if (cond == NULL)
return NULL;
cond->list = NULL;
InitializeCriticalSection (&cond->lock);
return (DBusCondVar *) cond;
}
static void
_dbus_internal_condvar_free (DBusCondVar *cond)
{
DeleteCriticalSection (&cond->lock);
_dbus_list_clear (&cond->list);
dbus_free (cond);
}
static dbus_bool_t
_dbus_condvar_wait_win32 (DBusCondVar *cond,
DBusMutex *mutex,
int milliseconds)
{
DWORD retval;
dbus_bool_t ret;
HANDLE event = TlsGetValue (dbus_cond_event_tls);
if (!event)
{
event = CreateEvent (0, FALSE, FALSE, NULL);
if (event == 0)
return FALSE;
TlsSetValue (dbus_cond_event_tls, event);
}
EnterCriticalSection (&cond->lock);
/* The event must not be signaled. Check this */
_dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT);
ret = _dbus_list_append (&cond->list, event);
LeaveCriticalSection (&cond->lock);
if (!ret)
return FALSE; /* Prepend failed */
_dbus_mutex_unlock (mutex);
retval = WaitForSingleObject (event, milliseconds);
_dbus_mutex_lock (mutex);
if (retval == WAIT_TIMEOUT)
{
EnterCriticalSection (&cond->lock);
_dbus_list_remove (&cond->list, event);
/* In the meantime we could have been signaled, so we must again
* wait for the signal, this time with no timeout, to reset
* it. retval is set again to honour the late arrival of the
* signal */
retval = WaitForSingleObject (event, 0);
LeaveCriticalSection (&cond->lock);
}
#ifndef DBUS_DISABLE_ASSERT
EnterCriticalSection (&cond->lock);
/* Now event must not be inside the array, check this */
_dbus_assert (_dbus_list_remove (cond->list, event) == FALSE);
LeaveCriticalSection (&cond->lock);
#endif /* !G_DISABLE_ASSERT */
return retval != WAIT_TIMEOUT;
}
static void
_dbus_internal_condvar_wait (DBusCondVar *cond,
DBusMutex *mutex)
{
_dbus_condvar_wait_win32 (cond, mutex, INFINITE);
}
static dbus_bool_t
_dbus_internal_condvar_wait_timeout (DBusCondVar *cond,
DBusMutex *mutex,
int timeout_milliseconds)
{
return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds);
}
static void
_dbus_internal_condvar_wake_one (DBusCondVar *cond)
{
EnterCriticalSection (&cond->lock);
if (cond->list != NULL)
SetEvent (_dbus_list_pop_first (&cond->list));
LeaveCriticalSection (&cond->lock);
}
static void
_dbus_internal_condvar_wake_all (DBusCondVar *cond)
{
EnterCriticalSection (&cond->lock);
while (cond->list != NULL)
SetEvent (_dbus_list_pop_first (&cond->list));
LeaveCriticalSection (&cond->lock);
}
#else /* Posix threads */
static DBusMutex*
_dbus_internal_mutex_new (void)
{
pthread_mutex_t *retval;
retval = dbus_new (pthread_mutex_t, 1);
if (retval == NULL)
return NULL;
if (pthread_mutex_init (retval, NULL))
{
dbus_free (retval);
return NULL;
}
return (DBusMutex *) retval;
}
static void
_dbus_internal_mutex_free (DBusMutex *mutex)
{
pthread_mutex_destroy ((pthread_mutex_t *) mutex);
dbus_free (mutex);
}
static dbus_bool_t
_dbus_internal_mutex_lock (DBusMutex *mutex)
{
return pthread_mutex_lock ((pthread_mutex_t *) mutex) == 0;
}
static dbus_bool_t
_dbus_internal_mutex_unlock (DBusMutex *mutex)
{
return pthread_mutex_unlock ((pthread_mutex_t *) mutex) == 0;
}
static DBusCondVar *
_dbus_internal_condvar_new (void)
{
pthread_cond_t *retval;
retval = dbus_new (pthread_cond_t, 1);
if (retval == NULL)
return NULL;
if (pthread_cond_init (retval, NULL))
{
dbus_free (retval);
return NULL;
}
return (DBusCondVar *) retval;
}
static void
_dbus_internal_condvar_free (DBusCondVar *cond)
{
pthread_cond_destroy ((pthread_cond_t *) cond);
dbus_free (cond);
}
static void
_dbus_internal_condvar_wait (DBusCondVar *cond,
DBusMutex *mutex)
{
pthread_cond_wait ((pthread_cond_t *)cond,
(pthread_mutex_t *) mutex);
}
static dbus_bool_t
_dbus_internal_condvar_wait_timeout (DBusCondVar *cond,
DBusMutex *mutex,
int timeout_milliseconds)
{
struct timeval time_now;
struct timespec end_time;
int result;
gettimeofday (&time_now, NULL);
end_time.tv_sec = time_now.tv_sec + timeout_milliseconds / 1000;
end_time.tv_nsec = (time_now.tv_usec + (timeout_milliseconds % 1000) * 1000) * 1000;
if (end_time.tv_nsec > 1000*1000*1000)
{
end_time.tv_sec += 1;
end_time.tv_nsec -= 1000*1000*1000;
}
result = pthread_cond_timedwait ((pthread_cond_t *) cond,
(pthread_mutex_t *) mutex,
&end_time);
return result == ETIMEDOUT;
}
static void
_dbus_internal_condvar_wake_one (DBusCondVar *cond)
{
pthread_cond_signal ((pthread_cond_t *)cond);
}
static void
_dbus_internal_condvar_wake_all (DBusCondVar *cond)
{
pthread_cond_broadcast ((pthread_cond_t *)cond);
}
#endif
static const DBusThreadFunctions internal_functions =
{
DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
_dbus_internal_mutex_new,
_dbus_internal_mutex_free,
_dbus_internal_mutex_lock,
_dbus_internal_mutex_unlock,
_dbus_internal_condvar_new,
_dbus_internal_condvar_free,
_dbus_internal_condvar_wait,
_dbus_internal_condvar_wait_timeout,
_dbus_internal_condvar_wake_one,
_dbus_internal_condvar_wake_all
};
/**
*
* Calls dbus_threads_init() with a default set of
@ -1022,19 +669,7 @@ static const DBusThreadFunctions internal_functions =
dbus_bool_t
dbus_threads_init_default (void)
{
#ifdef USE_WIN32_THREADS
/* We reuse this over several generations, because we can't
* free the events once they are in use
*/
if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
{
dbus_cond_event_tls = TlsAlloc ();
if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
return FALSE;
}
#endif
return dbus_threads_init (&internal_functions);
return _dbus_threads_init_platform_specific ();
}

View file

@ -46,13 +46,16 @@ typedef struct DBusCondVar DBusCondVar;
typedef DBusMutex* (* DBusMutexNewFunction) (void);
/** Deprecated, provide DBusRecursiveMutexFreeFunction instead. */
typedef void (* DBusMutexFreeFunction) (DBusMutex *mutex);
/** Deprecated, provide DBusRecursiveMutexLockFunction instead. */
/** Deprecated, provide DBusRecursiveMutexLockFunction instead. Return value is lock success, but gets ignored in practice. */
typedef dbus_bool_t (* DBusMutexLockFunction) (DBusMutex *mutex);
/** Deprecated, provide DBusRecursiveMutexUnlockFunction instead. */
/** Deprecated, provide DBusRecursiveMutexUnlockFunction instead. Return value is unlock success, but gets ignored in practice. */
typedef dbus_bool_t (* DBusMutexUnlockFunction) (DBusMutex *mutex);
/** Creates a new recursively-lockable mutex, or returns #NULL if not enough memory.
* Found in #DBusThreadFunctions
* Found in #DBusThreadFunctions. Do not just use PTHREAD_MUTEX_RECURSIVE for this, because
* it does not save/restore the recursion count when waiting on a condition. libdbus
* requires the Java-style behavior where the mutex is fully unlocked to wait on
* a condition.
*/
typedef DBusMutex* (* DBusRecursiveMutexNewFunction) (void);
/** Frees a recursively-lockable mutex. Found in #DBusThreadFunctions.
@ -71,11 +74,21 @@ typedef DBusCondVar* (* DBusCondVarNewFunction) (void);
/** Frees a condition variable. Found in #DBusThreadFunctions.
*/
typedef void (* DBusCondVarFreeFunction) (DBusCondVar *cond);
/** Waits on a condition variable. Found in #DBusThreadFunctions.
/** Waits on a condition variable. Found in
* #DBusThreadFunctions. Must work with either a recursive or
* nonrecursive mutex, whichever the thread implementation
* provides. Note that PTHREAD_MUTEX_RECURSIVE does not work with
* condition variables (does not save/restore the recursion count) so
* don't try using simply pthread_cond_wait() and a
* PTHREAD_MUTEX_RECURSIVE to implement this, it won't work right.
*/
typedef void (* DBusCondVarWaitFunction) (DBusCondVar *cond,
DBusMutex *mutex);
/** Waits on a condition variable with a timeout. Found in #DBusThreadFunctions.
/** Waits on a condition variable with a timeout. Found in
* #DBusThreadFunctions. Returns #TRUE if the wait did not
* time out, and #FALSE if it did.
*/
typedef dbus_bool_t (* DBusCondVarWaitTimeoutFunction) (DBusCondVar *cond,
DBusMutex *mutex,
@ -115,6 +128,22 @@ typedef enum
* Functions that must be implemented to make the D-Bus library
* thread-aware. The recursive mutex functions should be specified
* rather than the old, deprecated nonrecursive ones.
*
* The condition variable functions have to work with recursive
* mutexes if you provide those, or with nonrecursive mutexes if you
* provide those.
*
* If implementing threads using pthreads, be aware that
* PTHREAD_MUTEX_RECURSIVE is broken in combination with condition
* variables. libdbus relies on the Java-style behavior that when
* waiting on a condition, the recursion count is saved and restored,
* and the mutex is completely unlocked, not just decremented one
* level of recursion.
*
* Thus with pthreads you probably have to roll your own emulated
* recursive mutexes, you can't use PTHREAD_MUTEX_RECURSIVE. This is
* what dbus_threads_init_default() does on platforms that use
* pthreads.
*/
typedef struct
{