diff --git a/src/common.h b/src/common.h index 9abd605cb..51fb9186e 100644 --- a/src/common.h +++ b/src/common.h @@ -45,7 +45,7 @@ # include "win32/error.h" # include "win32/version.h" # ifdef GIT_THREADS -# include "win32/pthread.h" +# include "win32/thread.h" # endif # if defined(GIT_MSVC_CRTDBG) # include "win32/w32_stack.h" diff --git a/src/global.c b/src/global.c index 32e497507..eee0aea57 100644 --- a/src/global.c +++ b/src/global.c @@ -134,7 +134,7 @@ static int synchronized_threads_init(void) _tls_index = TlsAlloc(); - win32_pthread_initialize(); + git_threads_init(); if (git_mutex_init(&git__mwindow_mutex)) return -1; diff --git a/src/pack-objects.c b/src/pack-objects.c index 11e13f7d4..29231e028 100644 --- a/src/pack-objects.c +++ b/src/pack-objects.c @@ -1186,7 +1186,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list, git_mutex_init(&p[i].mutex); git_cond_init(&p[i].cond); - ret = git_thread_create(&p[i].thread, NULL, + ret = git_thread_create(&p[i].thread, threaded_find_deltas, &p[i]); if (ret) { giterr_set(GITERR_THREAD, "unable to create thread"); diff --git a/src/thread-utils.h b/src/thread-utils.h index 14c8a41ff..f0161989f 100644 --- a/src/thread-utils.h +++ b/src/thread-utils.h @@ -40,58 +40,12 @@ typedef git_atomic git_atomic_ssize; #ifdef GIT_THREADS -#if !defined(GIT_WIN32) - -typedef struct { - pthread_t thread; -} git_thread; - -#define git_thread_create(git_thread_ptr, attr, start_routine, arg) \ - pthread_create(&(git_thread_ptr)->thread, attr, start_routine, arg) -#define git_thread_join(git_thread_ptr, status) \ - pthread_join((git_thread_ptr)->thread, status) - +#ifdef GIT_WIN32 +# include "win32/thread.h" +#else +# include "unix/pthread.h" #endif -/* Pthreads Mutex */ -#define git_mutex pthread_mutex_t -#define git_mutex_init(a) pthread_mutex_init(a, NULL) -#define git_mutex_lock(a) pthread_mutex_lock(a) -#define git_mutex_unlock(a) pthread_mutex_unlock(a) -#define git_mutex_free(a) pthread_mutex_destroy(a) - -/* Pthreads condition vars */ -#define git_cond pthread_cond_t -#define git_cond_init(c) pthread_cond_init(c, NULL) -#define git_cond_free(c) pthread_cond_destroy(c) -#define git_cond_wait(c, l) pthread_cond_wait(c, l) -#define git_cond_signal(c) pthread_cond_signal(c) -#define git_cond_broadcast(c) pthread_cond_broadcast(c) - -/* Pthread (-ish) rwlock - * - * This differs from normal pthreads rwlocks in two ways: - * 1. Separate APIs for releasing read locks and write locks (as - * opposed to the pure POSIX API which only has one unlock fn) - * 2. You should not use recursive read locks (i.e. grabbing a read - * lock in a thread that already holds a read lock) because the - * Windows implementation doesn't support it - */ -#define git_rwlock pthread_rwlock_t -#define git_rwlock_init(a) pthread_rwlock_init(a, NULL) -#define git_rwlock_rdlock(a) pthread_rwlock_rdlock(a) -#define git_rwlock_rdunlock(a) pthread_rwlock_rdunlock(a) -#define git_rwlock_wrlock(a) pthread_rwlock_wrlock(a) -#define git_rwlock_wrunlock(a) pthread_rwlock_wrunlock(a) -#define git_rwlock_free(a) pthread_rwlock_destroy(a) -#define GIT_RWLOCK_STATIC_INIT PTHREAD_RWLOCK_INITIALIZER - -#ifndef GIT_WIN32 -#define pthread_rwlock_rdunlock pthread_rwlock_unlock -#define pthread_rwlock_wrunlock pthread_rwlock_unlock -#endif - - GIT_INLINE(void) git_atomic_set(git_atomic *a, int val) { #if defined(GIT_WIN32) @@ -178,7 +132,7 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) #else #define git_thread unsigned int -#define git_thread_create(thread, attr, start_routine, arg) 0 +#define git_thread_create(thread, start_routine, arg) 0 #define git_thread_join(id, status) (void)0 /* Pthreads Mutex */ diff --git a/src/unix/pthread.h b/src/unix/pthread.h new file mode 100644 index 000000000..0f3f17927 --- /dev/null +++ b/src/unix/pthread.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_unix_pthread_h__ +#define INCLUDE_unix_pthread_h__ + +typedef struct { + pthread_t thread; +} git_thread; + +#define git_threads_init() (void)0 +#define git_thread_create(git_thread_ptr, start_routine, arg) \ + pthread_create(&(git_thread_ptr)->thread, NULL, start_routine, arg) +#define git_thread_join(git_thread_ptr, status) \ + pthread_join((git_thread_ptr)->thread, status) + +/* Git Mutex */ +#define git_mutex pthread_mutex_t +#define git_mutex_init(a) pthread_mutex_init(a, NULL) +#define git_mutex_lock(a) pthread_mutex_lock(a) +#define git_mutex_unlock(a) pthread_mutex_unlock(a) +#define git_mutex_free(a) pthread_mutex_destroy(a) + +/* Git condition vars */ +#define git_cond pthread_cond_t +#define git_cond_init(c) pthread_cond_init(c, NULL) +#define git_cond_free(c) pthread_cond_destroy(c) +#define git_cond_wait(c, l) pthread_cond_wait(c, l) +#define git_cond_signal(c) pthread_cond_signal(c) +#define git_cond_broadcast(c) pthread_cond_broadcast(c) + +/* Pthread (-ish) rwlock + * + * This differs from normal pthreads rwlocks in two ways: + * 1. Separate APIs for releasing read locks and write locks (as + * opposed to the pure POSIX API which only has one unlock fn) + * 2. You should not use recursive read locks (i.e. grabbing a read + * lock in a thread that already holds a read lock) because the + * Windows implementation doesn't support it + */ +#define git_rwlock pthread_rwlock_t +#define git_rwlock_init(a) pthread_rwlock_init(a, NULL) +#define git_rwlock_rdlock(a) pthread_rwlock_rdlock(a) +#define git_rwlock_rdunlock(a) pthread_rwlock_unlock(a) +#define git_rwlock_wrlock(a) pthread_rwlock_wrlock(a) +#define git_rwlock_wrunlock(a) pthread_rwlock_unlock(a) +#define git_rwlock_free(a) pthread_rwlock_destroy(a) +#define GIT_RWLOCK_STATIC_INIT PTHREAD_RWLOCK_INITIALIZER + +#endif /* INCLUDE_unix_pthread_h__ */ diff --git a/src/win32/precompiled.h b/src/win32/precompiled.h index 33ce106d3..10ca0b80c 100644 --- a/src/win32/precompiled.h +++ b/src/win32/precompiled.h @@ -16,7 +16,7 @@ #include #include #ifdef GIT_THREADS - #include "win32/pthread.h" + #include "win32/thread.h" #endif #include "git2.h" diff --git a/src/win32/pthread.h b/src/win32/pthread.h deleted file mode 100644 index e4826ca7f..000000000 --- a/src/win32/pthread.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#ifndef GIT_PTHREAD_H -#define GIT_PTHREAD_H - -#include "../common.h" - -#if defined (_MSC_VER) -# define GIT_RESTRICT __restrict -#else -# define GIT_RESTRICT __restrict__ -#endif - -typedef struct { - HANDLE thread; - void *(*proc)(void *); - void *param; - void *result; -} git_win32_thread; - -typedef int pthread_mutexattr_t; -typedef int pthread_condattr_t; -typedef int pthread_attr_t; -typedef int pthread_rwlockattr_t; - -typedef CRITICAL_SECTION pthread_mutex_t; -typedef HANDLE pthread_cond_t; - -typedef struct { void *Ptr; } GIT_SRWLOCK; - -typedef struct { - union { - GIT_SRWLOCK srwl; - CRITICAL_SECTION csec; - } native; -} pthread_rwlock_t; - -#define PTHREAD_MUTEX_INITIALIZER {(void*)-1} - -int git_win32__thread_create( - git_win32_thread *GIT_RESTRICT, - const pthread_attr_t *GIT_RESTRICT, - void *(*) (void *), - void *GIT_RESTRICT); - -int git_win32__thread_join( - git_win32_thread *, - void **); - -#ifdef GIT_THREADS - -typedef git_win32_thread git_thread; - -#define git_thread_create(git_thread_ptr, attr, start_routine, arg) \ - git_win32__thread_create(git_thread_ptr, attr, start_routine, arg) -#define git_thread_join(git_thread_ptr, status) \ - git_win32__thread_join(git_thread_ptr, status) - -#endif - -int pthread_mutex_init( - pthread_mutex_t *GIT_RESTRICT mutex, - const pthread_mutexattr_t *GIT_RESTRICT mutexattr); -int pthread_mutex_destroy(pthread_mutex_t *); -int pthread_mutex_lock(pthread_mutex_t *); -int pthread_mutex_unlock(pthread_mutex_t *); - -int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *); -int pthread_cond_destroy(pthread_cond_t *); -int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *); -int pthread_cond_signal(pthread_cond_t *); -/* pthread_cond_broadcast is not supported on Win32 yet. */ - -int pthread_num_processors_np(void); - -int pthread_rwlock_init( - pthread_rwlock_t *GIT_RESTRICT lock, - const pthread_rwlockattr_t *GIT_RESTRICT attr); -int pthread_rwlock_rdlock(pthread_rwlock_t *); -int pthread_rwlock_rdunlock(pthread_rwlock_t *); -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); - -#endif diff --git a/src/win32/pthread.c b/src/win32/thread.c similarity index 72% rename from src/win32/pthread.c rename to src/win32/thread.c index a1cc18932..80d56ce5d 100644 --- a/src/win32/pthread.c +++ b/src/win32/thread.c @@ -5,18 +5,26 @@ * a Linking Exception. For full terms see the included COPYING file. */ -#include "pthread.h" +#include "thread.h" #include "../global.h" #define CLEAN_THREAD_EXIT 0x6F012842 +typedef void (WINAPI *win32_srwlock_fn)(GIT_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; + /* The thread procedure stub used to invoke the caller's procedure * and capture the return value for later collection. Windows will * only hold a DWORD, but we need to be able to store an entire * void pointer. This requires the indirection. */ static DWORD WINAPI git_win32__threadproc(LPVOID lpParameter) { - git_win32_thread *thread = lpParameter; + git_thread *thread = lpParameter; thread->result = thread->proc(thread->param); @@ -25,14 +33,31 @@ static DWORD WINAPI git_win32__threadproc(LPVOID lpParameter) return CLEAN_THREAD_EXIT; } -int git_win32__thread_create( - git_win32_thread *GIT_RESTRICT thread, - const pthread_attr_t *GIT_RESTRICT attr, +int git_threads_init(void) +{ + HMODULE hModule = GetModuleHandleW(L"kernel32"); + + if (hModule) { + win32_srwlock_initialize = (win32_srwlock_fn) + GetProcAddress(hModule, "InitializeSRWLock"); + win32_srwlock_acquire_shared = (win32_srwlock_fn) + GetProcAddress(hModule, "AcquireSRWLockShared"); + win32_srwlock_release_shared = (win32_srwlock_fn) + GetProcAddress(hModule, "ReleaseSRWLockShared"); + win32_srwlock_acquire_exclusive = (win32_srwlock_fn) + GetProcAddress(hModule, "AcquireSRWLockExclusive"); + win32_srwlock_release_exclusive = (win32_srwlock_fn) + GetProcAddress(hModule, "ReleaseSRWLockExclusive"); + } + + return 0; +} + +int git_thread_create( + git_thread *GIT_RESTRICT thread, void *(*start_routine)(void*), void *GIT_RESTRICT arg) { - GIT_UNUSED(attr); - thread->result = NULL; thread->param = arg; thread->proc = start_routine; @@ -42,8 +67,8 @@ int git_win32__thread_create( return thread->thread ? 0 : -1; } -int git_win32__thread_join( - git_win32_thread *thread, +int git_thread_join( + git_thread *thread, void **value_ptr) { DWORD exit; @@ -70,39 +95,32 @@ int git_win32__thread_join( return 0; } -int pthread_mutex_init( - pthread_mutex_t *GIT_RESTRICT mutex, - const pthread_mutexattr_t *GIT_RESTRICT mutexattr) +int git_mutex_init(git_mutex *GIT_RESTRICT mutex) { - GIT_UNUSED(mutexattr); InitializeCriticalSection(mutex); return 0; } -int pthread_mutex_destroy(pthread_mutex_t *mutex) +int git_mutex_free(git_mutex *mutex) { DeleteCriticalSection(mutex); return 0; } -int pthread_mutex_lock(pthread_mutex_t *mutex) +int git_mutex_lock(git_mutex *mutex) { EnterCriticalSection(mutex); return 0; } -int pthread_mutex_unlock(pthread_mutex_t *mutex) +int git_mutex_unlock(git_mutex *mutex) { LeaveCriticalSection(mutex); return 0; } -int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) +int git_cond_init(git_cond *cond) { - /* We don't support non-default attributes. */ - if (attr) - return EINVAL; - /* This is an auto-reset event. */ *cond = CreateEventW(NULL, FALSE, FALSE, NULL); assert(*cond); @@ -112,7 +130,7 @@ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) return *cond ? 0 : ENOMEM; } -int pthread_cond_destroy(pthread_cond_t *cond) +int git_cond_free(git_cond *cond) { BOOL closed; @@ -127,7 +145,7 @@ int pthread_cond_destroy(pthread_cond_t *cond) return 0; } -int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +int git_cond_wait(git_cond *cond, git_mutex *mutex) { int error; DWORD wait_result; @@ -136,7 +154,7 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) return EINVAL; /* The caller must be holding the mutex. */ - error = pthread_mutex_unlock(mutex); + error = git_mutex_unlock(mutex); if (error) return error; @@ -145,10 +163,10 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) assert(WAIT_OBJECT_0 == wait_result); GIT_UNUSED(wait_result); - return pthread_mutex_lock(mutex); + return git_mutex_lock(mutex); } -int pthread_cond_signal(pthread_cond_t *cond) +int git_cond_signal(git_cond *cond) { BOOL signaled; @@ -162,36 +180,8 @@ 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. - */ -int pthread_num_processors_np(void) +int git_rwlock_init(git_rwlock *GIT_RESTRICT lock) { - DWORD_PTR p, s; - int n = 0; - - if (GetProcessAffinityMask(GetCurrentProcess(), &p, &s)) - for (; p; p >>= 1) - n += p&1; - - return n ? n : 1; -} - -typedef void (WINAPI *win32_srwlock_fn)(GIT_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) -{ - GIT_UNUSED(attr); - if (win32_srwlock_initialize) win32_srwlock_initialize(&lock->native.srwl); else @@ -200,7 +190,7 @@ int pthread_rwlock_init( return 0; } -int pthread_rwlock_rdlock(pthread_rwlock_t *lock) +int git_rwlock_rdlock(git_rwlock *lock) { if (win32_srwlock_acquire_shared) win32_srwlock_acquire_shared(&lock->native.srwl); @@ -210,7 +200,7 @@ int pthread_rwlock_rdlock(pthread_rwlock_t *lock) return 0; } -int pthread_rwlock_rdunlock(pthread_rwlock_t *lock) +int git_rwlock_rdunlock(git_rwlock *lock) { if (win32_srwlock_release_shared) win32_srwlock_release_shared(&lock->native.srwl); @@ -220,7 +210,7 @@ int pthread_rwlock_rdunlock(pthread_rwlock_t *lock) return 0; } -int pthread_rwlock_wrlock(pthread_rwlock_t *lock) +int git_rwlock_wrlock(git_rwlock *lock) { if (win32_srwlock_acquire_exclusive) win32_srwlock_acquire_exclusive(&lock->native.srwl); @@ -230,7 +220,7 @@ int pthread_rwlock_wrlock(pthread_rwlock_t *lock) return 0; } -int pthread_rwlock_wrunlock(pthread_rwlock_t *lock) +int git_rwlock_wrunlock(git_rwlock *lock) { if (win32_srwlock_release_exclusive) win32_srwlock_release_exclusive(&lock->native.srwl); @@ -240,30 +230,10 @@ int pthread_rwlock_wrunlock(pthread_rwlock_t *lock) return 0; } -int pthread_rwlock_destroy(pthread_rwlock_t *lock) +int git_rwlock_free(git_rwlock *lock) { if (!win32_srwlock_initialize) DeleteCriticalSection(&lock->native.csec); git__memzero(lock, sizeof(*lock)); return 0; } - -int win32_pthread_initialize(void) -{ - HMODULE hModule = GetModuleHandleW(L"kernel32"); - - if (hModule) { - win32_srwlock_initialize = (win32_srwlock_fn) - GetProcAddress(hModule, "InitializeSRWLock"); - win32_srwlock_acquire_shared = (win32_srwlock_fn) - GetProcAddress(hModule, "AcquireSRWLockShared"); - win32_srwlock_release_shared = (win32_srwlock_fn) - GetProcAddress(hModule, "ReleaseSRWLockShared"); - win32_srwlock_acquire_exclusive = (win32_srwlock_fn) - GetProcAddress(hModule, "AcquireSRWLockExclusive"); - win32_srwlock_release_exclusive = (win32_srwlock_fn) - GetProcAddress(hModule, "ReleaseSRWLockExclusive"); - } - - return 0; -} diff --git a/src/win32/thread.h b/src/win32/thread.h new file mode 100644 index 000000000..0d01822a6 --- /dev/null +++ b/src/win32/thread.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_win32_thread_h__ +#define INCLUDE_win32_thread_h__ + +#include "../common.h" + +#if defined (_MSC_VER) +# define GIT_RESTRICT __restrict +#else +# define GIT_RESTRICT __restrict__ +#endif + +typedef struct { + HANDLE thread; + void *(*proc)(void *); + void *param; + void *result; +} git_thread; + +typedef CRITICAL_SECTION git_mutex; +typedef HANDLE git_cond; + +typedef struct { void *Ptr; } GIT_SRWLOCK; + +typedef struct { + union { + GIT_SRWLOCK srwl; + CRITICAL_SECTION csec; + } native; +} git_rwlock; + +int git_threads_init(void); + +int git_thread_create(git_thread *GIT_RESTRICT, + void *(*) (void *), + void *GIT_RESTRICT); +int git_thread_join(git_thread *, void **); + +int git_mutex_init(git_mutex *GIT_RESTRICT mutex); +int git_mutex_free(git_mutex *); +int git_mutex_lock(git_mutex *); +int git_mutex_unlock(git_mutex *); + +int git_cond_init(git_cond *); +int git_cond_free(git_cond *); +int git_cond_wait(git_cond *, git_mutex *); +int git_cond_signal(git_cond *); + +int git_rwlock_init(git_rwlock *GIT_RESTRICT lock); +int git_rwlock_rdlock(git_rwlock *); +int git_rwlock_rdunlock(git_rwlock *); +int git_rwlock_wrlock(git_rwlock *); +int git_rwlock_wrunlock(git_rwlock *); +int git_rwlock_free(git_rwlock *); + +#endif /* INCLUDE_win32_thread_h__ */ diff --git a/tests/object/cache.c b/tests/object/cache.c index bdf12da7a..680f23630 100644 --- a/tests/object/cache.c +++ b/tests/object/cache.c @@ -220,7 +220,7 @@ void test_object_cache__threadmania(void) fn = (th & 1) ? cache_parsed : cache_raw; #ifdef GIT_THREADS - cl_git_pass(git_thread_create(&t[th], NULL, fn, data)); + cl_git_pass(git_thread_create(&t[th], fn, data)); #else cl_assert(fn(data) == data); git__free(data); @@ -267,7 +267,7 @@ void test_object_cache__fast_thread_rush(void) data[th] = th; #ifdef GIT_THREADS cl_git_pass( - git_thread_create(&t[th], NULL, cache_quick, &data[th])); + git_thread_create(&t[th], cache_quick, &data[th])); #else cl_assert(cache_quick(&data[th]) == &data[th]); #endif diff --git a/tests/threads/refdb.c b/tests/threads/refdb.c index 6589e3922..f869bcb44 100644 --- a/tests/threads/refdb.c +++ b/tests/threads/refdb.c @@ -75,7 +75,7 @@ void test_threads_refdb__iterator(void) for (t = 0; t < THREADS; ++t) { id[t] = t; #ifdef GIT_THREADS - cl_git_pass(git_thread_create(&th[t], NULL, iterate_refs, &id[t])); + cl_git_pass(git_thread_create(&th[t], iterate_refs, &id[t])); #else th[t] = t; iterate_refs(&id[t]); @@ -196,7 +196,7 @@ void test_threads_refdb__edit_while_iterate(void) * for now by just running on a single thread... */ /* #ifdef GIT_THREADS */ -/* cl_git_pass(git_thread_create(&th[t], NULL, fn, &id[t])); */ +/* cl_git_pass(git_thread_create(&th[t], fn, &id[t])); */ /* #else */ fn(&id[t]); /* #endif */ @@ -211,7 +211,7 @@ void test_threads_refdb__edit_while_iterate(void) for (t = 0; t < THREADS; ++t) { id[t] = t; - cl_git_pass(git_thread_create(&th[t], NULL, iterate_refs, &id[t])); + cl_git_pass(git_thread_create(&th[t], iterate_refs, &id[t])); } for (t = 0; t < THREADS; ++t) { diff --git a/tests/threads/thread_helpers.c b/tests/threads/thread_helpers.c index 760a7bd33..54bf6097d 100644 --- a/tests/threads/thread_helpers.c +++ b/tests/threads/thread_helpers.c @@ -24,7 +24,7 @@ void run_in_parallel( for (t = 0; t < threads; ++t) { id[t] = t; #ifdef GIT_THREADS - cl_git_pass(git_thread_create(&th[t], NULL, func, &id[t])); + cl_git_pass(git_thread_create(&th[t], func, &id[t])); #else cl_assert(func(&id[t]) == &id[t]); #endif