diff options
Diffstat (limited to 'src/3rdparty/libdbus/dbus/dbus-sysdeps-thread-win.c')
-rw-r--r-- | src/3rdparty/libdbus/dbus/dbus-sysdeps-thread-win.c | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/src/3rdparty/libdbus/dbus/dbus-sysdeps-thread-win.c b/src/3rdparty/libdbus/dbus/dbus-sysdeps-thread-win.c new file mode 100644 index 00000000..9f1818f9 --- /dev/null +++ b/src/3rdparty/libdbus/dbus/dbus-sysdeps-thread-win.c @@ -0,0 +1,339 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-sysdeps-pthread.c Implements threads using Windows threads (internal to libdbus) + * + * Copyright (C) 2006 Red Hat, Inc. + * + * SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <config.h> +#include "dbus-init-win.h" +#include "dbus-internals.h" +#include "dbus-sysdeps.h" +#include "dbus-sysdeps-win.h" +#include "dbus-threads.h" +#include "dbus-list.h" + +#include <stdio.h> + +#include <windows.h> + +#ifdef DBUS_DISABLE_ASSERT +#define THREAD_CHECK_TRUE(func_name, result_or_call) \ + do { if (!(result_or_call)) { /* ignore */ } } while (0) +#else +#define THREAD_CHECK_TRUE(func_name, result_or_call) do { \ + if (!(result_or_call)) { \ + _dbus_warn_check_failed ("thread function %s failed (windows error code=%ld) in %s", \ + func_name, GetLastError (), _DBUS_FUNCTION_NAME); \ + } \ +} while (0) +#endif /* !DBUS_DISABLE_ASSERT */ + +/* Protected by DllMain lock, effectively */ +static dbus_bool_t global_init_done = FALSE; +static CRITICAL_SECTION init_lock; + +/* Called from C++ code in dbus-init-win.cpp. */ +void +_dbus_threads_windows_init_global (void) +{ + /* this ensures that the object that acts as our global constructor + * actually gets linked in when we're linked statically */ + _dbus_threads_windows_ensure_ctor_linked (); + + InitializeCriticalSection (&init_lock); + global_init_done = TRUE; +} + +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; + +/* Protected by DllMain lock, effectively */ +static HMODULE dbus_dll_hmodule; + +void * +_dbus_win_get_dll_hmodule (void) +{ + return dbus_dll_hmodule; +} + +#ifdef DBUS_WINCE +#define hinst_t HANDLE +#else +#define hinst_t HINSTANCE +#endif + +BOOL WINAPI DllMain (hinst_t, DWORD, LPVOID); + +/* We need this to free the TLS events on thread exit */ +BOOL WINAPI +DllMain (hinst_t hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ + HANDLE event; + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + dbus_dll_hmodule = hinstDLL; + break; + 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; +} + +DBusCMutex * +_dbus_platform_cmutex_new (void) +{ + HANDLE handle; + handle = CreateMutex (NULL, FALSE, NULL); + THREAD_CHECK_TRUE ("CreateMutex", handle); + return (DBusCMutex *) handle; +} + +DBusRMutex * +_dbus_platform_rmutex_new (void) +{ + HANDLE handle; + handle = CreateMutex (NULL, FALSE, NULL); + THREAD_CHECK_TRUE ("CreateMutex", handle); + return (DBusRMutex *) handle; +} + +DBusRMutex * +_dbus_win_rmutex_named_new (const char *name) +{ + HANDLE handle; + handle = CreateMutex (NULL, FALSE, name); + THREAD_CHECK_TRUE ("CreateMutex", handle); + return (DBusRMutex *) handle; +} + +void +_dbus_platform_cmutex_free (DBusCMutex *mutex) +{ + THREAD_CHECK_TRUE ("CloseHandle", CloseHandle ((HANDLE *) mutex)); +} + +void +_dbus_platform_rmutex_free (DBusRMutex *mutex) +{ + THREAD_CHECK_TRUE ("CloseHandle", CloseHandle ((HANDLE *) mutex)); +} + +void +_dbus_platform_cmutex_lock (DBusCMutex *mutex) +{ + THREAD_CHECK_TRUE ("WaitForSingleObject", WaitForSingleObject ((HANDLE *) mutex, INFINITE) == WAIT_OBJECT_0); +} + +void +_dbus_platform_rmutex_lock (DBusRMutex *mutex) +{ + THREAD_CHECK_TRUE ("WaitForSingleObject", WaitForSingleObject ((HANDLE *) mutex, INFINITE) == WAIT_OBJECT_0); +} + +void +_dbus_platform_cmutex_unlock (DBusCMutex *mutex) +{ + THREAD_CHECK_TRUE ("ReleaseMutex", ReleaseMutex ((HANDLE *) mutex)); +} + +void +_dbus_platform_rmutex_unlock (DBusRMutex *mutex) +{ + THREAD_CHECK_TRUE ("ReleaseMutex", ReleaseMutex ((HANDLE *) mutex)); +} + +DBusCondVar * +_dbus_platform_condvar_new (void) +{ + DBusCondVar *cond; + + cond = dbus_new (DBusCondVar, 1); + if (cond == NULL) + return NULL; + + cond->list = NULL; + + InitializeCriticalSection (&cond->lock); + return cond; +} + +void +_dbus_platform_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, + DBusCMutex *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_platform_cmutex_unlock (mutex); + retval = WaitForSingleObject (event, milliseconds); + _dbus_platform_cmutex_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; +} + +void +_dbus_platform_condvar_wait (DBusCondVar *cond, + DBusCMutex *mutex) +{ + _dbus_condvar_wait_win32 (cond, mutex, INFINITE); +} + +dbus_bool_t +_dbus_platform_condvar_wait_timeout (DBusCondVar *cond, + DBusCMutex *mutex, + int timeout_milliseconds) +{ + return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds); +} + +void +_dbus_platform_condvar_wake_one (DBusCondVar *cond) +{ + EnterCriticalSection (&cond->lock); + + if (cond->list != NULL) + { + SetEvent (_dbus_list_pop_first (&cond->list)); + /* Avoid live lock by pushing the waiter to the mutex lock + instruction, which is fair. If we don't do this, we could + acquire the condition variable again before the waiter has a + chance itself, leading to starvation. */ + Sleep (0); + } + LeaveCriticalSection (&cond->lock); +} + +dbus_bool_t +_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 TRUE; +} + +void +_dbus_threads_lock_platform_specific (void) +{ + _dbus_assert (global_init_done); + EnterCriticalSection (&init_lock); +} + +void +_dbus_threads_unlock_platform_specific (void) +{ + _dbus_assert (global_init_done); + LeaveCriticalSection (&init_lock); +} + +#ifdef DBUS_ENABLE_VERBOSE_MODE +void +_dbus_print_thread (void) +{ + fprintf (stderr, "%lu: 0x%04lx: ", _dbus_pid_for_log (), GetCurrentThreadId ()); +} +#endif |