summaryrefslogtreecommitdiffstats
path: root/dbus/dbus-sysdeps-win-thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'dbus/dbus-sysdeps-win-thread.c')
-rw-r--r--dbus/dbus-sysdeps-win-thread.c259
1 files changed, 259 insertions, 0 deletions
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);
+}
+