D-Bus  1.6.12
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 <windows.h>
32 
33 struct DBusCondVar {
35  CRITICAL_SECTION lock;
36 };
37 
38 static DWORD dbus_cond_event_tls = TLS_OUT_OF_INDEXES;
39 
40 
41 static HMODULE dbus_dll_hmodule;
42 
43 void *
44 _dbus_win_get_dll_hmodule (void)
45 {
46  return dbus_dll_hmodule;
47 }
48 
49 #ifdef DBUS_WINCE
50 #define hinst_t HANDLE
51 #else
52 #define hinst_t HINSTANCE
53 #endif
54 
55 BOOL WINAPI DllMain (hinst_t, DWORD, LPVOID);
56 
57 /* We need this to free the TLS events on thread exit */
58 BOOL WINAPI
59 DllMain (hinst_t hinstDLL,
60  DWORD fdwReason,
61  LPVOID lpvReserved)
62 {
63  HANDLE event;
64  switch (fdwReason)
65  {
66  case DLL_PROCESS_ATTACH:
67  dbus_dll_hmodule = hinstDLL;
68  break;
69  case DLL_THREAD_DETACH:
70  if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
71  {
72  event = TlsGetValue(dbus_cond_event_tls);
73  CloseHandle (event);
74  TlsSetValue(dbus_cond_event_tls, NULL);
75  }
76  break;
77  case DLL_PROCESS_DETACH:
78  if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
79  {
80  event = TlsGetValue(dbus_cond_event_tls);
81  CloseHandle (event);
82  TlsSetValue(dbus_cond_event_tls, NULL);
83 
84  TlsFree(dbus_cond_event_tls);
85  }
86  break;
87  default:
88  break;
89  }
90  return TRUE;
91 }
92 
93 DBusCMutex *
94 _dbus_platform_cmutex_new (void)
95 {
96  HANDLE handle;
97  handle = CreateMutex (NULL, FALSE, NULL);
98  return (DBusCMutex *) handle;
99 }
100 
101 DBusRMutex *
102 _dbus_platform_rmutex_new (void)
103 {
104  HANDLE handle;
105  handle = CreateMutex (NULL, FALSE, NULL);
106  return (DBusRMutex *) handle;
107 }
108 
109 void
110 _dbus_platform_cmutex_free (DBusCMutex *mutex)
111 {
112  CloseHandle ((HANDLE *) mutex);
113 }
114 
115 void
116 _dbus_platform_rmutex_free (DBusRMutex *mutex)
117 {
118  CloseHandle ((HANDLE *) mutex);
119 }
120 
121 void
122 _dbus_platform_cmutex_lock (DBusCMutex *mutex)
123 {
124  WaitForSingleObject ((HANDLE *) mutex, INFINITE);
125 }
126 
127 void
128 _dbus_platform_rmutex_lock (DBusRMutex *mutex)
129 {
130  WaitForSingleObject ((HANDLE *) mutex, INFINITE);
131 }
132 
133 void
134 _dbus_platform_cmutex_unlock (DBusCMutex *mutex)
135 {
136  ReleaseMutex ((HANDLE *) mutex);
137 }
138 
139 void
140 _dbus_platform_rmutex_unlock (DBusRMutex *mutex)
141 {
142  ReleaseMutex ((HANDLE *) mutex);
143 }
144 
145 DBusCondVar *
146 _dbus_platform_condvar_new (void)
147 {
148  DBusCondVar *cond;
149 
150  cond = dbus_new (DBusCondVar, 1);
151  if (cond == NULL)
152  return NULL;
153 
154  cond->list = NULL;
155 
156  InitializeCriticalSection (&cond->lock);
157  return cond;
158 }
159 
160 void
161 _dbus_platform_condvar_free (DBusCondVar *cond)
162 {
163  DeleteCriticalSection (&cond->lock);
164  _dbus_list_clear (&cond->list);
165  dbus_free (cond);
166 }
167 
168 static dbus_bool_t
169 _dbus_condvar_wait_win32 (DBusCondVar *cond,
170  DBusCMutex *mutex,
171  int milliseconds)
172 {
173  DWORD retval;
174  dbus_bool_t ret;
175  HANDLE event = TlsGetValue (dbus_cond_event_tls);
176 
177  if (!event)
178  {
179  event = CreateEvent (0, FALSE, FALSE, NULL);
180  if (event == 0)
181  return FALSE;
182  TlsSetValue (dbus_cond_event_tls, event);
183  }
184 
185  EnterCriticalSection (&cond->lock);
186 
187  /* The event must not be signaled. Check this */
188  _dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT);
189 
190  ret = _dbus_list_append (&cond->list, event);
191 
192  LeaveCriticalSection (&cond->lock);
193 
194  if (!ret)
195  return FALSE; /* Prepend failed */
196 
197  _dbus_platform_cmutex_unlock (mutex);
198  retval = WaitForSingleObject (event, milliseconds);
199  _dbus_platform_cmutex_lock (mutex);
200 
201  if (retval == WAIT_TIMEOUT)
202  {
203  EnterCriticalSection (&cond->lock);
204  _dbus_list_remove (&cond->list, event);
205 
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
209  * signal */
210  retval = WaitForSingleObject (event, 0);
211 
212  LeaveCriticalSection (&cond->lock);
213  }
214 
215 #ifndef DBUS_DISABLE_ASSERT
216  EnterCriticalSection (&cond->lock);
217 
218  /* Now event must not be inside the array, check this */
219  _dbus_assert (_dbus_list_remove (&cond->list, event) == FALSE);
220 
221  LeaveCriticalSection (&cond->lock);
222 #endif /* !G_DISABLE_ASSERT */
223 
224  return retval != WAIT_TIMEOUT;
225 }
226 
227 void
228 _dbus_platform_condvar_wait (DBusCondVar *cond,
229  DBusCMutex *mutex)
230 {
231  _dbus_condvar_wait_win32 (cond, mutex, INFINITE);
232 }
233 
235 _dbus_platform_condvar_wait_timeout (DBusCondVar *cond,
236  DBusCMutex *mutex,
237  int timeout_milliseconds)
238 {
239  return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds);
240 }
241 
242 void
243 _dbus_platform_condvar_wake_one (DBusCondVar *cond)
244 {
245  EnterCriticalSection (&cond->lock);
246 
247  if (cond->list != NULL)
248  {
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. */
254  Sleep (0);
255  }
256  LeaveCriticalSection (&cond->lock);
257 }
258 
261 {
262  /* We reuse this over several generations, because we can't
263  * free the events once they are in use
264  */
265  if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
266  {
267  dbus_cond_event_tls = TlsAlloc ();
268  if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
269  return FALSE;
270  }
271 
272  return dbus_threads_init (NULL);
273 }
274 
#define NULL
A null pointer, defined appropriately for C or C++.
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:700
#define dbus_new(type, count)
Safe macro for using dbus_malloc().
Definition: dbus-memory.h:58
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
dbus_bool_t _dbus_threads_init_platform_specific(void)
Initialize threads as in dbus_threads_init_default(), appropriately for the platform.
dbus_bool_t _dbus_list_remove(DBusList **list, void *data)
Removes a value from the list.
Definition: dbus-list.c:404
DBusList * list
list thread-local-stored events waiting on the cond variable
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35
dbus_bool_t _dbus_list_append(DBusList **list, void *data)
Appends a value to the list.
Definition: dbus-list.c:259
void * _dbus_list_pop_first(DBusList **list)
Removes the first value in the list and returns it.
Definition: dbus-list.c:638
#define TRUE
Expands to &quot;1&quot;.
A node in a linked list.
Definition: dbus-list.h:34
#define FALSE
Expands to &quot;0&quot;.
dbus_bool_t dbus_threads_init(const DBusThreadFunctions *functions)
Initializes threads, like dbus_threads_init_default().
Definition: dbus-threads.c:585
CRITICAL_SECTION lock
lock protecting the list
void _dbus_list_clear(DBusList **list)
Frees all links in the list and sets the list head to NULL.
Definition: dbus-list.c:531