D-Bus 1.6.12
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-sysdeps-pthread.c Implements threads using Windows threads (internal to libdbus) 00003 * 00004 * Copyright (C) 2006 Red Hat, Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 * 00022 */ 00023 00024 #include <config.h> 00025 #include "dbus-internals.h" 00026 #include "dbus-sysdeps.h" 00027 #include "dbus-sysdeps-win.h" 00028 #include "dbus-threads.h" 00029 #include "dbus-list.h" 00030 00031 #include <windows.h> 00032 00033 struct DBusCondVar { 00034 DBusList *list; 00035 CRITICAL_SECTION lock; 00036 }; 00037 00038 static DWORD dbus_cond_event_tls = TLS_OUT_OF_INDEXES; 00039 00040 00041 static HMODULE dbus_dll_hmodule; 00042 00043 void * 00044 _dbus_win_get_dll_hmodule (void) 00045 { 00046 return dbus_dll_hmodule; 00047 } 00048 00049 #ifdef DBUS_WINCE 00050 #define hinst_t HANDLE 00051 #else 00052 #define hinst_t HINSTANCE 00053 #endif 00054 00055 BOOL WINAPI DllMain (hinst_t, DWORD, LPVOID); 00056 00057 /* We need this to free the TLS events on thread exit */ 00058 BOOL WINAPI 00059 DllMain (hinst_t hinstDLL, 00060 DWORD fdwReason, 00061 LPVOID lpvReserved) 00062 { 00063 HANDLE event; 00064 switch (fdwReason) 00065 { 00066 case DLL_PROCESS_ATTACH: 00067 dbus_dll_hmodule = hinstDLL; 00068 break; 00069 case DLL_THREAD_DETACH: 00070 if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES) 00071 { 00072 event = TlsGetValue(dbus_cond_event_tls); 00073 CloseHandle (event); 00074 TlsSetValue(dbus_cond_event_tls, NULL); 00075 } 00076 break; 00077 case DLL_PROCESS_DETACH: 00078 if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES) 00079 { 00080 event = TlsGetValue(dbus_cond_event_tls); 00081 CloseHandle (event); 00082 TlsSetValue(dbus_cond_event_tls, NULL); 00083 00084 TlsFree(dbus_cond_event_tls); 00085 } 00086 break; 00087 default: 00088 break; 00089 } 00090 return TRUE; 00091 } 00092 00093 DBusCMutex * 00094 _dbus_platform_cmutex_new (void) 00095 { 00096 HANDLE handle; 00097 handle = CreateMutex (NULL, FALSE, NULL); 00098 return (DBusCMutex *) handle; 00099 } 00100 00101 DBusRMutex * 00102 _dbus_platform_rmutex_new (void) 00103 { 00104 HANDLE handle; 00105 handle = CreateMutex (NULL, FALSE, NULL); 00106 return (DBusRMutex *) handle; 00107 } 00108 00109 void 00110 _dbus_platform_cmutex_free (DBusCMutex *mutex) 00111 { 00112 CloseHandle ((HANDLE *) mutex); 00113 } 00114 00115 void 00116 _dbus_platform_rmutex_free (DBusRMutex *mutex) 00117 { 00118 CloseHandle ((HANDLE *) mutex); 00119 } 00120 00121 void 00122 _dbus_platform_cmutex_lock (DBusCMutex *mutex) 00123 { 00124 WaitForSingleObject ((HANDLE *) mutex, INFINITE); 00125 } 00126 00127 void 00128 _dbus_platform_rmutex_lock (DBusRMutex *mutex) 00129 { 00130 WaitForSingleObject ((HANDLE *) mutex, INFINITE); 00131 } 00132 00133 void 00134 _dbus_platform_cmutex_unlock (DBusCMutex *mutex) 00135 { 00136 ReleaseMutex ((HANDLE *) mutex); 00137 } 00138 00139 void 00140 _dbus_platform_rmutex_unlock (DBusRMutex *mutex) 00141 { 00142 ReleaseMutex ((HANDLE *) mutex); 00143 } 00144 00145 DBusCondVar * 00146 _dbus_platform_condvar_new (void) 00147 { 00148 DBusCondVar *cond; 00149 00150 cond = dbus_new (DBusCondVar, 1); 00151 if (cond == NULL) 00152 return NULL; 00153 00154 cond->list = NULL; 00155 00156 InitializeCriticalSection (&cond->lock); 00157 return cond; 00158 } 00159 00160 void 00161 _dbus_platform_condvar_free (DBusCondVar *cond) 00162 { 00163 DeleteCriticalSection (&cond->lock); 00164 _dbus_list_clear (&cond->list); 00165 dbus_free (cond); 00166 } 00167 00168 static dbus_bool_t 00169 _dbus_condvar_wait_win32 (DBusCondVar *cond, 00170 DBusCMutex *mutex, 00171 int milliseconds) 00172 { 00173 DWORD retval; 00174 dbus_bool_t ret; 00175 HANDLE event = TlsGetValue (dbus_cond_event_tls); 00176 00177 if (!event) 00178 { 00179 event = CreateEvent (0, FALSE, FALSE, NULL); 00180 if (event == 0) 00181 return FALSE; 00182 TlsSetValue (dbus_cond_event_tls, event); 00183 } 00184 00185 EnterCriticalSection (&cond->lock); 00186 00187 /* The event must not be signaled. Check this */ 00188 _dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT); 00189 00190 ret = _dbus_list_append (&cond->list, event); 00191 00192 LeaveCriticalSection (&cond->lock); 00193 00194 if (!ret) 00195 return FALSE; /* Prepend failed */ 00196 00197 _dbus_platform_cmutex_unlock (mutex); 00198 retval = WaitForSingleObject (event, milliseconds); 00199 _dbus_platform_cmutex_lock (mutex); 00200 00201 if (retval == WAIT_TIMEOUT) 00202 { 00203 EnterCriticalSection (&cond->lock); 00204 _dbus_list_remove (&cond->list, event); 00205 00206 /* In the meantime we could have been signaled, so we must again 00207 * wait for the signal, this time with no timeout, to reset 00208 * it. retval is set again to honour the late arrival of the 00209 * signal */ 00210 retval = WaitForSingleObject (event, 0); 00211 00212 LeaveCriticalSection (&cond->lock); 00213 } 00214 00215 #ifndef DBUS_DISABLE_ASSERT 00216 EnterCriticalSection (&cond->lock); 00217 00218 /* Now event must not be inside the array, check this */ 00219 _dbus_assert (_dbus_list_remove (&cond->list, event) == FALSE); 00220 00221 LeaveCriticalSection (&cond->lock); 00222 #endif /* !G_DISABLE_ASSERT */ 00223 00224 return retval != WAIT_TIMEOUT; 00225 } 00226 00227 void 00228 _dbus_platform_condvar_wait (DBusCondVar *cond, 00229 DBusCMutex *mutex) 00230 { 00231 _dbus_condvar_wait_win32 (cond, mutex, INFINITE); 00232 } 00233 00234 dbus_bool_t 00235 _dbus_platform_condvar_wait_timeout (DBusCondVar *cond, 00236 DBusCMutex *mutex, 00237 int timeout_milliseconds) 00238 { 00239 return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds); 00240 } 00241 00242 void 00243 _dbus_platform_condvar_wake_one (DBusCondVar *cond) 00244 { 00245 EnterCriticalSection (&cond->lock); 00246 00247 if (cond->list != NULL) 00248 { 00249 SetEvent (_dbus_list_pop_first (&cond->list)); 00250 /* Avoid live lock by pushing the waiter to the mutex lock 00251 instruction, which is fair. If we don't do this, we could 00252 acquire the condition variable again before the waiter has a 00253 chance itself, leading to starvation. */ 00254 Sleep (0); 00255 } 00256 LeaveCriticalSection (&cond->lock); 00257 } 00258 00259 dbus_bool_t 00260 _dbus_threads_init_platform_specific (void) 00261 { 00262 /* We reuse this over several generations, because we can't 00263 * free the events once they are in use 00264 */ 00265 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES) 00266 { 00267 dbus_cond_event_tls = TlsAlloc (); 00268 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES) 00269 return FALSE; 00270 } 00271 00272 return dbus_threads_init (NULL); 00273 } 00274