1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-sysdeps-pthread.c Implements threads using Windows threads (internal to libdbus)
4 * Copyright (C) 2006 Red Hat, Inc.
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "dbus-internals.h"
26 #include "dbus-sysdeps.h"
27 #include "dbus-sysdeps-win.h"
28 #include "dbus-threads.h"
29 #include "dbus-list.h"
34 DBusList *list; /**< list thread-local-stored events waiting on the cond variable */
35 CRITICAL_SECTION lock; /**< lock protecting the list */
38 static DWORD dbus_cond_event_tls = TLS_OUT_OF_INDEXES;
41 static HMODULE dbus_dll_hmodule;
44 _dbus_win_get_dll_hmodule (void)
46 return dbus_dll_hmodule;
50 #define hinst_t HANDLE
52 #define hinst_t HINSTANCE
55 BOOL WINAPI DllMain (hinst_t, DWORD, LPVOID);
57 /* We need this to free the TLS events on thread exit */
59 DllMain (hinst_t hinstDLL,
66 case DLL_PROCESS_ATTACH:
67 dbus_dll_hmodule = hinstDLL;
69 case DLL_THREAD_DETACH:
70 if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
72 event = TlsGetValue(dbus_cond_event_tls);
74 TlsSetValue(dbus_cond_event_tls, NULL);
77 case DLL_PROCESS_DETACH:
78 if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
80 event = TlsGetValue(dbus_cond_event_tls);
82 TlsSetValue(dbus_cond_event_tls, NULL);
84 TlsFree(dbus_cond_event_tls);
94 _dbus_platform_cmutex_new (void)
97 handle = CreateMutex (NULL, FALSE, NULL);
98 return (DBusCMutex *) handle;
102 _dbus_platform_rmutex_new (void)
105 handle = CreateMutex (NULL, FALSE, NULL);
106 return (DBusRMutex *) handle;
110 _dbus_platform_cmutex_free (DBusCMutex *mutex)
112 CloseHandle ((HANDLE *) mutex);
116 _dbus_platform_rmutex_free (DBusRMutex *mutex)
118 CloseHandle ((HANDLE *) mutex);
122 _dbus_platform_cmutex_lock (DBusCMutex *mutex)
124 WaitForSingleObject ((HANDLE *) mutex, INFINITE);
128 _dbus_platform_rmutex_lock (DBusRMutex *mutex)
130 WaitForSingleObject ((HANDLE *) mutex, INFINITE);
134 _dbus_platform_cmutex_unlock (DBusCMutex *mutex)
136 ReleaseMutex ((HANDLE *) mutex);
140 _dbus_platform_rmutex_unlock (DBusRMutex *mutex)
142 ReleaseMutex ((HANDLE *) mutex);
146 _dbus_platform_condvar_new (void)
150 cond = dbus_new (DBusCondVar, 1);
156 InitializeCriticalSection (&cond->lock);
161 _dbus_platform_condvar_free (DBusCondVar *cond)
163 DeleteCriticalSection (&cond->lock);
164 _dbus_list_clear (&cond->list);
169 _dbus_condvar_wait_win32 (DBusCondVar *cond,
175 HANDLE event = TlsGetValue (dbus_cond_event_tls);
179 event = CreateEvent (0, FALSE, FALSE, NULL);
182 TlsSetValue (dbus_cond_event_tls, event);
185 EnterCriticalSection (&cond->lock);
187 /* The event must not be signaled. Check this */
188 _dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT);
190 ret = _dbus_list_append (&cond->list, event);
192 LeaveCriticalSection (&cond->lock);
195 return FALSE; /* Prepend failed */
197 _dbus_platform_cmutex_unlock (mutex);
198 retval = WaitForSingleObject (event, milliseconds);
199 _dbus_platform_cmutex_lock (mutex);
201 if (retval == WAIT_TIMEOUT)
203 EnterCriticalSection (&cond->lock);
204 _dbus_list_remove (&cond->list, event);
206 /* In the meantime we could have been signaled, so we must again
207 * wait for the signal, this time with no timeout, to reset
208 * it. retval is set again to honour the late arrival of the
210 retval = WaitForSingleObject (event, 0);
212 LeaveCriticalSection (&cond->lock);
215 #ifndef DBUS_DISABLE_ASSERT
216 EnterCriticalSection (&cond->lock);
218 /* Now event must not be inside the array, check this */
219 _dbus_assert (_dbus_list_remove (&cond->list, event) == FALSE);
221 LeaveCriticalSection (&cond->lock);
222 #endif /* !G_DISABLE_ASSERT */
224 return retval != WAIT_TIMEOUT;
228 _dbus_platform_condvar_wait (DBusCondVar *cond,
231 _dbus_condvar_wait_win32 (cond, mutex, INFINITE);
235 _dbus_platform_condvar_wait_timeout (DBusCondVar *cond,
237 int timeout_milliseconds)
239 return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds);
243 _dbus_platform_condvar_wake_one (DBusCondVar *cond)
245 EnterCriticalSection (&cond->lock);
247 if (cond->list != NULL)
249 SetEvent (_dbus_list_pop_first (&cond->list));
250 /* Avoid live lock by pushing the waiter to the mutex lock
251 instruction, which is fair. If we don't do this, we could
252 acquire the condition variable again before the waiter has a
253 chance itself, leading to starvation. */
256 LeaveCriticalSection (&cond->lock);
260 _dbus_threads_init_platform_specific (void)
262 /* We reuse this over several generations, because we can't
263 * free the events once they are in use
265 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
267 dbus_cond_event_tls = TlsAlloc ();
268 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
272 return dbus_threads_init (NULL);