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_windows_mutex_new (void)
97 handle = CreateMutex (NULL, FALSE, NULL);
98 return (DBusMutex *) handle;
102 _dbus_windows_mutex_free (DBusMutex *mutex)
104 CloseHandle ((HANDLE *) mutex);
108 _dbus_windows_mutex_lock (DBusMutex *mutex)
110 return WaitForSingleObject ((HANDLE *) mutex, INFINITE) != WAIT_FAILED;
114 _dbus_windows_mutex_unlock (DBusMutex *mutex)
116 return ReleaseMutex ((HANDLE *) mutex) != 0;
120 _dbus_windows_condvar_new (void)
124 cond = dbus_new (DBusCondVar, 1);
130 InitializeCriticalSection (&cond->lock);
131 return (DBusCondVar *) cond;
135 _dbus_windows_condvar_free (DBusCondVar *cond)
137 DeleteCriticalSection (&cond->lock);
138 _dbus_list_clear (&cond->list);
143 _dbus_condvar_wait_win32 (DBusCondVar *cond,
149 HANDLE event = TlsGetValue (dbus_cond_event_tls);
153 event = CreateEvent (0, FALSE, FALSE, NULL);
156 TlsSetValue (dbus_cond_event_tls, event);
159 EnterCriticalSection (&cond->lock);
161 /* The event must not be signaled. Check this */
162 _dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT);
164 ret = _dbus_list_append (&cond->list, event);
166 LeaveCriticalSection (&cond->lock);
169 return FALSE; /* Prepend failed */
171 _dbus_mutex_unlock (mutex);
172 retval = WaitForSingleObject (event, milliseconds);
173 _dbus_mutex_lock (mutex);
175 if (retval == WAIT_TIMEOUT)
177 EnterCriticalSection (&cond->lock);
178 _dbus_list_remove (&cond->list, event);
180 /* In the meantime we could have been signaled, so we must again
181 * wait for the signal, this time with no timeout, to reset
182 * it. retval is set again to honour the late arrival of the
184 retval = WaitForSingleObject (event, 0);
186 LeaveCriticalSection (&cond->lock);
189 #ifndef DBUS_DISABLE_ASSERT
190 EnterCriticalSection (&cond->lock);
192 /* Now event must not be inside the array, check this */
193 _dbus_assert (_dbus_list_remove (&cond->list, event) == FALSE);
195 LeaveCriticalSection (&cond->lock);
196 #endif /* !G_DISABLE_ASSERT */
198 return retval != WAIT_TIMEOUT;
202 _dbus_windows_condvar_wait (DBusCondVar *cond,
205 _dbus_condvar_wait_win32 (cond, mutex, INFINITE);
209 _dbus_windows_condvar_wait_timeout (DBusCondVar *cond,
211 int timeout_milliseconds)
213 return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds);
217 _dbus_windows_condvar_wake_one (DBusCondVar *cond)
219 EnterCriticalSection (&cond->lock);
221 if (cond->list != NULL)
223 SetEvent (_dbus_list_pop_first (&cond->list));
224 /* Avoid live lock by pushing the waiter to the mutex lock
225 instruction, which is fair. If we don't do this, we could
226 acquire the condition variable again before the waiter has a
227 chance itself, leading to starvation. */
230 LeaveCriticalSection (&cond->lock);
234 _dbus_windows_condvar_wake_all (DBusCondVar *cond)
236 EnterCriticalSection (&cond->lock);
238 while (cond->list != NULL)
239 SetEvent (_dbus_list_pop_first (&cond->list));
241 if (cond->list != NULL)
243 /* Avoid live lock by pushing the waiter to the mutex lock
244 instruction, which is fair. If we don't do this, we could
245 acquire the condition variable again before the waiter has a
246 chance itself, leading to starvation. */
250 LeaveCriticalSection (&cond->lock);
253 static const DBusThreadFunctions windows_functions =
255 DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
256 DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
257 DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
258 DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
259 DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
260 DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
261 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
262 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
263 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
264 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
265 _dbus_windows_mutex_new,
266 _dbus_windows_mutex_free,
267 _dbus_windows_mutex_lock,
268 _dbus_windows_mutex_unlock,
269 _dbus_windows_condvar_new,
270 _dbus_windows_condvar_free,
271 _dbus_windows_condvar_wait,
272 _dbus_windows_condvar_wait_timeout,
273 _dbus_windows_condvar_wake_one,
274 _dbus_windows_condvar_wake_all
278 _dbus_threads_init_platform_specific (void)
280 /* We reuse this over several generations, because we can't
281 * free the events once they are in use
283 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
285 dbus_cond_event_tls = TlsAlloc ();
286 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
290 return dbus_threads_init (&windows_functions);