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