dbus: fix 64-bit compiler warnings
[platform/upstream/dbus.git] / dbus / 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;        /**< list thread-local-stored events waiting on the cond variable */
52   CRITICAL_SECTION lock; /**< lock protecting the list */
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
72 BOOL WINAPI DllMain (hinst_t, DWORD, LPVOID);
73
74 /* We need this to free the TLS events on thread exit */
75 BOOL WINAPI
76 DllMain (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