diff options
| -rw-r--r-- | ChangeLog | 13 | ||||
| -rw-r--r-- | dbus/Makefile.am | 1 | ||||
| -rw-r--r-- | dbus/dbus-connection.c | 19 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps-pthread.c | 167 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps-win-thread.c | 259 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps.h | 6 | ||||
| -rw-r--r-- | dbus/dbus-threads-internal.h | 8 | ||||
| -rw-r--r-- | dbus/dbus-threads.c | 379 | ||||
| -rw-r--r-- | dbus/dbus-threads.h | 39 | 
9 files changed, 506 insertions, 385 deletions
| @@ -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 diff --git a/dbus/Makefile.am b/dbus/Makefile.am index b8d97783..c6fb4755 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -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				\ diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 7a20e047..e2debdd0 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -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          { diff --git a/dbus/dbus-sysdeps-pthread.c b/dbus/dbus-sysdeps-pthread.c new file mode 100644 index 00000000..3b7bb6d1 --- /dev/null +++ b/dbus/dbus-sysdeps-pthread.c @@ -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); +} diff --git a/dbus/dbus-sysdeps-win-thread.c b/dbus/dbus-sysdeps-win-thread.c new file mode 100644 index 00000000..e0a51031 --- /dev/null +++ b/dbus/dbus-sysdeps-win-thread.c @@ -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); +} + diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 9e4e6544..eb395e05 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -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);  /** @} */ diff --git a/dbus/dbus-threads-internal.h b/dbus/dbus-threads-internal.h index 8f26bca1..ed30df65 100644 --- a/dbus/dbus-threads-internal.h +++ b/dbus/dbus-threads-internal.h @@ -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 diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c index 98f08730..f962316b 100644 --- a/dbus/dbus-threads.c +++ b/dbus/dbus-threads.c @@ -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 ();  } diff --git a/dbus/dbus-threads.h b/dbus/dbus-threads.h index 344b0ffd..5cb13b1a 100644 --- a/dbus/dbus-threads.h +++ b/dbus/dbus-threads.h @@ -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  { | 
