~ubuntu-branches/ubuntu/maverick/dbus/maverick-proposed

« back to all changes in this revision

Viewing changes to dbus/dbus-sysdeps-thread-win.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2010-09-27 13:06:32 UTC
  • mfrom: (1.1.23 upstream)
  • Revision ID: james.westby@ubuntu.com-20100927130632-bqs145trvchd2lmf
Tags: 1.4.0-0ubuntu1
* New upstream release
 - Fixes https://bugs.freedesktop.org/show_bug.cgi?id=17754 Race condition in protected_change_timeout
 - Requested by various upstream KDE developers http://lists.kde.org/?t=128514970000004&r=1&w=2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
struct DBusCondVar {
 
34
  DBusList *list;        /**< list thread-local-stored events waiting on the cond variable */
 
35
  CRITICAL_SECTION lock; /**< lock protecting the list */
 
36
};
 
37
 
 
38
static DWORD dbus_cond_event_tls = TLS_OUT_OF_INDEXES;
 
39
 
 
40
 
 
41
static HMODULE dbus_dll_hmodule;
 
42
 
 
43
void *
 
44
_dbus_win_get_dll_hmodule (void)
 
45
{
 
46
  return dbus_dll_hmodule;
 
47
}
 
48
 
 
49
#ifdef DBUS_WINCE
 
50
#define hinst_t HANDLE
 
51
#else
 
52
#define hinst_t HINSTANCE
 
53
#endif
 
54
 
 
55
BOOL WINAPI DllMain (hinst_t, DWORD, LPVOID);
 
56
 
 
57
/* We need this to free the TLS events on thread exit */
 
58
BOOL WINAPI
 
59
DllMain (hinst_t hinstDLL,
 
60
         DWORD     fdwReason,
 
61
         LPVOID    lpvReserved)
 
62
{
 
63
  HANDLE event;
 
64
  switch (fdwReason) 
 
65
    { 
 
66
    case DLL_PROCESS_ATTACH:
 
67
      dbus_dll_hmodule = hinstDLL;
 
68
      break;
 
69
    case DLL_THREAD_DETACH:
 
70
      if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
 
71
        {
 
72
          event = TlsGetValue(dbus_cond_event_tls);
 
73
          CloseHandle (event);
 
74
          TlsSetValue(dbus_cond_event_tls, NULL);
 
75
        }
 
76
      break;
 
77
    case DLL_PROCESS_DETACH: 
 
78
      if (dbus_cond_event_tls != TLS_OUT_OF_INDEXES)
 
79
        {
 
80
          event = TlsGetValue(dbus_cond_event_tls);
 
81
          CloseHandle (event);
 
82
          TlsSetValue(dbus_cond_event_tls, NULL);
 
83
 
 
84
          TlsFree(dbus_cond_event_tls); 
 
85
        }
 
86
      break;
 
87
    default: 
 
88
      break; 
 
89
    }
 
90
  return TRUE;
 
91
}
 
92
 
 
93
static DBusMutex*
 
94
_dbus_windows_mutex_new (void)
 
95
{
 
96
  HANDLE handle;
 
97
  handle = CreateMutex (NULL, FALSE, NULL);
 
98
  return (DBusMutex *) handle;
 
99
}
 
100
 
 
101
static void
 
102
_dbus_windows_mutex_free (DBusMutex *mutex)
 
103
{
 
104
  CloseHandle ((HANDLE *) mutex);
 
105
}
 
106
 
 
107
static dbus_bool_t
 
108
_dbus_windows_mutex_lock (DBusMutex *mutex)
 
109
{
 
110
  return WaitForSingleObject ((HANDLE *) mutex, INFINITE) != WAIT_FAILED;
 
111
}
 
112
 
 
113
static dbus_bool_t
 
114
_dbus_windows_mutex_unlock (DBusMutex *mutex)
 
115
{
 
116
  return ReleaseMutex ((HANDLE *) mutex) != 0;
 
117
}
 
118
 
 
119
static DBusCondVar *
 
120
_dbus_windows_condvar_new (void)
 
121
{
 
122
  DBusCondVar *cond;
 
123
    
 
124
  cond = dbus_new (DBusCondVar, 1);
 
125
  if (cond == NULL)
 
126
    return NULL;
 
127
  
 
128
  cond->list = NULL;
 
129
  
 
130
  InitializeCriticalSection (&cond->lock);
 
131
  return (DBusCondVar *) cond;
 
132
}
 
133
 
 
134
static void
 
135
_dbus_windows_condvar_free (DBusCondVar *cond)
 
136
{
 
137
  DeleteCriticalSection (&cond->lock);
 
138
  _dbus_list_clear (&cond->list);
 
139
  dbus_free (cond);
 
140
}
 
141
 
 
142
static dbus_bool_t
 
143
_dbus_condvar_wait_win32 (DBusCondVar *cond,
 
144
                          DBusMutex *mutex,
 
145
                          int milliseconds)
 
146
{
 
147
  DWORD retval;
 
148
  dbus_bool_t ret;
 
149
  HANDLE event = TlsGetValue (dbus_cond_event_tls);
 
150
 
 
151
  if (!event)
 
152
    {
 
153
      event = CreateEvent (0, FALSE, FALSE, NULL);
 
154
      if (event == 0)
 
155
        return FALSE;
 
156
      TlsSetValue (dbus_cond_event_tls, event);
 
157
    }
 
158
 
 
159
  EnterCriticalSection (&cond->lock);
 
160
 
 
161
  /* The event must not be signaled. Check this */
 
162
  _dbus_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT);
 
163
 
 
164
  ret = _dbus_list_append (&cond->list, event);
 
165
  
 
166
  LeaveCriticalSection (&cond->lock);
 
167
  
 
168
  if (!ret)
 
169
    return FALSE; /* Prepend failed */
 
170
 
 
171
  _dbus_mutex_unlock (mutex);
 
172
  retval = WaitForSingleObject (event, milliseconds);
 
173
  _dbus_mutex_lock (mutex);
 
174
  
 
175
  if (retval == WAIT_TIMEOUT)
 
176
    {
 
177
      EnterCriticalSection (&cond->lock);
 
178
      _dbus_list_remove (&cond->list, event);
 
179
 
 
180
      /* In the meantime we could have been signaled, so we must again
 
181
       * wait for the signal, this time with no timeout, to reset
 
182
       * it. retval is set again to honour the late arrival of the
 
183
       * signal */
 
184
      retval = WaitForSingleObject (event, 0);
 
185
 
 
186
      LeaveCriticalSection (&cond->lock);
 
187
    }
 
188
 
 
189
#ifndef DBUS_DISABLE_ASSERT
 
190
  EnterCriticalSection (&cond->lock);
 
191
 
 
192
  /* Now event must not be inside the array, check this */
 
193
  _dbus_assert (_dbus_list_remove (&cond->list, event) == FALSE);
 
194
 
 
195
  LeaveCriticalSection (&cond->lock);
 
196
#endif /* !G_DISABLE_ASSERT */
 
197
 
 
198
  return retval != WAIT_TIMEOUT;
 
199
}
 
200
 
 
201
static void
 
202
_dbus_windows_condvar_wait (DBusCondVar *cond,
 
203
                            DBusMutex   *mutex)
 
204
{
 
205
  _dbus_condvar_wait_win32 (cond, mutex, INFINITE);
 
206
}
 
207
 
 
208
static dbus_bool_t
 
209
_dbus_windows_condvar_wait_timeout (DBusCondVar               *cond,
 
210
                                     DBusMutex                 *mutex,
 
211
                                     int                        timeout_milliseconds)
 
212
{
 
213
  return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds);
 
214
}
 
215
 
 
216
static void
 
217
_dbus_windows_condvar_wake_one (DBusCondVar *cond)
 
218
{
 
219
  EnterCriticalSection (&cond->lock);
 
220
  
 
221
  if (cond->list != NULL)
 
222
    SetEvent (_dbus_list_pop_first (&cond->list));
 
223
    
 
224
  LeaveCriticalSection (&cond->lock);
 
225
}
 
226
 
 
227
static void
 
228
_dbus_windows_condvar_wake_all (DBusCondVar *cond)
 
229
{
 
230
  EnterCriticalSection (&cond->lock);
 
231
 
 
232
  while (cond->list != NULL)
 
233
    SetEvent (_dbus_list_pop_first (&cond->list));
 
234
  
 
235
  LeaveCriticalSection (&cond->lock);
 
236
}
 
237
 
 
238
static const DBusThreadFunctions windows_functions =
 
239
{
 
240
  DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
 
241
  DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
 
242
  DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
 
243
  DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
 
244
  DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
 
245
  DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
 
246
  DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
 
247
  DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
 
248
  DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
 
249
  DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
 
250
  _dbus_windows_mutex_new,
 
251
  _dbus_windows_mutex_free,
 
252
  _dbus_windows_mutex_lock,
 
253
  _dbus_windows_mutex_unlock,
 
254
  _dbus_windows_condvar_new,
 
255
  _dbus_windows_condvar_free,
 
256
  _dbus_windows_condvar_wait,
 
257
  _dbus_windows_condvar_wait_timeout,
 
258
  _dbus_windows_condvar_wake_one,
 
259
  _dbus_windows_condvar_wake_all
 
260
};
 
261
 
 
262
dbus_bool_t
 
263
_dbus_threads_init_platform_specific (void)
 
264
{
 
265
  /* We reuse this over several generations, because we can't
 
266
   * free the events once they are in use
 
267
   */
 
268
  if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
 
269
    {
 
270
      dbus_cond_event_tls = TlsAlloc ();
 
271
      if (dbus_cond_event_tls == TLS_OUT_OF_INDEXES)
 
272
        return FALSE;
 
273
    }
 
274
 
 
275
  return dbus_threads_init (&windows_functions);
 
276
}
 
277