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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00024 #include "dbus-internals.h"
00025 #include "dbus-sysdeps.h"
00026 #include "dbus-threads.h"
00027 #include "dbus-list.h"
00028 
00029 #include <windows.h>
00030 
00031 struct DBusCondVar {
00032   DBusList *list;        
00033   CRITICAL_SECTION lock; 
00034 };
00035 
00036 static DWORD dbus_cond_event_tls = TLS_OUT_OF_INDEXES;
00037 
00038 
00039 BOOL WINAPI DllMain (HINSTANCE hinstDLL,
00040                      DWORD     fdwReason,
00041                      LPVOID    lpvReserved);
00042 
00043 /* We need this to free the TLS events on thread exit */
00044 BOOL WINAPI
00045 DllMain (HINSTANCE hinstDLL,
00046          DWORD     fdwReason,
00047          LPVOID    lpvReserved)
00048 {
00049   HANDLE event;
00050   switch (fdwReason) 
00051     { 
00052     case DLL_THREAD_DETACH:
00053       if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
00054         {
00055           event = TlsGetValue(dbus_cond_event_tls);
00056           CloseHandle (event);
00057           TlsSetValue(dbus_cond_event_tls, NULL);
00058         }
00059       break;
00060     case DLL_PROCESS_DETACH: 
00061       if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
00062         {
00063           event = TlsGetValue(dbus_cond_event_tls);
00064           CloseHandle (event);
00065           TlsSetValue(dbus_cond_event_tls, NULL);
00066 
00067           TlsFree(dbus_cond_event_tls); 
00068         }
00069       break;
00070     default: 
00071       break; 
00072     }
00073   return TRUE;
00074 }
00075 
00076 static DBusMutex*
00077 _dbus_windows_mutex_new (void)
00078 {
00079   HANDLE handle;
00080   handle = CreateMutex (NULL, FALSE, NULL);
00081   return (DBusMutex *) handle;
00082 }
00083 
00084 static void
00085 _dbus_windows_mutex_free (DBusMutex *mutex)
00086 {
00087   CloseHandle ((HANDLE *) mutex);
00088 }
00089 
00090 static dbus_bool_t
00091 _dbus_windows_mutex_lock (DBusMutex *mutex)
00092 {
00093   return WaitForSingleObject ((HANDLE *) mutex, INFINITE) != WAIT_FAILED;
00094 }
00095 
00096 static dbus_bool_t
00097 _dbus_windows_mutex_unlock (DBusMutex *mutex)
00098 {
00099   return ReleaseMutex ((HANDLE *) mutex) != 0;
00100 }
00101 
00102 static DBusCondVar *
00103 _dbus_windows_condvar_new (void)
00104 {
00105   DBusCondVar *cond;
00106     
00107   cond = dbus_new (DBusCondVar, 1);
00108   if (cond == NULL)
00109     return NULL;
00110   
00111   cond->list = NULL;
00112   
00113   InitializeCriticalSection (&cond->lock);
00114   return (DBusCondVar *) cond;
00115 }
00116 
00117 static void
00118 _dbus_windows_condvar_free (DBusCondVar *cond)
00119 {
00120   DeleteCriticalSection (&cond->lock);
00121   _dbus_list_clear (&cond->list);
00122   dbus_free (cond);
00123 }
00124 
00125 static dbus_bool_t
00126 _dbus_condvar_wait_win32 (DBusCondVar *cond,
00127                           DBusMutex *mutex,
00128                           int milliseconds)
00129 {
00130   DWORD retval;
00131   dbus_bool_t ret;
00132   HANDLE event = TlsGetValue (dbus_cond_event_tls);
00133 
00134   if (!event)
00135     {
00136       event = CreateEvent (0, FALSE, FALSE, NULL);
00137       if (event == 0)
00138         return FALSE;
00139       TlsSetValue (dbus_cond_event_tls, event);
00140     }
00141 
00142   EnterCriticalSection (&cond->lock);
00143 
00144   /* The event must not be signaled. Check this */
00145   _dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT);
00146 
00147   ret = _dbus_list_append (&cond->list, event);
00148   
00149   LeaveCriticalSection (&cond->lock);
00150   
00151   if (!ret)
00152     return FALSE; /* Prepend failed */
00153 
00154   _dbus_mutex_unlock (mutex);
00155   retval = WaitForSingleObject (event, milliseconds);
00156   _dbus_mutex_lock (mutex);
00157   
00158   if (retval == WAIT_TIMEOUT)
00159     {
00160       EnterCriticalSection (&cond->lock);
00161       _dbus_list_remove (&cond->list, event);
00162 
00163       /* In the meantime we could have been signaled, so we must again
00164        * wait for the signal, this time with no timeout, to reset
00165        * it. retval is set again to honour the late arrival of the
00166        * signal */
00167       retval = WaitForSingleObject (event, 0);
00168 
00169       LeaveCriticalSection (&cond->lock);
00170     }
00171 
00172 #ifndef DBUS_DISABLE_ASSERT
00173   EnterCriticalSection (&cond->lock);
00174 
00175   /* Now event must not be inside the array, check this */
00176   _dbus_assert (_dbus_list_remove (&cond->list, event) == FALSE);
00177 
00178   LeaveCriticalSection (&cond->lock);
00179 #endif /* !G_DISABLE_ASSERT */
00180 
00181   return retval != WAIT_TIMEOUT;
00182 }
00183 
00184 static void
00185 _dbus_windows_condvar_wait (DBusCondVar *cond,
00186                             DBusMutex   *mutex)
00187 {
00188   _dbus_condvar_wait_win32 (cond, mutex, INFINITE);
00189 }
00190 
00191 static dbus_bool_t
00192 _dbus_windows_condvar_wait_timeout (DBusCondVar               *cond,
00193                                      DBusMutex                 *mutex,
00194                                      int                        timeout_milliseconds)
00195 {
00196   return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds);
00197 }
00198 
00199 static void
00200 _dbus_windows_condvar_wake_one (DBusCondVar *cond)
00201 {
00202   EnterCriticalSection (&cond->lock);
00203   
00204   if (cond->list != NULL)
00205     SetEvent (_dbus_list_pop_first (&cond->list));
00206     
00207   LeaveCriticalSection (&cond->lock);
00208 }
00209 
00210 static void
00211 _dbus_windows_condvar_wake_all (DBusCondVar *cond)
00212 {
00213   EnterCriticalSection (&cond->lock);
00214 
00215   while (cond->list != NULL)
00216     SetEvent (_dbus_list_pop_first (&cond->list));
00217   
00218   LeaveCriticalSection (&cond->lock);
00219 }
00220 
00221 static const DBusThreadFunctions windows_functions =
00222 {
00223   DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
00224   DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
00225   DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
00226   DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
00227   DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
00228   DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
00229   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
00230   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
00231   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
00232   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
00233   _dbus_windows_mutex_new,
00234   _dbus_windows_mutex_free,
00235   _dbus_windows_mutex_lock,
00236   _dbus_windows_mutex_unlock,
00237   _dbus_windows_condvar_new,
00238   _dbus_windows_condvar_free,
00239   _dbus_windows_condvar_wait,
00240   _dbus_windows_condvar_wait_timeout,
00241   _dbus_windows_condvar_wake_one,
00242   _dbus_windows_condvar_wake_all
00243 };
00244 
00245 dbus_bool_t
00246 _dbus_threads_init_platform_specific (void)
00247 {
00248   /* We reuse this over several generations, because we can't
00249    * free the events once they are in use
00250    */
00251   if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
00252     {
00253       dbus_cond_event_tls = TlsAlloc ();
00254       if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
00255         return FALSE;
00256     }
00257 
00258   return dbus_threads_init (&windows_functions);
00259 }
00260 

Generated on Wed Aug 29 12:15:04 2007 for D-Bus by  doxygen 1.5.2