D-Bus 1.14.10
dbus-sysdeps-thread-win.c
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2/* dbus-sysdeps-pthread.c Implements threads using Windows threads (internal to libdbus)
3 *
4 * Copyright (C) 2006 Red Hat, Inc.
5 *
6 * Licensed under the Academic Free License version 2.1
7 *
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.
12 *
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.
17 *
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
21 *
22 */
23
24#include <config.h>
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"
30
31#include <stdio.h>
32
33#include <windows.h>
34
35/* Protected by DllMain lock, effectively */
36static dbus_bool_t global_init_done = FALSE;
37static CRITICAL_SECTION init_lock;
38
39/* Called from C++ code in dbus-init-win.cpp. */
40void
41_dbus_threads_windows_init_global (void)
42{
43 /* this ensures that the object that acts as our global constructor
44 * actually gets linked in when we're linked statically */
45 _dbus_threads_windows_ensure_ctor_linked ();
46
47 InitializeCriticalSection (&init_lock);
48 global_init_done = TRUE;
49}
50
51struct DBusCondVar {
53 CRITICAL_SECTION lock;
54};
55
56static DWORD dbus_cond_event_tls = TLS_OUT_OF_INDEXES;
57
58/* Protected by DllMain lock, effectively */
59static HMODULE dbus_dll_hmodule;
60
61void *
62_dbus_win_get_dll_hmodule (void)
63{
64 return dbus_dll_hmodule;
65}
66
67#ifdef DBUS_WINCE
68#define hinst_t HANDLE
69#else
70#define hinst_t HINSTANCE
71#endif
72
73BOOL WINAPI DllMain (hinst_t, DWORD, LPVOID);
74
75/* We need this to free the TLS events on thread exit */
76BOOL WINAPI
77DllMain (hinst_t hinstDLL,
78 DWORD fdwReason,
79 LPVOID lpvReserved)
80{
81 HANDLE event;
82 switch (fdwReason)
83 {
84 case DLL_PROCESS_ATTACH:
85 dbus_dll_hmodule = hinstDLL;
86 break;
87 case DLL_THREAD_DETACH:
88 if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
89 {
90 event = TlsGetValue(dbus_cond_event_tls);
91 CloseHandle (event);
92 TlsSetValue(dbus_cond_event_tls, NULL);
93 }
94 break;
95 case DLL_PROCESS_DETACH:
96 if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
97 {
98 event = TlsGetValue(dbus_cond_event_tls);
99 CloseHandle (event);
100 TlsSetValue(dbus_cond_event_tls, NULL);
101
102 TlsFree(dbus_cond_event_tls);
103 }
104 break;
105 default:
106 break;
107 }
108 return TRUE;
109}
110
112_dbus_platform_cmutex_new (void)
113{
114 HANDLE handle;
115 handle = CreateMutex (NULL, FALSE, NULL);
116 return (DBusCMutex *) handle;
117}
118
120_dbus_platform_rmutex_new (void)
121{
122 HANDLE handle;
123 handle = CreateMutex (NULL, FALSE, NULL);
124 return (DBusRMutex *) handle;
125}
126
127void
128_dbus_platform_cmutex_free (DBusCMutex *mutex)
129{
130 CloseHandle ((HANDLE *) mutex);
131}
132
133void
134_dbus_platform_rmutex_free (DBusRMutex *mutex)
135{
136 CloseHandle ((HANDLE *) mutex);
137}
138
139void
140_dbus_platform_cmutex_lock (DBusCMutex *mutex)
141{
142 WaitForSingleObject ((HANDLE *) mutex, INFINITE);
143}
144
145void
146_dbus_platform_rmutex_lock (DBusRMutex *mutex)
147{
148 WaitForSingleObject ((HANDLE *) mutex, INFINITE);
149}
150
151void
152_dbus_platform_cmutex_unlock (DBusCMutex *mutex)
153{
154 ReleaseMutex ((HANDLE *) mutex);
155}
156
157void
158_dbus_platform_rmutex_unlock (DBusRMutex *mutex)
159{
160 ReleaseMutex ((HANDLE *) mutex);
161}
162
164_dbus_platform_condvar_new (void)
165{
166 DBusCondVar *cond;
167
168 cond = dbus_new (DBusCondVar, 1);
169 if (cond == NULL)
170 return NULL;
171
172 cond->list = NULL;
173
174 InitializeCriticalSection (&cond->lock);
175 return cond;
176}
177
178void
179_dbus_platform_condvar_free (DBusCondVar *cond)
180{
181 DeleteCriticalSection (&cond->lock);
182 _dbus_list_clear (&cond->list);
183 dbus_free (cond);
184}
185
186static dbus_bool_t
187_dbus_condvar_wait_win32 (DBusCondVar *cond,
188 DBusCMutex *mutex,
189 int milliseconds)
190{
191 DWORD retval;
192 dbus_bool_t ret;
193 HANDLE event = TlsGetValue (dbus_cond_event_tls);
194
195 if (!event)
196 {
197 event = CreateEvent (0, FALSE, FALSE, NULL);
198 if (event == 0)
199 return FALSE;
200 TlsSetValue (dbus_cond_event_tls, event);
201 }
202
203 EnterCriticalSection (&cond->lock);
204
205 /* The event must not be signaled. Check this */
206 _dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT);
207
208 ret = _dbus_list_append (&cond->list, event);
209
210 LeaveCriticalSection (&cond->lock);
211
212 if (!ret)
213 return FALSE; /* Prepend failed */
214
215 _dbus_platform_cmutex_unlock (mutex);
216 retval = WaitForSingleObject (event, milliseconds);
217 _dbus_platform_cmutex_lock (mutex);
218
219 if (retval == WAIT_TIMEOUT)
220 {
221 EnterCriticalSection (&cond->lock);
222 _dbus_list_remove (&cond->list, event);
223
224 /* In the meantime we could have been signaled, so we must again
225 * wait for the signal, this time with no timeout, to reset
226 * it. retval is set again to honour the late arrival of the
227 * signal */
228 retval = WaitForSingleObject (event, 0);
229
230 LeaveCriticalSection (&cond->lock);
231 }
232
233#ifndef DBUS_DISABLE_ASSERT
234 EnterCriticalSection (&cond->lock);
235
236 /* Now event must not be inside the array, check this */
237 _dbus_assert (_dbus_list_remove (&cond->list, event) == FALSE);
238
239 LeaveCriticalSection (&cond->lock);
240#endif /* !G_DISABLE_ASSERT */
241
242 return retval != WAIT_TIMEOUT;
243}
244
245void
246_dbus_platform_condvar_wait (DBusCondVar *cond,
247 DBusCMutex *mutex)
248{
249 _dbus_condvar_wait_win32 (cond, mutex, INFINITE);
250}
251
253_dbus_platform_condvar_wait_timeout (DBusCondVar *cond,
254 DBusCMutex *mutex,
255 int timeout_milliseconds)
256{
257 return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds);
258}
259
260void
261_dbus_platform_condvar_wake_one (DBusCondVar *cond)
262{
263 EnterCriticalSection (&cond->lock);
264
265 if (cond->list != NULL)
266 {
267 SetEvent (_dbus_list_pop_first (&cond->list));
268 /* Avoid live lock by pushing the waiter to the mutex lock
269 instruction, which is fair. If we don't do this, we could
270 acquire the condition variable again before the waiter has a
271 chance itself, leading to starvation. */
272 Sleep (0);
273 }
274 LeaveCriticalSection (&cond->lock);
275}
276
279{
280 /* We reuse this over several generations, because we can't
281 * free the events once they are in use
282 */
283 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
284 {
285 dbus_cond_event_tls = TlsAlloc ();
286 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
287 return FALSE;
288 }
289
290 return TRUE;
291}
292
293void
295{
296 _dbus_assert (global_init_done);
297 EnterCriticalSection (&init_lock);
298}
299
300void
302{
303 _dbus_assert (global_init_done);
304 LeaveCriticalSection (&init_lock);
305}
306
307#ifdef DBUS_ENABLE_VERBOSE_MODE
308void
309_dbus_print_thread (void)
310{
311 fprintf (stderr, "%lu: 0x%04lx: ", _dbus_pid_for_log (), GetCurrentThreadId ());
312}
313#endif
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
dbus_bool_t _dbus_list_remove(DBusList **list, void *data)
Removes a value from the list.
Definition: dbus-list.c:416
void * _dbus_list_pop_first(DBusList **list)
Removes the first value in the list and returns it.
Definition: dbus-list.c:677
void _dbus_list_clear(DBusList **list)
Frees all links in the list and sets the list head to NULL.
Definition: dbus-list.c:543
dbus_bool_t _dbus_list_append(DBusList **list, void *data)
Appends a value to the list.
Definition: dbus-list.c:271
#define NULL
A null pointer, defined appropriately for C or C++.
#define TRUE
Expands to "1".
#define FALSE
Expands to "0".
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:692
#define dbus_new(type, count)
Safe macro for using dbus_malloc().
Definition: dbus-memory.h:57
unsigned long _dbus_pid_for_log(void)
The only reason this is separate from _dbus_getpid() is to allow it on Windows for logging but not fo...
void _dbus_threads_lock_platform_specific(void)
Lock a static mutex used to protect _dbus_threads_init_platform_specific().
void _dbus_threads_unlock_platform_specific(void)
Undo _dbus_threads_lock_platform_specific().
dbus_bool_t _dbus_threads_init_platform_specific(void)
Initialize threads as in dbus_threads_init_default(), appropriately for the platform.
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35
CRITICAL_SECTION lock
lock protecting the list
DBusList * list
list thread-local-stored events waiting on the cond variable
A node in a linked list.
Definition: dbus-list.h:35