root/opal/mca/event/libevent2022/libevent/evthread_win32.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. evthread_win32_lock_create
  2. evthread_win32_lock_free
  3. evthread_win32_lock
  4. evthread_win32_unlock
  5. evthread_win32_get_id
  6. evthread_win32_condvar_init
  7. evthread_win32_condvar_alloc
  8. evthread_win32_condvar_free
  9. evthread_win32_condvar_signal
  10. evthread_win32_condvar_wait
  11. evthread_win32_cond_alloc
  12. evthread_win32_cond_free
  13. evthread_win32_cond_signal
  14. evthread_win32_cond_wait
  15. evthread_use_windows_threads

   1 /*
   2  * Copyright 2009-2012 Niels Provos and Nick Mathewson
   3  *
   4  * Redistribution and use in source and binary forms, with or without
   5  * modification, are permitted provided that the following conditions
   6  * are met:
   7  * 1. Redistributions of source code must retain the above copyright
   8  *    notice, this list of conditions and the following disclaimer.
   9  * 2. Redistributions in binary form must reproduce the above copyright
  10  *    notice, this list of conditions and the following disclaimer in the
  11  *    documentation and/or other materials provided with the distribution.
  12  * 3. The name of the author may not be used to endorse or promote products
  13  *    derived from this software without specific prior written permission.
  14  *
  15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25  */
  26 #include "event2/event-config.h"
  27 
  28 #ifdef WIN32
  29 #ifndef _WIN32_WINNT
  30 /* Minimum required for InitializeCriticalSectionAndSpinCount */
  31 #define _WIN32_WINNT 0x0403
  32 #endif
  33 #include <winsock2.h>
  34 #define WIN32_LEAN_AND_MEAN
  35 #include <windows.h>
  36 #undef WIN32_LEAN_AND_MEAN
  37 #include <sys/locking.h>
  38 #endif
  39 
  40 struct event_base;
  41 #include "event2/thread.h"
  42 
  43 #include "mm-internal.h"
  44 #include "evthread-internal.h"
  45 
  46 #define SPIN_COUNT 2000
  47 
  48 static void *
  49 evthread_win32_lock_create(unsigned locktype)
  50 {
  51         CRITICAL_SECTION *lock = mm_malloc(sizeof(CRITICAL_SECTION));
  52         if (!lock)
  53                 return NULL;
  54         if (InitializeCriticalSectionAndSpinCount(lock, SPIN_COUNT) == 0) {
  55                 mm_free(lock);
  56                 return NULL;
  57         }
  58         return lock;
  59 }
  60 
  61 static void
  62 evthread_win32_lock_free(void *_lock, unsigned locktype)
  63 {
  64         CRITICAL_SECTION *lock = _lock;
  65         DeleteCriticalSection(lock);
  66         mm_free(lock);
  67 }
  68 
  69 static int
  70 evthread_win32_lock(unsigned mode, void *_lock)
  71 {
  72         CRITICAL_SECTION *lock = _lock;
  73         if ((mode & EVTHREAD_TRY)) {
  74                 return ! TryEnterCriticalSection(lock);
  75         } else {
  76                 EnterCriticalSection(lock);
  77                 return 0;
  78         }
  79 }
  80 
  81 static int
  82 evthread_win32_unlock(unsigned mode, void *_lock)
  83 {
  84         CRITICAL_SECTION *lock = _lock;
  85         LeaveCriticalSection(lock);
  86         return 0;
  87 }
  88 
  89 static unsigned long
  90 evthread_win32_get_id(void)
  91 {
  92         return (unsigned long) GetCurrentThreadId();
  93 }
  94 
  95 #ifdef WIN32_HAVE_CONDITION_VARIABLES
  96 static void WINAPI (*InitializeConditionVariable_fn)(PCONDITION_VARIABLE)
  97         = NULL;
  98 static BOOL WINAPI (*SleepConditionVariableCS_fn)(
  99         PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD) = NULL;
 100 static void WINAPI (*WakeAllConditionVariable_fn)(PCONDITION_VARIABLE) = NULL;
 101 static void WINAPI (*WakeConditionVariable_fn)(PCONDITION_VARIABLE) = NULL;
 102 
 103 static int
 104 evthread_win32_condvar_init(void)
 105 {
 106         HANDLE lib;
 107 
 108         lib = GetModuleHandle(TEXT("kernel32.dll"));
 109         if (lib == NULL)
 110                 return 0;
 111 
 112 #define LOAD(name)                              \
 113         name##_fn = GetProcAddress(lib, #name)
 114         LOAD(InitializeConditionVariable);
 115         LOAD(SleepConditionVariableCS);
 116         LOAD(WakeAllConditionVariable);
 117         LOAD(WakeConditionVariable);
 118 
 119         return InitializeConditionVariable_fn && SleepConditionVariableCS_fn &&
 120             WakeAllConditionVariable_fn && WakeConditionVariable_fn;
 121 }
 122 
 123 /* XXXX Even if we can build this, we don't necessarily want to: the functions
 124  * in question didn't exist before Vista, so we'd better LoadProc them. */
 125 static void *
 126 evthread_win32_condvar_alloc(unsigned condflags)
 127 {
 128         CONDITION_VARIABLE *cond = mm_malloc(sizeof(CONDITION_VARIABLE));
 129         if (!cond)
 130                 return NULL;
 131         InitializeConditionVariable_fn(cond);
 132         return cond;
 133 }
 134 
 135 static void
 136 evthread_win32_condvar_free(void *_cond)
 137 {
 138         CONDITION_VARIABLE *cond = _cond;
 139         /* There doesn't _seem_ to be a cleaup fn here... */
 140         mm_free(cond);
 141 }
 142 
 143 static int
 144 evthread_win32_condvar_signal(void *_cond, int broadcast)
 145 {
 146         CONDITION_VARIABLE *cond = _cond;
 147         if (broadcast)
 148                 WakeAllConditionVariable_fn(cond);
 149         else
 150                 WakeConditionVariable_fn(cond);
 151         return 0;
 152 }
 153 
 154 static int
 155 evthread_win32_condvar_wait(void *_cond, void *_lock, const struct timeval *tv)
 156 {
 157         CONDITION_VARIABLE *cond = _cond;
 158         CRITICAL_SECTION *lock = _lock;
 159         DWORD ms, err;
 160         BOOL result;
 161 
 162         if (tv)
 163                 ms = evutil_tv_to_msec(tv);
 164         else
 165                 ms = INFINITE;
 166         result = SleepConditionVariableCS_fn(cond, lock, ms);
 167         if (result) {
 168                 if (GetLastError() == WAIT_TIMEOUT)
 169                         return 1;
 170                 else
 171                         return -1;
 172         } else {
 173                 return 0;
 174         }
 175 }
 176 #endif
 177 
 178 struct evthread_win32_cond {
 179         HANDLE event;
 180 
 181         CRITICAL_SECTION lock;
 182         int n_waiting;
 183         int n_to_wake;
 184         int generation;
 185 };
 186 
 187 static void *
 188 evthread_win32_cond_alloc(unsigned flags)
 189 {
 190         struct evthread_win32_cond *cond;
 191         if (!(cond = mm_malloc(sizeof(struct evthread_win32_cond))))
 192                 return NULL;
 193         if (InitializeCriticalSectionAndSpinCount(&cond->lock, SPIN_COUNT)==0) {
 194                 mm_free(cond);
 195                 return NULL;
 196         }
 197         if ((cond->event = CreateEvent(NULL,TRUE,FALSE,NULL)) == NULL) {
 198                 DeleteCriticalSection(&cond->lock);
 199                 mm_free(cond);
 200                 return NULL;
 201         }
 202         cond->n_waiting = cond->n_to_wake = cond->generation = 0;
 203         return cond;
 204 }
 205 
 206 static void
 207 evthread_win32_cond_free(void *_cond)
 208 {
 209         struct evthread_win32_cond *cond = _cond;
 210         DeleteCriticalSection(&cond->lock);
 211         CloseHandle(cond->event);
 212         mm_free(cond);
 213 }
 214 
 215 static int
 216 evthread_win32_cond_signal(void *_cond, int broadcast)
 217 {
 218         struct evthread_win32_cond *cond = _cond;
 219         EnterCriticalSection(&cond->lock);
 220         if (broadcast)
 221                 cond->n_to_wake = cond->n_waiting;
 222         else
 223                 ++cond->n_to_wake;
 224         cond->generation++;
 225         SetEvent(cond->event);
 226         LeaveCriticalSection(&cond->lock);
 227         return 0;
 228 }
 229 
 230 static int
 231 evthread_win32_cond_wait(void *_cond, void *_lock, const struct timeval *tv)
 232 {
 233         struct evthread_win32_cond *cond = _cond;
 234         CRITICAL_SECTION *lock = _lock;
 235         int generation_at_start;
 236         int waiting = 1;
 237         int result = -1;
 238         DWORD ms = INFINITE, ms_orig = INFINITE, startTime, endTime;
 239         if (tv)
 240                 ms_orig = ms = evutil_tv_to_msec(tv);
 241 
 242         EnterCriticalSection(&cond->lock);
 243         ++cond->n_waiting;
 244         generation_at_start = cond->generation;
 245         LeaveCriticalSection(&cond->lock);
 246 
 247         LeaveCriticalSection(lock);
 248 
 249         startTime = GetTickCount();
 250         do {
 251                 DWORD res;
 252                 res = WaitForSingleObject(cond->event, ms);
 253                 EnterCriticalSection(&cond->lock);
 254                 if (cond->n_to_wake &&
 255                     cond->generation != generation_at_start) {
 256                         --cond->n_to_wake;
 257                         --cond->n_waiting;
 258                         result = 0;
 259                         waiting = 0;
 260                         goto out;
 261                 } else if (res != WAIT_OBJECT_0) {
 262                         result = (res==WAIT_TIMEOUT) ? 1 : -1;
 263                         --cond->n_waiting;
 264                         waiting = 0;
 265                         goto out;
 266                 } else if (ms != INFINITE) {
 267                         endTime = GetTickCount();
 268                         if (startTime + ms_orig <= endTime) {
 269                                 result = 1; /* Timeout */
 270                                 --cond->n_waiting;
 271                                 waiting = 0;
 272                                 goto out;
 273                         } else {
 274                                 ms = startTime + ms_orig - endTime;
 275                         }
 276                 }
 277                 /* If we make it here, we are still waiting. */
 278                 if (cond->n_to_wake == 0) {
 279                         /* There is nobody else who should wake up; reset
 280                          * the event. */
 281                         ResetEvent(cond->event);
 282                 }
 283         out:
 284                 LeaveCriticalSection(&cond->lock);
 285         } while (waiting);
 286 
 287         EnterCriticalSection(lock);
 288 
 289         EnterCriticalSection(&cond->lock);
 290         if (!cond->n_waiting)
 291                 ResetEvent(cond->event);
 292         LeaveCriticalSection(&cond->lock);
 293 
 294         return result;
 295 }
 296 
 297 int
 298 evthread_use_windows_threads(void)
 299 {
 300         struct evthread_lock_callbacks cbs = {
 301                 EVTHREAD_LOCK_API_VERSION,
 302                 EVTHREAD_LOCKTYPE_RECURSIVE,
 303                 evthread_win32_lock_create,
 304                 evthread_win32_lock_free,
 305                 evthread_win32_lock,
 306                 evthread_win32_unlock
 307         };
 308 
 309 
 310         struct evthread_condition_callbacks cond_cbs = {
 311                 EVTHREAD_CONDITION_API_VERSION,
 312                 evthread_win32_cond_alloc,
 313                 evthread_win32_cond_free,
 314                 evthread_win32_cond_signal,
 315                 evthread_win32_cond_wait
 316         };
 317 #ifdef WIN32_HAVE_CONDITION_VARIABLES
 318         struct evthread_condition_callbacks condvar_cbs = {
 319                 EVTHREAD_CONDITION_API_VERSION,
 320                 evthread_win32_condvar_alloc,
 321                 evthread_win32_condvar_free,
 322                 evthread_win32_condvar_signal,
 323                 evthread_win32_condvar_wait
 324         };
 325 #endif
 326 
 327         evthread_set_lock_callbacks(&cbs);
 328         evthread_set_id_callback(evthread_win32_get_id);
 329 #ifdef WIN32_HAVE_CONDITION_VARIABLES
 330         if (evthread_win32_condvar_init()) {
 331                 evthread_set_condition_callbacks(&condvar_cbs);
 332                 return 0;
 333         }
 334 #endif
 335         evthread_set_condition_callbacks(&cond_cbs);
 336 
 337         return 0;
 338 }
 339 

/* [<][>][^][v][top][bottom][index][help] */