1009b811d678f36cf63be4fe26f3fbaa38aa0078eSerhiy Storchaka/* 2e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * Portable condition variable support for windows and pthreads. 3e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * Everything is inline, this header can be included where needed. 4e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * 5e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * APIs generally return 0 on success and non-zero on error, 6e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * and the caller needs to use its platform's error mechanism to 7e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * discover the error (errno, or GetLastError()) 8e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * 9e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * Note that some implementations cannot distinguish between a 10e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * condition variable wait time-out and successful wait. Most often 11e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * the difference is moot anyway since the wait condition must be 12e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * re-checked. 13e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * PyCOND_TIMEDWAIT, in addition to returning negative on error, 14e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * thus returns 0 on regular success, 1 on timeout 15e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * or 2 if it can't tell. 160006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * 170006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * There are at least two caveats with using these condition variables, 180006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * due to the fact that they may be emulated with Semaphores on 190006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * Windows: 200006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * 1) While PyCOND_SIGNAL() will wake up at least one thread, we 210006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * cannot currently guarantee that it will be one of the threads 220006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * already waiting in a PyCOND_WAIT() call. It _could_ cause 230006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * the wakeup of a subsequent thread to try a PyCOND_WAIT(), 240006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * including the thread doing the PyCOND_SIGNAL() itself. 250006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * The same applies to PyCOND_BROADCAST(), if N threads are waiting 260006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * then at least N threads will be woken up, but not necessarily 270006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * those already waiting. 280006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * For this reason, don't make the scheduling assumption that a 290006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * specific other thread will get the wakeup signal 300006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * 2) The _mutex_ must be held when calling PyCOND_SIGNAL() and 310006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * PyCOND_BROADCAST(). 320006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * While e.g. the posix standard strongly recommends that the mutex 330006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * associated with the condition variable is held when a 340006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * pthread_cond_signal() call is made, this is not a hard requirement, 350006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * although scheduling will not be "reliable" if it isn't. Here 360006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * the mutex is used for internal synchronization of the emulated 370006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson * Condition Variable. 38e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson */ 39e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 40e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#ifndef _CONDVAR_H_ 41e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define _CONDVAR_H_ 42e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 43e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#include "Python.h" 44e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 45e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#ifndef _POSIX_THREADS 46e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* This means pthreads are not implemented in libc headers, hence the macro 47e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson not present in unistd.h. But they still can be implemented as an external 48e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson library (e.g. gnu pth in pthread emulation) */ 49e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson# ifdef HAVE_PTHREAD_H 50e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson# include <pthread.h> /* _POSIX_THREADS */ 51e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson# endif 52e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#endif 53e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 54e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#ifdef _POSIX_THREADS 55e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* 56e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * POSIX support 57e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson */ 58e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define Py_HAVE_CONDVAR 59e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 60e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#include <pthread.h> 61e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 62e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define PyCOND_ADD_MICROSECONDS(tv, interval) \ 6333096fe8296b57c6e634e58af1c632b8e2f5bc05Kristján Valur Jónssondo { /* TODO: add overflow and truncation checks */ \ 64e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson tv.tv_usec += (long) interval; \ 65e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson tv.tv_sec += tv.tv_usec / 1000000; \ 66e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson tv.tv_usec %= 1000000; \ 67e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} while (0) 68e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 69e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* We assume all modern POSIX systems have gettimeofday() */ 70e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#ifdef GETTIMEOFDAY_NO_TZ 71e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define PyCOND_GETTIMEOFDAY(ptv) gettimeofday(ptv) 72e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#else 73e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define PyCOND_GETTIMEOFDAY(ptv) gettimeofday(ptv, (struct timezone *)NULL) 74e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#endif 75e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 76e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* The following functions return 0 on success, nonzero on error */ 77e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define PyMUTEX_T pthread_mutex_t 78e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define PyMUTEX_INIT(mut) pthread_mutex_init((mut), NULL) 79e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define PyMUTEX_FINI(mut) pthread_mutex_destroy(mut) 80e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define PyMUTEX_LOCK(mut) pthread_mutex_lock(mut) 81e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define PyMUTEX_UNLOCK(mut) pthread_mutex_unlock(mut) 82e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 83e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define PyCOND_T pthread_cond_t 84e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define PyCOND_INIT(cond) pthread_cond_init((cond), NULL) 85e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define PyCOND_FINI(cond) pthread_cond_destroy(cond) 86e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define PyCOND_SIGNAL(cond) pthread_cond_signal(cond) 87e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define PyCOND_BROADCAST(cond) pthread_cond_broadcast(cond) 88e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define PyCOND_WAIT(cond, mut) pthread_cond_wait((cond), (mut)) 89e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 90e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* return 0 for success, 1 on timeout, -1 on error */ 91e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 92af580dff4af3cb812cdd7a229a4a65059b3bc1eeBenjamin PetersonPyCOND_TIMEDWAIT(PyCOND_T *cond, PyMUTEX_T *mut, long long us) 93e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 94e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson int r; 95e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson struct timespec ts; 96e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson struct timeval deadline; 97e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 98e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson PyCOND_GETTIMEOFDAY(&deadline); 99e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson PyCOND_ADD_MICROSECONDS(deadline, us); 100e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson ts.tv_sec = deadline.tv_sec; 101e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson ts.tv_nsec = deadline.tv_usec * 1000; 102e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 103e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson r = pthread_cond_timedwait((cond), (mut), &ts); 104e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson if (r == ETIMEDOUT) 105e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 1; 106e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson else if (r) 107e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return -1; 108009b811d678f36cf63be4fe26f3fbaa38aa0078eSerhiy Storchaka else 109e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 110e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 111e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 112e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#elif defined(NT_THREADS) 113e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* 114e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * Windows (XP, 2003 server and later, as well as (hopefully) CE) support 115e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * 116e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * Emulated condition variables ones that work with XP and later, plus 117e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * example native support on VISTA and onwards. 118e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson */ 119e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define Py_HAVE_CONDVAR 120e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 121e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 122e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* include windows if it hasn't been done before */ 123e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define WIN32_LEAN_AND_MEAN 124e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#include <windows.h> 125e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 126e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* options */ 127e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* non-emulated condition variables are provided for those that want 128e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * to target Windows Vista. Modify this macro to enable them. 129e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson */ 130e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#ifndef _PY_EMULATED_WIN_CV 131e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define _PY_EMULATED_WIN_CV 1 /* use emulated condition variables */ 132e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#endif 133e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 134e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* fall back to emulation if not targeting Vista */ 135e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#if !defined NTDDI_VISTA || NTDDI_VERSION < NTDDI_VISTA 136e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#undef _PY_EMULATED_WIN_CV 137e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#define _PY_EMULATED_WIN_CV 1 138e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#endif 139e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 140e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 141e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#if _PY_EMULATED_WIN_CV 142e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 143e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* The mutex is a CriticalSection object and 144e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson The condition variables is emulated with the help of a semaphore. 145e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson Semaphores are available on Windows XP (2003 server) and later. 146e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson We use a Semaphore rather than an auto-reset event, because although 147e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson an auto-resent event might appear to solve the lost-wakeup bug (race 148e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson condition between releasing the outer lock and waiting) because it 149e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson maintains state even though a wait hasn't happened, there is still 150e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson a lost wakeup problem if more than one thread are interrupted in the 151e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson critical place. A semaphore solves that, because its state is counted, 152e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson not Boolean. 153e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson Because it is ok to signal a condition variable with no one 154e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson waiting, we need to keep track of the number of 155e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson waiting threads. Otherwise, the semaphore's state could rise 156e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson without bound. This also helps reduce the number of "spurious wakeups" 157e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson that would otherwise happen. 158e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 1590006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson This implementation still has the problem that the threads woken 1600006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson with a "signal" aren't necessarily those that are already 1610006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson waiting. It corresponds to listing 2 in: 1620006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson http://birrell.org/andrew/papers/ImplementingCVs.pdf 1630006aacb9dda6d62013c86aac47d977b3f04921aKristjan Valur Jonsson 164e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson Generic emulations of the pthread_cond_* API using 165e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson earlier Win32 functions can be found on the Web. 16632ecccaf632ba1219734249f528a451076290386Kristján Valur Jónsson The following read can be give background information to these issues, 16732ecccaf632ba1219734249f528a451076290386Kristján Valur Jónsson but the implementations are all broken in some way. 168e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson http://www.cse.wustl.edu/~schmidt/win32-cv-1.html 169e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson*/ 170e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 171e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónssontypedef CRITICAL_SECTION PyMUTEX_T; 172e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 173e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 174e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyMUTEX_INIT(PyMUTEX_T *cs) 175e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 176e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson InitializeCriticalSection(cs); 177e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 178e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 179e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 180e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 181e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyMUTEX_FINI(PyMUTEX_T *cs) 182e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 183e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson DeleteCriticalSection(cs); 184e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 185e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 186e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 187e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 188e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyMUTEX_LOCK(PyMUTEX_T *cs) 189e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 190e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson EnterCriticalSection(cs); 191e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 192e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 193e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 194e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 195e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyMUTEX_UNLOCK(PyMUTEX_T *cs) 196e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 197e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson LeaveCriticalSection(cs); 198e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 199e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 200e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 201e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* The ConditionVariable object. From XP onwards it is easily emulated with 202e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * a Semaphore 203e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson */ 204e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 205e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónssontypedef struct _PyCOND_T 206e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 207e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson HANDLE sem; 2081617077bccc4ff0c3d54d066af4c3cfd532cf3faKristjan Valur Jonsson int waiting; /* to allow PyCOND_SIGNAL to be a no-op */ 209e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} PyCOND_T; 210e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 211e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 212e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyCOND_INIT(PyCOND_T *cv) 213e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 214e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson /* A semaphore with a "large" max value, The positive value 215e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * is only needed to catch those "lost wakeup" events and 216e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * race conditions when a timed wait elapses. 217e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson */ 218e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson cv->sem = CreateSemaphore(NULL, 0, 100000, NULL); 219e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson if (cv->sem==NULL) 220e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return -1; 221e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson cv->waiting = 0; 222e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 223e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 224e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 225e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 226e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyCOND_FINI(PyCOND_T *cv) 227e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 228e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return CloseHandle(cv->sem) ? 0 : -1; 229e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 230e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 231e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* this implementation can detect a timeout. Returns 1 on timeout, 232e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * 0 otherwise (and -1 on error) 233e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson */ 234e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 235e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson_PyCOND_WAIT_MS(PyCOND_T *cv, PyMUTEX_T *cs, DWORD ms) 236e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 237e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson DWORD wait; 238e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson cv->waiting++; 239e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson PyMUTEX_UNLOCK(cs); 240e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson /* "lost wakeup bug" would occur if the caller were interrupted here, 24115f44ab043b37c064d6891c7864205fed9fb0dd1Raymond Hettinger * but we are safe because we are using a semaphore which has an internal 242e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * count. 243e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson */ 244b26a9b10ea5f095da0c699e41b29a724021cd09aMartin v. Löwis wait = WaitForSingleObjectEx(cv->sem, ms, FALSE); 245e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson PyMUTEX_LOCK(cs); 246e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson if (wait != WAIT_OBJECT_0) 247e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson --cv->waiting; 248e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson /* Here we have a benign race condition with PyCOND_SIGNAL. 249e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * When failure occurs or timeout, it is possible that 250e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * PyCOND_SIGNAL also decrements this value 251e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * and signals releases the mutex. This is benign because it 252e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * just means an extra spurious wakeup for a waiting thread. 2531617077bccc4ff0c3d54d066af4c3cfd532cf3faKristjan Valur Jonsson * ('waiting' corresponds to the semaphore's "negative" count and 2541617077bccc4ff0c3d54d066af4c3cfd532cf3faKristjan Valur Jonsson * we may end up with e.g. (waiting == -1 && sem.count == 1). When 2551617077bccc4ff0c3d54d066af4c3cfd532cf3faKristjan Valur Jonsson * a new thread comes along, it will pass right throuhgh, having 2561617077bccc4ff0c3d54d066af4c3cfd532cf3faKristjan Valur Jonsson * adjusted it to (waiting == 0 && sem.count == 0). 257e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson */ 258009b811d678f36cf63be4fe26f3fbaa38aa0078eSerhiy Storchaka 259e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson if (wait == WAIT_FAILED) 260e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return -1; 261e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson /* return 0 on success, 1 on timeout */ 262e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return wait != WAIT_OBJECT_0; 263e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 264e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 265e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 266e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyCOND_WAIT(PyCOND_T *cv, PyMUTEX_T *cs) 267e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 268e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson int result = _PyCOND_WAIT_MS(cv, cs, INFINITE); 269e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return result >= 0 ? 0 : result; 270e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 271e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 272e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 273af580dff4af3cb812cdd7a229a4a65059b3bc1eeBenjamin PetersonPyCOND_TIMEDWAIT(PyCOND_T *cv, PyMUTEX_T *cs, long long us) 274e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 27533096fe8296b57c6e634e58af1c632b8e2f5bc05Kristján Valur Jónsson return _PyCOND_WAIT_MS(cv, cs, (DWORD)(us/1000)); 276e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 277e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 278e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 279e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyCOND_SIGNAL(PyCOND_T *cv) 280e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 2811617077bccc4ff0c3d54d066af4c3cfd532cf3faKristjan Valur Jonsson /* this test allows PyCOND_SIGNAL to be a no-op unless required 2821617077bccc4ff0c3d54d066af4c3cfd532cf3faKristjan Valur Jonsson * to wake someone up, thus preventing an unbounded increase of 2831617077bccc4ff0c3d54d066af4c3cfd532cf3faKristjan Valur Jonsson * the semaphore's internal counter. 2841617077bccc4ff0c3d54d066af4c3cfd532cf3faKristjan Valur Jonsson */ 2851617077bccc4ff0c3d54d066af4c3cfd532cf3faKristjan Valur Jonsson if (cv->waiting > 0) { 286e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson /* notifying thread decreases the cv->waiting count so that 2871617077bccc4ff0c3d54d066af4c3cfd532cf3faKristjan Valur Jonsson * a delay between notify and actual wakeup of the target thread 2881617077bccc4ff0c3d54d066af4c3cfd532cf3faKristjan Valur Jonsson * doesn't cause a number of extra ReleaseSemaphore calls. 289e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson */ 290e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson cv->waiting--; 291e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return ReleaseSemaphore(cv->sem, 1, NULL) ? 0 : -1; 292e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson } 293e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 294e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 295e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 296e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 297e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyCOND_BROADCAST(PyCOND_T *cv) 298e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 29932ecccaf632ba1219734249f528a451076290386Kristján Valur Jónsson int waiting = cv->waiting; 30032ecccaf632ba1219734249f528a451076290386Kristján Valur Jónsson if (waiting > 0) { 30132ecccaf632ba1219734249f528a451076290386Kristján Valur Jónsson cv->waiting = 0; 30232ecccaf632ba1219734249f528a451076290386Kristján Valur Jónsson return ReleaseSemaphore(cv->sem, waiting, NULL) ? 0 : -1; 303e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson } 304e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 305e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 306e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 307e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#else 308e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 309e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* Use native Win7 primitives if build target is Win7 or higher */ 310e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 311e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* SRWLOCK is faster and better than CriticalSection */ 312e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónssontypedef SRWLOCK PyMUTEX_T; 313e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 314e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 315e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyMUTEX_INIT(PyMUTEX_T *cs) 316e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 317e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson InitializeSRWLock(cs); 318e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 319e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 320e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 321e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 322e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyMUTEX_FINI(PyMUTEX_T *cs) 323e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 324e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 325e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 326e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 327e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 328e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyMUTEX_LOCK(PyMUTEX_T *cs) 329e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 330e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson AcquireSRWLockExclusive(cs); 331e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 332e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 333e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 334e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 335e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyMUTEX_UNLOCK(PyMUTEX_T *cs) 336e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 337e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson ReleaseSRWLockExclusive(cs); 338e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 339e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 340e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 341e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 342e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónssontypedef CONDITION_VARIABLE PyCOND_T; 343e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 344e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 345e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyCOND_INIT(PyCOND_T *cv) 346e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 347e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson InitializeConditionVariable(cv); 348e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 349e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 350e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 351e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyCOND_FINI(PyCOND_T *cv) 352e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 353e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 354e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 355e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 356e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 357e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyCOND_WAIT(PyCOND_T *cv, PyMUTEX_T *cs) 358e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 359e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return SleepConditionVariableSRW(cv, cs, INFINITE, 0) ? 0 : -1; 360e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 361e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 362e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson/* This implementation makes no distinction about timeouts. Signal 363e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson * 2 to indicate that we don't know. 364e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson */ 365e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 366af580dff4af3cb812cdd7a229a4a65059b3bc1eeBenjamin PetersonPyCOND_TIMEDWAIT(PyCOND_T *cv, PyMUTEX_T *cs, long long us) 367e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 36833096fe8296b57c6e634e58af1c632b8e2f5bc05Kristján Valur Jónsson return SleepConditionVariableSRW(cv, cs, (DWORD)(us/1000), 0) ? 2 : -1; 369e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 370e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 371e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 372e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyCOND_SIGNAL(PyCOND_T *cv) 373e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 374e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson WakeConditionVariable(cv); 375e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 376e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 377e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 378e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPy_LOCAL_INLINE(int) 379e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur JónssonPyCOND_BROADCAST(PyCOND_T *cv) 380e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson{ 381e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson WakeAllConditionVariable(cv); 382e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson return 0; 383e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson} 384e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 385e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 386e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#endif /* _PY_EMULATED_WIN_CV */ 387e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 388e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#endif /* _POSIX_THREADS, NT_THREADS */ 389e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson 390e75ff35af2b6c85d48c68b95f295aeac7396b162Kristján Valur Jónsson#endif /* _CONDVAR_H_ */ 391