D-Bus 1.4.1
|
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 static DBusMutex* 00094 _dbus_windows_mutex_new (void) 00095 { 00096 HANDLE handle; 00097 handle = CreateMutex (NULL, FALSE, NULL); 00098 return (DBusMutex *) handle; 00099 } 00100 00101 static void 00102 _dbus_windows_mutex_free (DBusMutex *mutex) 00103 { 00104 CloseHandle ((HANDLE *) mutex); 00105 } 00106 00107 static dbus_bool_t 00108 _dbus_windows_mutex_lock (DBusMutex *mutex) 00109 { 00110 return WaitForSingleObject ((HANDLE *) mutex, INFINITE) != WAIT_FAILED; 00111 } 00112 00113 static dbus_bool_t 00114 _dbus_windows_mutex_unlock (DBusMutex *mutex) 00115 { 00116 return ReleaseMutex ((HANDLE *) mutex) != 0; 00117 } 00118 00119 static DBusCondVar * 00120 _dbus_windows_condvar_new (void) 00121 { 00122 DBusCondVar *cond; 00123 00124 cond = dbus_new (DBusCondVar, 1); 00125 if (cond == NULL) 00126 return NULL; 00127 00128 cond->list = NULL; 00129 00130 InitializeCriticalSection (&cond->lock); 00131 return (DBusCondVar *) cond; 00132 } 00133 00134 static void 00135 _dbus_windows_condvar_free (DBusCondVar *cond) 00136 { 00137 DeleteCriticalSection (&cond->lock); 00138 _dbus_list_clear (&cond->list); 00139 dbus_free (cond); 00140 } 00141 00142 static dbus_bool_t 00143 _dbus_condvar_wait_win32 (DBusCondVar *cond, 00144 DBusMutex *mutex, 00145 int milliseconds) 00146 { 00147 DWORD retval; 00148 dbus_bool_t ret; 00149 HANDLE event = TlsGetValue (dbus_cond_event_tls); 00150 00151 if (!event) 00152 { 00153 event = CreateEvent (0, FALSE, FALSE, NULL); 00154 if (event == 0) 00155 return FALSE; 00156 TlsSetValue (dbus_cond_event_tls, event); 00157 } 00158 00159 EnterCriticalSection (&cond->lock); 00160 00161 /* The event must not be signaled. Check this */ 00162 _dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT); 00163 00164 ret = _dbus_list_append (&cond->list, event); 00165 00166 LeaveCriticalSection (&cond->lock); 00167 00168 if (!ret) 00169 return FALSE; /* Prepend failed */ 00170 00171 _dbus_mutex_unlock (mutex); 00172 retval = WaitForSingleObject (event, milliseconds); 00173 _dbus_mutex_lock (mutex); 00174 00175 if (retval == WAIT_TIMEOUT) 00176 { 00177 EnterCriticalSection (&cond->lock); 00178 _dbus_list_remove (&cond->list, event); 00179 00180 /* In the meantime we could have been signaled, so we must again 00181 * wait for the signal, this time with no timeout, to reset 00182 * it. retval is set again to honour the late arrival of the 00183 * signal */ 00184 retval = WaitForSingleObject (event, 0); 00185 00186 LeaveCriticalSection (&cond->lock); 00187 } 00188 00189 #ifndef DBUS_DISABLE_ASSERT 00190 EnterCriticalSection (&cond->lock); 00191 00192 /* Now event must not be inside the array, check this */ 00193 _dbus_assert (_dbus_list_remove (&cond->list, event) == FALSE); 00194 00195 LeaveCriticalSection (&cond->lock); 00196 #endif /* !G_DISABLE_ASSERT */ 00197 00198 return retval != WAIT_TIMEOUT; 00199 } 00200 00201 static void 00202 _dbus_windows_condvar_wait (DBusCondVar *cond, 00203 DBusMutex *mutex) 00204 { 00205 _dbus_condvar_wait_win32 (cond, mutex, INFINITE); 00206 } 00207 00208 static dbus_bool_t 00209 _dbus_windows_condvar_wait_timeout (DBusCondVar *cond, 00210 DBusMutex *mutex, 00211 int timeout_milliseconds) 00212 { 00213 return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds); 00214 } 00215 00216 static void 00217 _dbus_windows_condvar_wake_one (DBusCondVar *cond) 00218 { 00219 EnterCriticalSection (&cond->lock); 00220 00221 if (cond->list != NULL) 00222 SetEvent (_dbus_list_pop_first (&cond->list)); 00223 00224 LeaveCriticalSection (&cond->lock); 00225 } 00226 00227 static void 00228 _dbus_windows_condvar_wake_all (DBusCondVar *cond) 00229 { 00230 EnterCriticalSection (&cond->lock); 00231 00232 while (cond->list != NULL) 00233 SetEvent (_dbus_list_pop_first (&cond->list)); 00234 00235 LeaveCriticalSection (&cond->lock); 00236 } 00237 00238 static const DBusThreadFunctions windows_functions = 00239 { 00240 DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK | 00241 DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK | 00242 DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK | 00243 DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK | 00244 DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK | 00245 DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK | 00246 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK | 00247 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK | 00248 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK| 00249 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK, 00250 _dbus_windows_mutex_new, 00251 _dbus_windows_mutex_free, 00252 _dbus_windows_mutex_lock, 00253 _dbus_windows_mutex_unlock, 00254 _dbus_windows_condvar_new, 00255 _dbus_windows_condvar_free, 00256 _dbus_windows_condvar_wait, 00257 _dbus_windows_condvar_wait_timeout, 00258 _dbus_windows_condvar_wake_one, 00259 _dbus_windows_condvar_wake_all 00260 }; 00261 00262 dbus_bool_t 00263 _dbus_threads_init_platform_specific (void) 00264 { 00265 /* We reuse this over several generations, because we can't 00266 * free the events once they are in use 00267 */ 00268 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES) 00269 { 00270 dbus_cond_event_tls = TlsAlloc (); 00271 if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES) 00272 return FALSE; 00273 } 00274 00275 return dbus_threads_init (&windows_functions); 00276 } 00277