{"thread":{"id":"49824","subject":"[PATCH 0/1] win32: modernize pthread_cond_*() shims","startedAt":"2018-11-13T18:52:37Z","lastAt":"2018-11-13T18:52:39Z","messageCount":2,"participants":["Johannes Schindelin via GitGitGadget","Loo Rong Jie via GitGitGadget"],"isPatch":true,"patchVersion":1,"patchTotal":1},"messages":[{"id":"363192","messageId":"pull.80.git.gitgitgadget@gmail.com","threadId":"49824","inReplyTo":null,"subject":"[PATCH 0/1] win32: modernize pthread_cond_*() shims","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-11-13T18:52:34Z","receivedAt":"2018-11-13T18:52:37Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"And yet another patch from Git for Windows' cache of treasures.\n\nIt was challenging to emulate the functions related to pthread_cond_t as\nlong as we tried to maintain support for Windows XP, which has nothing close\nto that feature. Now that we require Windows Vista or later, we can make use\nof the very nice functions associated with the CONDITION_VARIABLE data type.\n\nLook at how much code this deletes, and how little it introduces. This is a\nmaintainer's dream.\n\nLoo Rong Jie (1):\n  win32: replace pthread_cond_*() with much simpler code\n\n compat/win32/pthread.c | 138 -----------------------------------------\n compat/win32/pthread.h |  28 +++------\n 2 files changed, 7 insertions(+), 159 deletions(-)\n\n\nbase-commit: 8858448bb49332d353febc078ce4a3abcc962efe\nPublished-As: https://github.com/gitgitgadget/git/releases/tags/pr-80%2Fdscho%2Fmingw-modernize-pthread_cond_t-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-80/dscho/mingw-modernize-pthread_cond_t-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/80\n-- \ngitgitgadget\n"},{"id":"363193","messageId":"315638630d27761ebdb7e7092ac347b17b9b30d4.1542135152.git.gitgitgadget@gmail.com","threadId":"49824","inReplyTo":"pull.80.git.gitgitgadget@gmail.com","subject":"[PATCH 1/1] win32: replace pthread_cond_*() with much simpler code","fromName":"Loo Rong Jie via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-11-13T18:52:35Z","receivedAt":"2018-11-13T18:52:39Z","isPatch":true,"sender":{"key":"name:Loo Rong Jie","avatar":null},"body":"From: Loo Rong Jie <loorongjie@gmail.com>\n\nThe Win32 CONDITION_VARIABLE has better performance and is easier to\nmaintain, as the code is a lot shorter now (the semantics of the\nCONDITION_VARIABLE matches the pthread_cond_t very well).\n\nNote: CONDITION_VARIABLE is not available in Windows XP and below,\nbut the declared minimal Windows version required to build and run\nGit for Windows is Windows Vista (which is also beyond its\nend-of-life, but for less long than Windows XP), so that's okay.\n\nSigned-off-by: Loo Rong Jie <loorongjie@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n compat/win32/pthread.c | 138 -----------------------------------------\n compat/win32/pthread.h |  28 +++------\n 2 files changed, 7 insertions(+), 159 deletions(-)\n\ndiff --git a/compat/win32/pthread.c b/compat/win32/pthread.c\nindex e18f5c6e2e..2e7eead42c 100644\n--- a/compat/win32/pthread.c\n+++ b/compat/win32/pthread.c\n@@ -56,141 +56,3 @@ pthread_t pthread_self(void)\n \tt.tid = GetCurrentThreadId();\n \treturn t;\n }\n-\n-int pthread_cond_init(pthread_cond_t *cond, const void *unused)\n-{\n-\tcond->waiters = 0;\n-\tcond->was_broadcast = 0;\n-\tInitializeCriticalSection(&cond->waiters_lock);\n-\n-\tcond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);\n-\tif (!cond->sema)\n-\t\tdie(\"CreateSemaphore() failed\");\n-\n-\tcond->continue_broadcast = CreateEvent(NULL,\t/* security */\n-\t\t\t\tFALSE,\t\t\t/* auto-reset */\n-\t\t\t\tFALSE,\t\t\t/* not signaled */\n-\t\t\t\tNULL);\t\t\t/* name */\n-\tif (!cond->continue_broadcast)\n-\t\tdie(\"CreateEvent() failed\");\n-\n-\treturn 0;\n-}\n-\n-int pthread_cond_destroy(pthread_cond_t *cond)\n-{\n-\tCloseHandle(cond->sema);\n-\tCloseHandle(cond->continue_broadcast);\n-\tDeleteCriticalSection(&cond->waiters_lock);\n-\treturn 0;\n-}\n-\n-int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex)\n-{\n-\tint last_waiter;\n-\n-\tEnterCriticalSection(&cond->waiters_lock);\n-\tcond->waiters++;\n-\tLeaveCriticalSection(&cond->waiters_lock);\n-\n-\t/*\n-\t * Unlock external mutex and wait for signal.\n-\t * NOTE: we've held mutex locked long enough to increment\n-\t * waiters count above, so there's no problem with\n-\t * leaving mutex unlocked before we wait on semaphore.\n-\t */\n-\tLeaveCriticalSection(mutex);\n-\n-\t/* let's wait - ignore return value */\n-\tWaitForSingleObject(cond->sema, INFINITE);\n-\n-\t/*\n-\t * Decrease waiters count. If we are the last waiter, then we must\n-\t * notify the broadcasting thread that it can continue.\n-\t * But if we continued due to cond_signal, we do not have to do that\n-\t * because the signaling thread knows that only one waiter continued.\n-\t */\n-\tEnterCriticalSection(&cond->waiters_lock);\n-\tcond->waiters--;\n-\tlast_waiter = cond->was_broadcast && cond->waiters == 0;\n-\tLeaveCriticalSection(&cond->waiters_lock);\n-\n-\tif (last_waiter) {\n-\t\t/*\n-\t\t * cond_broadcast was issued while mutex was held. This means\n-\t\t * that all other waiters have continued, but are contending\n-\t\t * for the mutex at the end of this function because the\n-\t\t * broadcasting thread did not leave cond_broadcast, yet.\n-\t\t * (This is so that it can be sure that each waiter has\n-\t\t * consumed exactly one slice of the semaphor.)\n-\t\t * The last waiter must tell the broadcasting thread that it\n-\t\t * can go on.\n-\t\t */\n-\t\tSetEvent(cond->continue_broadcast);\n-\t\t/*\n-\t\t * Now we go on to contend with all other waiters for\n-\t\t * the mutex. Auf in den Kampf!\n-\t\t */\n-\t}\n-\t/* lock external mutex again */\n-\tEnterCriticalSection(mutex);\n-\n-\treturn 0;\n-}\n-\n-/*\n- * IMPORTANT: This implementation requires that pthread_cond_signal\n- * is called while the mutex is held that is used in the corresponding\n- * pthread_cond_wait calls!\n- */\n-int pthread_cond_signal(pthread_cond_t *cond)\n-{\n-\tint have_waiters;\n-\n-\tEnterCriticalSection(&cond->waiters_lock);\n-\thave_waiters = cond->waiters > 0;\n-\tLeaveCriticalSection(&cond->waiters_lock);\n-\n-\t/*\n-\t * Signal only when there are waiters\n-\t */\n-\tif (have_waiters)\n-\t\treturn ReleaseSemaphore(cond->sema, 1, NULL) ?\n-\t\t\t0 : err_win_to_posix(GetLastError());\n-\telse\n-\t\treturn 0;\n-}\n-\n-/*\n- * DOUBLY IMPORTANT: This implementation requires that pthread_cond_broadcast\n- * is called while the mutex is held that is used in the corresponding\n- * pthread_cond_wait calls!\n- */\n-int pthread_cond_broadcast(pthread_cond_t *cond)\n-{\n-\tEnterCriticalSection(&cond->waiters_lock);\n-\n-\tif ((cond->was_broadcast = cond->waiters > 0)) {\n-\t\t/* wake up all waiters */\n-\t\tReleaseSemaphore(cond->sema, cond->waiters, NULL);\n-\t\tLeaveCriticalSection(&cond->waiters_lock);\n-\t\t/*\n-\t\t * At this point all waiters continue. Each one takes its\n-\t\t * slice of the semaphor. Now it's our turn to wait: Since\n-\t\t * the external mutex is held, no thread can leave cond_wait,\n-\t\t * yet. For this reason, we can be sure that no thread gets\n-\t\t * a chance to eat *more* than one slice. OTOH, it means\n-\t\t * that the last waiter must send us a wake-up.\n-\t\t */\n-\t\tWaitForSingleObject(cond->continue_broadcast, INFINITE);\n-\t\t/*\n-\t\t * Since the external mutex is held, no thread can enter\n-\t\t * cond_wait, and, hence, it is safe to reset this flag\n-\t\t * without cond->waiters_lock held.\n-\t\t */\n-\t\tcond->was_broadcast = 0;\n-\t} else {\n-\t\tLeaveCriticalSection(&cond->waiters_lock);\n-\t}\n-\treturn 0;\n-}\ndiff --git a/compat/win32/pthread.h b/compat/win32/pthread.h\nindex 1c164088fb..c6cb8dd219 100644\n--- a/compat/win32/pthread.h\n+++ b/compat/win32/pthread.h\n@@ -32,27 +32,13 @@ typedef int pthread_mutexattr_t;\n #define pthread_mutexattr_settype(a, t) 0\n #define PTHREAD_MUTEX_RECURSIVE 0\n \n-/*\n- * Implement simple condition variable for Windows threads, based on ACE\n- * implementation.\n- *\n- * See original implementation: http://bit.ly/1vkDjo\n- * ACE homepage: http://www.cse.wustl.edu/~schmidt/ACE.html\n- * See also: http://www.cse.wustl.edu/~schmidt/win32-cv-1.html\n- */\n-typedef struct {\n-\tLONG waiters;\n-\tint was_broadcast;\n-\tCRITICAL_SECTION waiters_lock;\n-\tHANDLE sema;\n-\tHANDLE continue_broadcast;\n-} pthread_cond_t;\n-\n-extern int pthread_cond_init(pthread_cond_t *cond, const void *unused);\n-extern int pthread_cond_destroy(pthread_cond_t *cond);\n-extern int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex);\n-extern int pthread_cond_signal(pthread_cond_t *cond);\n-extern int pthread_cond_broadcast(pthread_cond_t *cond);\n+#define pthread_cond_t CONDITION_VARIABLE\n+\n+#define pthread_cond_init(a,b) InitializeConditionVariable((a))\n+#define pthread_cond_destroy(a) do {} while (0)\n+#define pthread_cond_wait(a,b) return_0(SleepConditionVariableCS((a), (b), INFINITE))\n+#define pthread_cond_signal WakeConditionVariable\n+#define pthread_cond_broadcast WakeAllConditionVariable\n \n /*\n  * Simple thread creation implementation using pthread API\n-- \ngitgitgadget\n"}]}