summaryrefslogtreecommitdiff
path: root/mysys/my_wincond.c
diff options
context:
space:
mode:
Diffstat (limited to 'mysys/my_wincond.c')
-rw-r--r--mysys/my_wincond.c220
1 files changed, 186 insertions, 34 deletions
diff --git a/mysys/my_wincond.c b/mysys/my_wincond.c
index abe339d63b1..64cd67bf8d9 100644
--- a/mysys/my_wincond.c
+++ b/mysys/my_wincond.c
@@ -29,7 +29,92 @@
#include <process.h>
#include <sys/timeb.h>
-int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
+
+/*
+ Windows native condition variables. We use runtime loading / function
+ pointers, because they are not available on XP
+*/
+
+/* Prototypes and function pointers for condition variable functions */
+typedef void (WINAPI * InitializeConditionVariableProc)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef BOOL (WINAPI * SleepConditionVariableCSProc)
+ (PCONDITION_VARIABLE ConditionVariable,
+ PCRITICAL_SECTION CriticalSection,
+ DWORD dwMilliseconds);
+
+typedef void (WINAPI * WakeAllConditionVariableProc)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef void (WINAPI * WakeConditionVariableProc)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+static InitializeConditionVariableProc my_InitializeConditionVariable;
+static SleepConditionVariableCSProc my_SleepConditionVariableCS;
+static WakeAllConditionVariableProc my_WakeAllConditionVariable;
+static WakeConditionVariableProc my_WakeConditionVariable;
+
+
+/**
+ Indicates if we have native condition variables,
+ initialized first time pthread_cond_init is called.
+*/
+
+static BOOL have_native_conditions= FALSE;
+
+
+/**
+ Check if native conditions can be used, load function pointers
+*/
+
+static void check_native_cond_availability(void)
+{
+ HMODULE module= GetModuleHandle("kernel32");
+
+ my_InitializeConditionVariable= (InitializeConditionVariableProc)
+ GetProcAddress(module, "InitializeConditionVariable");
+ my_SleepConditionVariableCS= (SleepConditionVariableCSProc)
+ GetProcAddress(module, "SleepConditionVariableCS");
+ my_WakeAllConditionVariable= (WakeAllConditionVariableProc)
+ GetProcAddress(module, "WakeAllConditionVariable");
+ my_WakeConditionVariable= (WakeConditionVariableProc)
+ GetProcAddress(module, "WakeConditionVariable");
+
+ if (my_InitializeConditionVariable)
+ have_native_conditions= TRUE;
+}
+
+
+
+/**
+ Convert abstime to milliseconds
+*/
+
+static DWORD get_milliseconds(const struct timespec *abstime)
+{
+ struct timespec current_time;
+ long long ms;
+
+ if (abstime == NULL)
+ return INFINITE;
+
+ set_timespec_nsec(current_time, 0);
+ ms= (abstime->tv_sec - current_time.tv_sec)*1000LL +
+ (abstime->tv_nsec - current_time.tv_nsec)/1000000LL;
+ if(ms < 0 )
+ ms= 0;
+ if(ms > UINT_MAX)
+ ms= INFINITE;
+ return (DWORD)ms;
+}
+
+
+/*
+ Old (pre-vista) implementation using events
+*/
+
+static int legacy_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
{
cond->waiting= 0;
InitializeCriticalSection(&cond->lock_waiting);
@@ -58,7 +143,8 @@ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
return 0;
}
-int pthread_cond_destroy(pthread_cond_t *cond)
+
+static int legacy_cond_destroy(pthread_cond_t *cond)
{
DeleteCriticalSection(&cond->lock_waiting);
@@ -70,41 +156,26 @@ int pthread_cond_destroy(pthread_cond_t *cond)
}
-int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
-{
- return pthread_cond_timedwait(cond,mutex,NULL);
-}
-
-
-int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+static int legacy_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
struct timespec *abstime)
{
int result;
- long timeout;
- union ft64 now;
-
+ DWORD timeout;
+ long long timeout_us;
+ my_hrtime_t now;
+ my_hrtime_t then;
if( abstime != NULL )
{
- GetSystemTimeAsFileTime(&now.ft);
-
- /*
- Calculate time left to abstime
- - subtract start time from current time(values are in 100ns units)
- - convert to millisec by dividing with 10000
- */
- timeout= (long)((abstime->tv.i64 - now.i64) / 10000);
-
- /* Don't allow the timeout to be negative */
- if (timeout < 0)
- timeout= 0L;
-
- /*
- Make sure the calucated timeout does not exceed original timeout
- value which could cause "wait for ever" if system time changes
- */
- if (timeout > abstime->max_timeout_msec)
- timeout= abstime->max_timeout_msec;
-
+ now= my_hrtime();
+ then.val= 1000000ULL*abstime->tv_sec + abstime->tv_nsec/1000;
+ timeout_us= then.val - now.val;
+
+ if (timeout_us < 0)
+ timeout= 0;
+ else if (timeout_us > 1000ULL*INFINITE)
+ timeout= INFINITE;
+ else
+ timeout= (DWORD)(timeout_us/1000);
}
else
{
@@ -147,7 +218,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
}
-int pthread_cond_signal(pthread_cond_t *cond)
+static int legacy_cond_signal(pthread_cond_t *cond)
{
EnterCriticalSection(&cond->lock_waiting);
@@ -160,7 +231,7 @@ int pthread_cond_signal(pthread_cond_t *cond)
}
-int pthread_cond_broadcast(pthread_cond_t *cond)
+static int legacy_cond_broadcast(pthread_cond_t *cond)
{
EnterCriticalSection(&cond->lock_waiting);
/*
@@ -182,6 +253,87 @@ int pthread_cond_broadcast(pthread_cond_t *cond)
}
+/*
+ Posix API functions. Just choose between native and legacy implementation.
+*/
+
+int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
+{
+ /*
+ Once initialization is used here rather than in my_init(), to
+ 1) avoid my_init() pitfalls- undefined order in which initialization should
+ run
+ 2) be potentially useful C++ (in static constructors that run before main())
+ 3) just to simplify the API.
+ Also, the overhead of my_pthread_once is very small.
+ */
+ static my_pthread_once_t once_control= MY_PTHREAD_ONCE_INIT;
+ my_pthread_once(&once_control, check_native_cond_availability);
+
+ if (have_native_conditions)
+ {
+ my_InitializeConditionVariable(&cond->native_cond);
+ return 0;
+ }
+ else
+ return legacy_cond_init(cond, attr);
+}
+
+
+int pthread_cond_destroy(pthread_cond_t *cond)
+{
+ if (have_native_conditions)
+ return 0; /* no destroy function */
+ else
+ return legacy_cond_destroy(cond);
+}
+
+
+int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+ if (have_native_conditions)
+ {
+ my_WakeAllConditionVariable(&cond->native_cond);
+ return 0;
+ }
+ else
+ return legacy_cond_broadcast(cond);
+}
+
+
+int pthread_cond_signal(pthread_cond_t *cond)
+{
+ if (have_native_conditions)
+ {
+ my_WakeConditionVariable(&cond->native_cond);
+ return 0;
+ }
+ else
+ return legacy_cond_signal(cond);
+}
+
+
+int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ struct timespec *abstime)
+{
+ if (have_native_conditions)
+ {
+ DWORD timeout= get_milliseconds(abstime);
+ if (!my_SleepConditionVariableCS(&cond->native_cond, mutex, timeout))
+ return ETIMEDOUT;
+ return 0;
+ }
+ else
+ return legacy_cond_timedwait(cond, mutex, abstime);
+}
+
+
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ return pthread_cond_timedwait(cond, mutex, NULL);
+}
+
+
int pthread_attr_init(pthread_attr_t *connect_att)
{
connect_att->dwStackSize = 0;