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
24 #include "dbus-internals.h"
25 #include "dbus-sysdeps.h"
26 #include "dbus-sysdeps-win.h"
27 #include "dbus-threads.h"
28 #include "dbus-list.h"
33 DBusList *list; /**< list thread-local-stored events waiting on the cond variable */
34 CRITICAL_SECTION lock; /**< lock protecting the list */
37 static DWORD dbus_cond_event_tls = TLS_OUT_OF_INDEXES;
40 static HMODULE dbus_dll_hmodule;
43 _dbus_win_get_dll_hmodule (void)
45 return dbus_dll_hmodule;
48 BOOL WINAPI DllMain (HINSTANCE hinstDLL,
52 /* We need this to free the TLS events on thread exit */
54 DllMain (HINSTANCE hinstDLL,
61 case DLL_PROCESS_ATTACH:
62 dbus_dll_hmodule = hinstDLL;
64 case DLL_THREAD_DETACH:
65 if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
67 event = TlsGetValue(dbus_cond_event_tls);
69 TlsSetValue(dbus_cond_event_tls, NULL);
72 case DLL_PROCESS_DETACH:
73 if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
75 event = TlsGetValue(dbus_cond_event_tls);
77 TlsSetValue(dbus_cond_event_tls, NULL);
79 TlsFree(dbus_cond_event_tls);
89 _dbus_windows_mutex_new (void)
92 handle = CreateMutex (NULL, FALSE, NULL);
93 return (DBusMutex *) handle;
97 _dbus_windows_mutex_free (DBusMutex *mutex)
99 CloseHandle ((HANDLE *) mutex);
103 _dbus_windows_mutex_lock (DBusMutex *mutex)
105 return WaitForSingleObject ((HANDLE *) mutex, INFINITE) != WAIT_FAILED;
109 _dbus_windows_mutex_unlock (DBusMutex *mutex)
111 return ReleaseMutex ((HANDLE *) mutex) != 0;
115 _dbus_windows_condvar_new (void)
119 cond = dbus_new (DBusCondVar, 1);
125 InitializeCriticalSection (&cond->lock);
126 return (DBusCondVar *) cond;
130 _dbus_windows_condvar_free (DBusCondVar *cond)
132 DeleteCriticalSection (&cond->lock);
133 _dbus_list_clear (&cond->list);
138 _dbus_condvar_wait_win32 (DBusCondVar *cond,
144 HANDLE event = TlsGetValue (dbus_cond_event_tls);
148 event = CreateEvent (0, FALSE, FALSE, NULL);
151 TlsSetValue (dbus_cond_event_tls, event);
154 EnterCriticalSection (&cond->lock);
156 /* The event must not be signaled. Check this */
157 _dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT);
159 ret = _dbus_list_append (&cond->list, event);
161 LeaveCriticalSection (&cond->lock);
164 return FALSE; /* Prepend failed */
166 _dbus_mutex_unlock (mutex);
167 retval = WaitForSingleObject (event, milliseconds);
168 _dbus_mutex_lock (mutex);
170 if (retval == WAIT_TIMEOUT)
172 EnterCriticalSection (&cond->lock);
173 _dbus_list_remove (&cond->list, event);
175 /* In the meantime we could have been signaled, so we must again
176 * wait for the signal, this time with no timeout, to reset
177 * it. retval is set again to honour the late arrival of the
179 retval = WaitForSingleObject (event, 0);
181 LeaveCriticalSection (&cond->lock);
184 #ifndef DBUS_DISABLE_ASSERT
185 EnterCriticalSection (&cond->lock);
187 /* Now event must not be inside the array, check this */
188 _dbus_assert (_dbus_list_remove (&cond->list, event) == FALSE);
190 LeaveCriticalSection (&cond->lock);
191 #endif /* !G_DISABLE_ASSERT */
193 return retval != WAIT_TIMEOUT;
197 _dbus_windows_condvar_wait (DBusCondVar *cond,
200 _dbus_condvar_wait_win32 (cond, mutex, INFINITE);
204 _dbus_windows_condvar_wait_timeout (DBusCondVar *cond,
206 int timeout_milliseconds)
208 return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds);
212 _dbus_windows_condvar_wake_one (DBusCondVar *cond)
214 EnterCriticalSection (&cond->lock);
216 if (cond->list != NULL)
217 SetEvent (_dbus_list_pop_first (&cond->list));
219 LeaveCriticalSection (&cond->lock);
223 _dbus_windows_condvar_wake_all (DBusCondVar *cond)
225 EnterCriticalSection (&cond->lock);
227 while (cond->list != NULL)
228 SetEvent (_dbus_list_pop_first (&cond->list));
230 LeaveCriticalSection (&cond->lock);
233 static const DBusThreadFunctions windows_functions =
235 DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
236 DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
237 DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
238 DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
239 DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
240 DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
241 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
242 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
243 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
244 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
245 _dbus_windows_mutex_new,
246 _dbus_windows_mutex_free,
247 _dbus_windows_mutex_lock,
248 _dbus_windows_mutex_unlock,
249 _dbus_windows_condvar_new,
250 _dbus_windows_condvar_free,
251 _dbus_windows_condvar_wait,
252 _dbus_windows_condvar_wait_timeout,
253 _dbus_windows_condvar_wake_one,
254 _dbus_windows_condvar_wake_all
258 _dbus_threads_init_platform_specific (void)
260 /* We reuse this over several generations, because we can't
261 * free the events once they are in use
263 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
265 dbus_cond_event_tls = TlsAlloc ();
266 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
270 return dbus_threads_init (&windows_functions);