D-Bus  1.6.8
dbus-sysdeps-thread-win.c
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