dbus/dbus dbus-threads.c,1.27,1.28 dbus-threads.h,1.9,1.10

John Palmieri johnp at kemper.freedesktop.org
Wed Sep 13 12:09:47 PDT 2006


Update of /cvs/dbus/dbus/dbus
In directory kemper:/tmp/cvs-serv27903/dbus

Modified Files:
	dbus-threads.c dbus-threads.h 
Log Message:
* dbus-threads.c (dbus_threads_init_default): New method for
  initializing the internal thread implementation (Patch from
  Alexander Larsson <alexl at redhat dot com>)


Index: dbus-threads.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-threads.c,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- dbus-threads.c	18 Aug 2006 20:24:56 -0000	1.27
+++ dbus-threads.c	13 Sep 2006 19:09:45 -0000	1.28
@@ -25,6 +25,17 @@
 #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,
@@ -34,8 +45,18 @@
   NULL, NULL, NULL, NULL,
   NULL, NULL, NULL, NULL
 };
-static int thread_init_generation = 0;
 
+#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;
 static DBusList *uninitialized_condvar_list = NULL;
 
@@ -482,6 +503,9 @@
  * in efficiency. Note that this function must be called
  * BEFORE the second thread is started.
  *
+ * Use dbus_threads_init_default() if you don't need a
+ * particular thread implementation.
+ *
  * This function may be called more than once.  The first
  * one wins.
  *
@@ -554,6 +578,374 @@
   return TRUE;
 }
 
+
+
+/* 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
+};
+
+/**
+ * 
+ * Initializes threads. If this function is not called,
+ * the D-Bus library will not lock any data structures.
+ * If it is called, D-Bus will do locking, at some cost
+ * in efficiency. Note that this function must be called
+ * BEFORE the second thread is started.
+ *
+ * This function may be called more than once.  The first
+ * one wins.
+ *
+ * @returns #TRUE on success, #FALSE if no memory
+ */
+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);
+}
+
+
 /** @} */
 
 #ifdef DBUS_BUILD_TESTS

Index: dbus-threads.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-threads.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- dbus-threads.h	3 Aug 2006 20:34:36 -0000	1.9
+++ dbus-threads.h	13 Sep 2006 19:09:45 -0000	1.10
@@ -98,6 +98,7 @@
 } DBusThreadFunctions;
 
 dbus_bool_t  dbus_threads_init         (const DBusThreadFunctions *functions);
+dbus_bool_t  dbus_threads_init_default (void);
 
 DBUS_END_DECLS
 



More information about the dbus-commit mailing list