From db39ffdbcc8c616b7010aa93f06637d87ee7ae02 Mon Sep 17 00:00:00 2001 From: Loo Rong Jie Date: Thu, 22 Jun 2017 09:03:29 +0800 Subject: [PATCH 1/3] Implement pthread_cond_t with Win32 CONDITION_VARIABLE Win32 CONDITION_VARIABLE has better performance and is easier to maintain. Since CONDITION_VARIABLE is not available in Windows XP and below, old implementation of pthread_cond_t is kept under define guard 'GIT_WIN_XP_SUPPORT'. To enable old implementation, build with make CFLAGS="-DGIT_WIN_XP_SUPPORT". Signed-off-by: Loo Rong Jie fast-forwarded. --- compat/win32/pthread.c | 40 ++++++++++++++++++++++++++++++++++++++++ compat/win32/pthread.h | 4 ++++ 2 files changed, 44 insertions(+) diff --git a/compat/win32/pthread.c b/compat/win32/pthread.c index e18f5c6e2e55a4..80243b67cb8dc1 100644 --- a/compat/win32/pthread.c +++ b/compat/win32/pthread.c @@ -57,6 +57,8 @@ pthread_t pthread_self(void) return t; } +#ifdef GIT_WIN_XP_SUPPORT + int pthread_cond_init(pthread_cond_t *cond, const void *unused) { cond->waiters = 0; @@ -194,3 +196,41 @@ int pthread_cond_broadcast(pthread_cond_t *cond) } return 0; } + +#else // GIT_WIN_XP_SUPPORT + +WINBASEAPI VOID WINAPI InitializeConditionVariable (PCONDITION_VARIABLE ConditionVariable); +WINBASEAPI VOID WINAPI WakeConditionVariable (PCONDITION_VARIABLE ConditionVariable); +WINBASEAPI VOID WINAPI WakeAllConditionVariable (PCONDITION_VARIABLE ConditionVariable); +WINBASEAPI WINBOOL WINAPI SleepConditionVariableCS (PCONDITION_VARIABLE ConditionVariable, PCRITICAL_SECTION CriticalSection, DWORD dwMilliseconds); + +int pthread_cond_init(pthread_cond_t *cond, const void *unused) +{ + InitializeConditionVariable(cond); + return 0; +} + +int pthread_cond_destroy(pthread_cond_t *cond) +{ + return 0; +} + +int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex) +{ + SleepConditionVariableCS(cond, mutex, INFINITE); + return 0; +} + +int pthread_cond_signal(pthread_cond_t *cond) +{ + WakeConditionVariable(cond); + return 0; +} + +int pthread_cond_broadcast(pthread_cond_t *cond) +{ + WakeAllConditionVariable(cond); + return 0; +} + +#endif // GIT_WIN_XP_SUPPORT diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h index 1c164088fbb64d..10a9d45f07eadd 100644 --- a/compat/win32/pthread.h +++ b/compat/win32/pthread.h @@ -32,6 +32,7 @@ typedef int pthread_mutexattr_t; #define pthread_mutexattr_settype(a, t) 0 #define PTHREAD_MUTEX_RECURSIVE 0 +#ifdef GIT_WIN_XP_SUPPORT /* * Implement simple condition variable for Windows threads, based on ACE * implementation. @@ -47,6 +48,9 @@ typedef struct { HANDLE sema; HANDLE continue_broadcast; } pthread_cond_t; +#else +typedef CONDITION_VARIABLE pthread_cond_t; +#endif extern int pthread_cond_init(pthread_cond_t *cond, const void *unused); extern int pthread_cond_destroy(pthread_cond_t *cond); From 617fa0f34ff4a2ec37ce61f96e029571ad532977 Mon Sep 17 00:00:00 2001 From: Loo Rong Jie Date: Fri, 23 Jun 2017 22:33:50 +0800 Subject: [PATCH 2/3] Format to 80 cols Signed-off-by: Loo Rong Jie --- compat/win32/pthread.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/compat/win32/pthread.c b/compat/win32/pthread.c index 80243b67cb8dc1..27e6092781d854 100644 --- a/compat/win32/pthread.c +++ b/compat/win32/pthread.c @@ -199,10 +199,16 @@ int pthread_cond_broadcast(pthread_cond_t *cond) #else // GIT_WIN_XP_SUPPORT -WINBASEAPI VOID WINAPI InitializeConditionVariable (PCONDITION_VARIABLE ConditionVariable); -WINBASEAPI VOID WINAPI WakeConditionVariable (PCONDITION_VARIABLE ConditionVariable); -WINBASEAPI VOID WINAPI WakeAllConditionVariable (PCONDITION_VARIABLE ConditionVariable); -WINBASEAPI WINBOOL WINAPI SleepConditionVariableCS (PCONDITION_VARIABLE ConditionVariable, PCRITICAL_SECTION CriticalSection, DWORD dwMilliseconds); +WINBASEAPI VOID WINAPI +InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable); +WINBASEAPI VOID WINAPI +WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable); +WINBASEAPI VOID WINAPI +WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable); +WINBASEAPI WINBOOL WINAPI +SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable, + PCRITICAL_SECTION CriticalSection, + DWORD dwMilliseconds); int pthread_cond_init(pthread_cond_t *cond, const void *unused) { From e42606780a8425362d95e8aa354e44eb39aef58f Mon Sep 17 00:00:00 2001 From: Loo Rong Jie Date: Tue, 15 Aug 2017 12:02:02 +0800 Subject: [PATCH 3/3] Remove old code and macro-ize implementation Signed-off-by: Loo Rong Jie --- compat/win32/pthread.c | 184 ----------------------------------------- compat/win32/pthread.h | 43 ++++------ 2 files changed, 18 insertions(+), 209 deletions(-) diff --git a/compat/win32/pthread.c b/compat/win32/pthread.c index 27e6092781d854..2e7eead42cb008 100644 --- a/compat/win32/pthread.c +++ b/compat/win32/pthread.c @@ -56,187 +56,3 @@ pthread_t pthread_self(void) t.tid = GetCurrentThreadId(); return t; } - -#ifdef GIT_WIN_XP_SUPPORT - -int pthread_cond_init(pthread_cond_t *cond, const void *unused) -{ - cond->waiters = 0; - cond->was_broadcast = 0; - InitializeCriticalSection(&cond->waiters_lock); - - cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL); - if (!cond->sema) - die("CreateSemaphore() failed"); - - cond->continue_broadcast = CreateEvent(NULL, /* security */ - FALSE, /* auto-reset */ - FALSE, /* not signaled */ - NULL); /* name */ - if (!cond->continue_broadcast) - die("CreateEvent() failed"); - - return 0; -} - -int pthread_cond_destroy(pthread_cond_t *cond) -{ - CloseHandle(cond->sema); - CloseHandle(cond->continue_broadcast); - DeleteCriticalSection(&cond->waiters_lock); - return 0; -} - -int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex) -{ - int last_waiter; - - EnterCriticalSection(&cond->waiters_lock); - cond->waiters++; - LeaveCriticalSection(&cond->waiters_lock); - - /* - * Unlock external mutex and wait for signal. - * NOTE: we've held mutex locked long enough to increment - * waiters count above, so there's no problem with - * leaving mutex unlocked before we wait on semaphore. - */ - LeaveCriticalSection(mutex); - - /* let's wait - ignore return value */ - WaitForSingleObject(cond->sema, INFINITE); - - /* - * Decrease waiters count. If we are the last waiter, then we must - * notify the broadcasting thread that it can continue. - * But if we continued due to cond_signal, we do not have to do that - * because the signaling thread knows that only one waiter continued. - */ - EnterCriticalSection(&cond->waiters_lock); - cond->waiters--; - last_waiter = cond->was_broadcast && cond->waiters == 0; - LeaveCriticalSection(&cond->waiters_lock); - - if (last_waiter) { - /* - * cond_broadcast was issued while mutex was held. This means - * that all other waiters have continued, but are contending - * for the mutex at the end of this function because the - * broadcasting thread did not leave cond_broadcast, yet. - * (This is so that it can be sure that each waiter has - * consumed exactly one slice of the semaphor.) - * The last waiter must tell the broadcasting thread that it - * can go on. - */ - SetEvent(cond->continue_broadcast); - /* - * Now we go on to contend with all other waiters for - * the mutex. Auf in den Kampf! - */ - } - /* lock external mutex again */ - EnterCriticalSection(mutex); - - return 0; -} - -/* - * IMPORTANT: This implementation requires that pthread_cond_signal - * is called while the mutex is held that is used in the corresponding - * pthread_cond_wait calls! - */ -int pthread_cond_signal(pthread_cond_t *cond) -{ - int have_waiters; - - EnterCriticalSection(&cond->waiters_lock); - have_waiters = cond->waiters > 0; - LeaveCriticalSection(&cond->waiters_lock); - - /* - * Signal only when there are waiters - */ - if (have_waiters) - return ReleaseSemaphore(cond->sema, 1, NULL) ? - 0 : err_win_to_posix(GetLastError()); - else - return 0; -} - -/* - * DOUBLY IMPORTANT: This implementation requires that pthread_cond_broadcast - * is called while the mutex is held that is used in the corresponding - * pthread_cond_wait calls! - */ -int pthread_cond_broadcast(pthread_cond_t *cond) -{ - EnterCriticalSection(&cond->waiters_lock); - - if ((cond->was_broadcast = cond->waiters > 0)) { - /* wake up all waiters */ - ReleaseSemaphore(cond->sema, cond->waiters, NULL); - LeaveCriticalSection(&cond->waiters_lock); - /* - * At this point all waiters continue. Each one takes its - * slice of the semaphor. Now it's our turn to wait: Since - * the external mutex is held, no thread can leave cond_wait, - * yet. For this reason, we can be sure that no thread gets - * a chance to eat *more* than one slice. OTOH, it means - * that the last waiter must send us a wake-up. - */ - WaitForSingleObject(cond->continue_broadcast, INFINITE); - /* - * Since the external mutex is held, no thread can enter - * cond_wait, and, hence, it is safe to reset this flag - * without cond->waiters_lock held. - */ - cond->was_broadcast = 0; - } else { - LeaveCriticalSection(&cond->waiters_lock); - } - return 0; -} - -#else // GIT_WIN_XP_SUPPORT - -WINBASEAPI VOID WINAPI -InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable); -WINBASEAPI VOID WINAPI -WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable); -WINBASEAPI VOID WINAPI -WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable); -WINBASEAPI WINBOOL WINAPI -SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable, - PCRITICAL_SECTION CriticalSection, - DWORD dwMilliseconds); - -int pthread_cond_init(pthread_cond_t *cond, const void *unused) -{ - InitializeConditionVariable(cond); - return 0; -} - -int pthread_cond_destroy(pthread_cond_t *cond) -{ - return 0; -} - -int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex) -{ - SleepConditionVariableCS(cond, mutex, INFINITE); - return 0; -} - -int pthread_cond_signal(pthread_cond_t *cond) -{ - WakeConditionVariable(cond); - return 0; -} - -int pthread_cond_broadcast(pthread_cond_t *cond) -{ - WakeAllConditionVariable(cond); - return 0; -} - -#endif // GIT_WIN_XP_SUPPORT diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h index 10a9d45f07eadd..4d204312d3cea4 100644 --- a/compat/win32/pthread.h +++ b/compat/win32/pthread.h @@ -32,31 +32,24 @@ typedef int pthread_mutexattr_t; #define pthread_mutexattr_settype(a, t) 0 #define PTHREAD_MUTEX_RECURSIVE 0 -#ifdef GIT_WIN_XP_SUPPORT -/* - * Implement simple condition variable for Windows threads, based on ACE - * implementation. - * - * See original implementation: http://bit.ly/1vkDjo - * ACE homepage: http://www.cse.wustl.edu/~schmidt/ACE.html - * See also: http://www.cse.wustl.edu/~schmidt/win32-cv-1.html - */ -typedef struct { - LONG waiters; - int was_broadcast; - CRITICAL_SECTION waiters_lock; - HANDLE sema; - HANDLE continue_broadcast; -} pthread_cond_t; -#else -typedef CONDITION_VARIABLE pthread_cond_t; -#endif - -extern int pthread_cond_init(pthread_cond_t *cond, const void *unused); -extern int pthread_cond_destroy(pthread_cond_t *cond); -extern int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex); -extern int pthread_cond_signal(pthread_cond_t *cond); -extern int pthread_cond_broadcast(pthread_cond_t *cond); +#define pthread_cond_t CONDITION_VARIABLE + +WINBASEAPI VOID WINAPI +InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable); +WINBASEAPI VOID WINAPI +WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable); +WINBASEAPI VOID WINAPI +WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable); +WINBASEAPI WINBOOL WINAPI +SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable, + PCRITICAL_SECTION CriticalSection, + DWORD dwMilliseconds); + +#define pthread_cond_init(a,b) InitializeConditionVariable((a)) +#define pthread_cond_destroy(a) do {} while (0) +#define pthread_cond_wait(a,b) return_0(SleepConditionVariableCS((a), (b), INFINITE)) +#define pthread_cond_signal WakeConditionVariable +#define pthread_cond_broadcast WakeAllConditionVariable /* * Simple thread creation implementation using pthread API