From 430953417f74dfcdbe030bafc069e1c07edceeb6 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 26 Aug 2013 14:56:31 -0700 Subject: [PATCH] Load SRWLock APIs at runtime This loads SRWLock APIs at runtime and in their absence (i.e. on Windows before Vista) falls back on a regular CRITICAL_SECTION that will not permit concurrent readers. --- CMakeLists.txt | 7 +--- src/global.c | 12 ++++-- src/hash/hash_win32.c | 3 +- src/thread-utils.h | 4 -- src/win32/pthread.c | 89 ++++++++++++++++++++++++++++++++++++++----- src/win32/pthread.h | 14 ++++++- 6 files changed, 103 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 019777e78..1c70ec2d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -287,13 +287,8 @@ FILE(GLOB SRC_H include/git2.h include/git2/*.h include/git2/sys/*.h) # On Windows use specific platform sources IF (WIN32 AND NOT CYGWIN) - ADD_DEFINITIONS(-DWIN32) + ADD_DEFINITIONS(-DWIN32 -D_WIN32_WINNT=0x0501) FILE(GLOB SRC_OS src/win32/*.c src/win32/*.h) - IF (THREADSAFE) - ADD_DEFINITIONS(-D_WIN32_WINNT=0x0600) - ELSE() - ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) - ENDIF() ELSEIF (AMIGA) ADD_DEFINITIONS(-DNO_ADDRINFO -DNO_READDIR_R) FILE(GLOB SRC_OS src/amiga/*.c src/amiga/*.h) diff --git a/src/global.c b/src/global.c index a06d0c81f..b504e5e0a 100644 --- a/src/global.c +++ b/src/global.c @@ -71,18 +71,22 @@ int git_threads_init(void) GIT_MEMORY_BARRIER; + win32_pthread_initialize(); + return error; } void git_threads_shutdown(void) { + /* Shut down any subsystems that have global state */ + win32_pthread_shutdown(); + git_futils_dirs_free(); + git_hash_global_shutdown(); + TlsFree(_tls_index); _tls_init = 0; - git_mutex_free(&git__mwindow_mutex); - /* Shut down any subsystems that have global state */ - git_hash_global_shutdown(); - git_futils_dirs_free(); + git_mutex_free(&git__mwindow_mutex); } git_global_st *git__global_state(void) diff --git a/src/hash/hash_win32.c b/src/hash/hash_win32.c index 43d54ca6d..6732f93d7 100644 --- a/src/hash/hash_win32.c +++ b/src/hash/hash_win32.c @@ -46,7 +46,8 @@ GIT_INLINE(int) hash_cng_prov_init(void) return -1; /* Load bcrypt.dll explicitly from the system directory */ - if ((dll_path_len = GetSystemDirectory(dll_path, MAX_PATH)) == 0 || dll_path_len > MAX_PATH || + if ((dll_path_len = GetSystemDirectory(dll_path, MAX_PATH)) == 0 || + dll_path_len > MAX_PATH || StringCchCat(dll_path, MAX_PATH, "\\") < 0 || StringCchCat(dll_path, MAX_PATH, GIT_HASH_CNG_DLL_NAME) < 0 || (hash_prov.prov.cng.dll = LoadLibrary(dll_path)) == NULL) diff --git a/src/thread-utils.h b/src/thread-utils.h index 371dc0b26..914c1357d 100644 --- a/src/thread-utils.h +++ b/src/thread-utils.h @@ -40,10 +40,6 @@ typedef git_atomic git_atomic_ssize; #ifdef GIT_THREADS -#if defined(GIT_WIN32) && _WIN32_WINNT < 0x0600 -# error "Unsupported Windows version for thread support" -#endif - #define git_thread pthread_t #define git_thread_create(thread, attr, start_routine, arg) \ pthread_create(thread, attr, start_routine, arg) diff --git a/src/win32/pthread.c b/src/win32/pthread.c index 41cb7a4c0..8775f632a 100644 --- a/src/win32/pthread.c +++ b/src/win32/pthread.c @@ -127,9 +127,10 @@ int pthread_cond_signal(pthread_cond_t *cond) return 0; } -/* pthread_cond_broadcast is not implemented because doing so with just Win32 events - * is quite complicated, and no caller in libgit2 uses it yet. */ - +/* pthread_cond_broadcast is not implemented because doing so with just + * Win32 events is quite complicated, and no caller in libgit2 uses it + * yet. + */ int pthread_num_processors_np(void) { DWORD_PTR p, s; @@ -142,41 +143,111 @@ int pthread_num_processors_np(void) return n ? n : 1; } + +static HINSTANCE win32_kernel32_dll; + +typedef void (WINAPI *win32_srwlock_fn)(SRWLOCK *); + +static win32_srwlock_fn win32_srwlock_initialize; +static win32_srwlock_fn win32_srwlock_acquire_shared; +static win32_srwlock_fn win32_srwlock_release_shared; +static win32_srwlock_fn win32_srwlock_acquire_exclusive; +static win32_srwlock_fn win32_srwlock_release_exclusive; + int pthread_rwlock_init( pthread_rwlock_t *GIT_RESTRICT lock, const pthread_rwlockattr_t *GIT_RESTRICT attr) { (void)attr; - InitializeSRWLock(lock); + + if (win32_srwlock_initialize) + win32_srwlock_initialize(&lock->native.srwl); + else + InitializeCriticalSection(&lock->native.csec); + return 0; } int pthread_rwlock_rdlock(pthread_rwlock_t *lock) { - AcquireSRWLockShared(lock); + if (win32_srwlock_acquire_shared) + win32_srwlock_acquire_shared(&lock->native.srwl); + else + EnterCriticalSection(&lock->native.csec); + return 0; } int pthread_rwlock_rdunlock(pthread_rwlock_t *lock) { - ReleaseSRWLockShared(lock); + if (win32_srwlock_release_shared) + win32_srwlock_release_shared(&lock->native.srwl); + else + LeaveCriticalSection(&lock->native.csec); + return 0; } int pthread_rwlock_wrlock(pthread_rwlock_t *lock) { - AcquireSRWLockExclusive(lock); + if (win32_srwlock_acquire_exclusive) + win32_srwlock_acquire_exclusive(&lock->native.srwl); + else + EnterCriticalSection(&lock->native.csec); + return 0; } int pthread_rwlock_wrunlock(pthread_rwlock_t *lock) { - ReleaseSRWLockExclusive(lock); + if (win32_srwlock_release_exclusive) + win32_srwlock_release_exclusive(&lock->native.srwl); + else + LeaveCriticalSection(&lock->native.csec); + return 0; } int pthread_rwlock_destroy(pthread_rwlock_t *lock) { - (void)lock; + if (!win32_srwlock_initialize) + DeleteCriticalSection(&lock->native.csec); + git__memzero(lock, sizeof(*lock)); + return 0; +} + + +int win32_pthread_initialize(void) +{ + if (win32_kernel32_dll) + return 0; + + win32_kernel32_dll = LoadLibrary("Kernel32.dll"); + if (!win32_kernel32_dll) { + giterr_set(GITERR_OS, "Could not load Kernel32.dll!"); + return -1; + } + + win32_srwlock_initialize = (win32_srwlock_fn) + GetProcAddress(win32_kernel32_dll, "InitializeSRWLock"); + win32_srwlock_acquire_shared = (win32_srwlock_fn) + GetProcAddress(win32_kernel32_dll, "AcquireSRWLockShared"); + win32_srwlock_release_shared = (win32_srwlock_fn) + GetProcAddress(win32_kernel32_dll, "ReleaseSRWLockShared"); + win32_srwlock_acquire_exclusive = (win32_srwlock_fn) + GetProcAddress(win32_kernel32_dll, "AcquireSRWLockExclusive"); + win32_srwlock_release_exclusive = (win32_srwlock_fn) + GetProcAddress(win32_kernel32_dll, "ReleaseSRWLockExclusive"); + + return 0; +} + +int win32_pthread_shutdown(void) +{ + if (win32_kernel32_dll) { + FreeLibrary(win32_kernel32_dll); + win32_kernel32_dll = NULL; + } + return 0; } diff --git a/src/win32/pthread.h b/src/win32/pthread.h index 50d836247..e84de471f 100644 --- a/src/win32/pthread.h +++ b/src/win32/pthread.h @@ -24,10 +24,17 @@ typedef int pthread_rwlockattr_t; typedef CRITICAL_SECTION pthread_mutex_t; typedef HANDLE pthread_t; typedef HANDLE pthread_cond_t; -typedef SRWLOCK pthread_rwlock_t; + +/* typedef struct { void *Ptr; } SRWLOCK; */ + +typedef struct { + union { + SRWLOCK srwl; + CRITICAL_SECTION csec; + } native; +} pthread_rwlock_t; #define PTHREAD_MUTEX_INITIALIZER {(void*)-1} -#define PTHREAD_RWLOCK_INITIALIZER SRWLOCK_INIT int pthread_create( pthread_t *GIT_RESTRICT thread, @@ -61,4 +68,7 @@ int pthread_rwlock_wrlock(pthread_rwlock_t *); int pthread_rwlock_wrunlock(pthread_rwlock_t *); int pthread_rwlock_destroy(pthread_rwlock_t *); +extern int win32_pthread_initialize(void); +extern int win32_pthread_shutdown(void); + #endif