D-Bus 1.12.4

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