summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2020-10-14 13:44:59 +0100
committerGitHub <noreply@github.com>2020-10-14 13:44:59 +0100
commit20450cbe7d161abbb3eb52d96867aeaa6dd99e12 (patch)
treee38c7f3203a88ed6d95c1326e882e594852b826d
parente9858645b26adb7aa2dc9034034bc5744b3cd690 (diff)
parent634c285a0eb016a2d144b35298dabc350d2e7576 (diff)
downloadlibgit2-20450cbe7d161abbb3eb52d96867aeaa6dd99e12.tar.gz
Merge pull request #5546 from libgit2/ethomson/init
Refactor "global" state
-rw-r--r--src/alloc.c22
-rw-r--r--src/allocators/win32_crtdbg.c1
-rw-r--r--src/errors.c26
-rw-r--r--src/filter.c4
-rw-r--r--src/futils.c3
-rw-r--r--src/global.c363
-rw-r--r--src/global.h41
-rw-r--r--src/hash/sha1/win32.c5
-rw-r--r--src/libgit2.c (renamed from src/settings.c)96
-rw-r--r--src/libgit2.h13
-rw-r--r--src/merge_driver.c4
-rw-r--r--src/mwindow.c18
-rw-r--r--src/mwindow.h2
-rw-r--r--src/net.c2
-rw-r--r--src/netops.c2
-rw-r--r--src/oid.c4
-rw-r--r--src/runtime.c147
-rw-r--r--src/runtime.h53
-rw-r--r--src/settings.h11
-rw-r--r--src/streams/mbedtls.c6
-rw-r--r--src/streams/openssl.c11
-rw-r--r--src/streams/registry.c5
-rw-r--r--src/streams/tls.c1
-rw-r--r--src/sysdir.c6
-rw-r--r--src/thread-utils.h2
-rw-r--r--src/threadstate.c155
-rw-r--r--src/threadstate.h24
-rw-r--r--src/trace.c2
-rw-r--r--src/transports/http.c1
-rw-r--r--src/transports/http.h1
-rw-r--r--src/transports/httpclient.c1
-rw-r--r--src/transports/ssh.c5
-rw-r--r--src/transports/winhttp.c1
-rw-r--r--src/unix/pthread.h3
-rw-r--r--src/win32/posix_w32.c1
-rw-r--r--src/win32/thread.c26
-rw-r--r--src/win32/thread.h2
-rw-r--r--tests/core/useragent.c2
-rw-r--r--tests/pack/filelimit.c1
-rw-r--r--tests/threads/basic.c8
40 files changed, 588 insertions, 493 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 51c4d8029..6972e7b59 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -6,10 +6,16 @@
*/
#include "alloc.h"
+#include "runtime.h"
#include "allocators/stdalloc.h"
#include "allocators/win32_crtdbg.h"
+#if defined(GIT_MSVC_CRTDBG)
+# include "win32/w32_stack.h"
+# include "win32/w32_crtdbg_stacktrace.h"
+#endif
+
git_allocator git__allocator;
static int setup_default_allocator(void)
@@ -21,8 +27,24 @@ static int setup_default_allocator(void)
#endif
}
+#if defined(GIT_MSVC_CRTDBG)
+static void allocator_global_shutdown(void)
+{
+ git_win32__crtdbg_stacktrace_cleanup();
+ git_win32__stack_cleanup();
+}
+#endif
+
int git_allocator_global_init(void)
{
+#if defined(GIT_MSVC_CRTDBG)
+ git_win32__crtdbg_stacktrace_init();
+ git_win32__stack_init();
+
+ if (git_runtime_shutdown_register(allocator_global_shutdown) < 0)
+ return -1;
+#endif
+
/*
* We don't want to overwrite any allocator which has been set before
* the init function is called.
diff --git a/src/allocators/win32_crtdbg.c b/src/allocators/win32_crtdbg.c
index 1187e2fcd..c726268a8 100644
--- a/src/allocators/win32_crtdbg.c
+++ b/src/allocators/win32_crtdbg.c
@@ -9,6 +9,7 @@
#if defined(GIT_MSVC_CRTDBG)
+#include "win32/w32_stack.h"
#include "win32/w32_crtdbg_stacktrace.h"
static void *crtdbg__malloc(size_t len, const char *file, int line)
diff --git a/src/errors.c b/src/errors.c
index 8570226b4..d4da50da8 100644
--- a/src/errors.c
+++ b/src/errors.c
@@ -7,7 +7,7 @@
#include "common.h"
-#include "global.h"
+#include "threadstate.h"
#include "posix.h"
#include "buffer.h"
@@ -22,18 +22,18 @@ static git_error g_git_oom_error = {
static void set_error_from_buffer(int error_class)
{
- git_error *error = &GIT_GLOBAL->error_t;
- git_buf *buf = &GIT_GLOBAL->error_buf;
+ git_error *error = &GIT_THREADSTATE->error_t;
+ git_buf *buf = &GIT_THREADSTATE->error_buf;
error->message = buf->ptr;
error->klass = error_class;
- GIT_GLOBAL->last_error = error;
+ GIT_THREADSTATE->last_error = error;
}
static void set_error(int error_class, char *string)
{
- git_buf *buf = &GIT_GLOBAL->error_buf;
+ git_buf *buf = &GIT_THREADSTATE->error_buf;
git_buf_clear(buf);
if (string) {
@@ -46,7 +46,7 @@ static void set_error(int error_class, char *string)
void git_error_set_oom(void)
{
- GIT_GLOBAL->last_error = &g_git_oom_error;
+ GIT_THREADSTATE->last_error = &g_git_oom_error;
}
void git_error_set(int error_class, const char *fmt, ...)
@@ -64,7 +64,7 @@ void git_error_vset(int error_class, const char *fmt, va_list ap)
DWORD win32_error_code = (error_class == GIT_ERROR_OS) ? GetLastError() : 0;
#endif
int error_code = (error_class == GIT_ERROR_OS) ? errno : 0;
- git_buf *buf = &GIT_GLOBAL->error_buf;
+ git_buf *buf = &GIT_THREADSTATE->error_buf;
git_buf_clear(buf);
if (fmt) {
@@ -97,7 +97,7 @@ void git_error_vset(int error_class, const char *fmt, va_list ap)
int git_error_set_str(int error_class, const char *string)
{
- git_buf *buf = &GIT_GLOBAL->error_buf;
+ git_buf *buf = &GIT_THREADSTATE->error_buf;
assert(string);
@@ -118,9 +118,9 @@ int git_error_set_str(int error_class, const char *string)
void git_error_clear(void)
{
- if (GIT_GLOBAL->last_error != NULL) {
+ if (GIT_THREADSTATE->last_error != NULL) {
set_error(0, NULL);
- GIT_GLOBAL->last_error = NULL;
+ GIT_THREADSTATE->last_error = NULL;
}
errno = 0;
@@ -131,13 +131,13 @@ void git_error_clear(void)
const git_error *git_error_last(void)
{
- return GIT_GLOBAL->last_error;
+ return GIT_THREADSTATE->last_error;
}
int git_error_state_capture(git_error_state *state, int error_code)
{
- git_error *error = GIT_GLOBAL->last_error;
- git_buf *error_buf = &GIT_GLOBAL->error_buf;
+ git_error *error = GIT_THREADSTATE->last_error;
+ git_buf *error_buf = &GIT_THREADSTATE->error_buf;
memset(state, 0, sizeof(git_error_state));
diff --git a/src/filter.c b/src/filter.c
index 09b57dc80..86db5a5e3 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -11,7 +11,7 @@
#include "futils.h"
#include "hash.h"
#include "repository.h"
-#include "global.h"
+#include "runtime.h"
#include "git2/sys/filter.h"
#include "git2/config.h"
#include "blob.h"
@@ -206,7 +206,7 @@ int git_filter_global_init(void)
GIT_FILTER_IDENT, ident, GIT_FILTER_IDENT_PRIORITY) < 0)
error = -1;
- git__on_shutdown(git_filter_global_shutdown);
+ error = git_runtime_shutdown_register(git_filter_global_shutdown);
done:
if (error) {
diff --git a/src/futils.c b/src/futils.c
index 8c0f008b3..2ad8a1b80 100644
--- a/src/futils.c
+++ b/src/futils.c
@@ -7,8 +7,9 @@
#include "futils.h"
-#include "global.h"
+#include "runtime.h"
#include "strmap.h"
+#include "hash.h"
#include <ctype.h>
#if GIT_WIN32
#include "win32/findfile.h"
diff --git a/src/global.c b/src/global.c
deleted file mode 100644
index 9fe8cd5d3..000000000
--- a/src/global.c
+++ /dev/null
@@ -1,363 +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.
- */
-
-#include "global.h"
-
-#include "alloc.h"
-#include "hash.h"
-#include "sysdir.h"
-#include "filter.h"
-#include "merge_driver.h"
-#include "pool.h"
-#include "streams/registry.h"
-#include "streams/mbedtls.h"
-#include "streams/openssl.h"
-#include "thread-utils.h"
-#include "git2/global.h"
-#include "transports/ssh.h"
-
-#if defined(GIT_MSVC_CRTDBG)
-#include "win32/w32_stack.h"
-#include "win32/w32_crtdbg_stacktrace.h"
-#endif
-
-git_mutex git__mwindow_mutex;
-
-typedef int (*git_global_init_fn)(void);
-
-static git_global_init_fn git__init_callbacks[] = {
- git_allocator_global_init,
- git_hash_global_init,
- git_sysdir_global_init,
- git_filter_global_init,
- git_merge_driver_global_init,
- git_transport_ssh_global_init,
- git_stream_registry_global_init,
- git_openssl_stream_global_init,
- git_mbedtls_stream_global_init,
- git_mwindow_global_init,
- git_pool_global_init
-};
-
-static git_global_shutdown_fn git__shutdown_callbacks[ARRAY_SIZE(git__init_callbacks)];
-
-static git_atomic git__n_shutdown_callbacks;
-static git_atomic git__n_inits;
-char *git__user_agent;
-char *git__ssl_ciphers;
-
-void git__on_shutdown(git_global_shutdown_fn callback)
-{
- int count = git_atomic_inc(&git__n_shutdown_callbacks);
- assert(count <= (int) ARRAY_SIZE(git__shutdown_callbacks) && count > 0);
- git__shutdown_callbacks[count - 1] = callback;
-}
-
-static void git__global_state_cleanup(git_global_st *st)
-{
- if (!st)
- return;
-
- git__free(st->error_t.message);
- st->error_t.message = NULL;
-}
-
-static int init_common(void)
-{
- size_t i;
- int ret;
-
- /* Initialize the CRT debug allocator first, before our first malloc */
-#if defined(GIT_MSVC_CRTDBG)
- git_win32__crtdbg_stacktrace_init();
- git_win32__stack_init();
-#endif
-
- /* Initialize subsystems that have global state */
- for (i = 0; i < ARRAY_SIZE(git__init_callbacks); i++)
- if ((ret = git__init_callbacks[i]()) != 0)
- break;
-
- GIT_MEMORY_BARRIER;
-
- return ret;
-}
-
-static void shutdown_common(void)
-{
- int pos;
-
- /* Shutdown subsystems that have registered */
- for (pos = git_atomic_get(&git__n_shutdown_callbacks);
- pos > 0;
- pos = git_atomic_dec(&git__n_shutdown_callbacks)) {
-
- git_global_shutdown_fn cb = git__swap(
- git__shutdown_callbacks[pos - 1], NULL);
-
- if (cb != NULL)
- cb();
- }
-
- git__free(git__user_agent);
- git__free(git__ssl_ciphers);
-}
-
-/**
- * Handle the global state with TLS
- *
- * If libgit2 is built with GIT_THREADS enabled,
- * the `git_libgit2_init()` function must be called
- * before calling any other function of the library.
- *
- * This function allocates a TLS index (using pthreads
- * or the native Win32 API) to store the global state
- * on a per-thread basis.
- *
- * Any internal method that requires global state will
- * then call `git__global_state()` which returns a pointer
- * to the global state structure; this pointer is lazily
- * allocated on each thread.
- *
- * Before shutting down the library, the
- * `git_libgit2_shutdown` method must be called to free
- * the previously reserved TLS index.
- *
- * If libgit2 is built without threading support, the
- * `git__global_statestate()` call returns a pointer to a single,
- * statically allocated global state. The `git_thread_`
- * functions are not available in that case.
- */
-
-/*
- * `git_libgit2_init()` allows subsystems to perform global setup,
- * which may take place in the global scope. An explicit memory
- * fence exists at the exit of `git_libgit2_init()`. Without this,
- * CPU cores are free to reorder cache invalidation of `_tls_init`
- * before cache invalidation of the subsystems' newly written global
- * state.
- */
-#if defined(GIT_THREADS) && defined(GIT_WIN32)
-
-static DWORD _fls_index;
-static volatile LONG _mutex = 0;
-
-static void WINAPI fls_free(void *st)
-{
- git__global_state_cleanup(st);
- git__free(st);
-}
-
-static int synchronized_threads_init(void)
-{
- int error;
-
- if ((_fls_index = FlsAlloc(fls_free)) == FLS_OUT_OF_INDEXES)
- return -1;
-
- git_threads_init();
-
- if (git_mutex_init(&git__mwindow_mutex))
- return -1;
-
- error = init_common();
-
- return error;
-}
-
-int git_libgit2_init(void)
-{
- int ret;
-
- /* Enter the lock */
- while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); }
-
- /* Only do work on a 0 -> 1 transition of the refcount */
- if ((ret = git_atomic_inc(&git__n_inits)) == 1) {
- if (synchronized_threads_init() < 0)
- ret = -1;
- }
-
- /* Exit the lock */
- InterlockedExchange(&_mutex, 0);
-
- return ret;
-}
-
-int git_libgit2_shutdown(void)
-{
- int ret;
-
- /* Enter the lock */
- while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); }
-
- /* Only do work on a 1 -> 0 transition of the refcount */
- if ((ret = git_atomic_dec(&git__n_inits)) == 0) {
- shutdown_common();
-
- FlsFree(_fls_index);
- git_mutex_free(&git__mwindow_mutex);
-
-#if defined(GIT_MSVC_CRTDBG)
- git_win32__crtdbg_stacktrace_cleanup();
- git_win32__stack_cleanup();
-#endif
- }
-
- /* Exit the lock */
- InterlockedExchange(&_mutex, 0);
-
- return ret;
-}
-
-git_global_st *git__global_state(void)
-{
- git_global_st *ptr;
-
- assert(git_atomic_get(&git__n_inits) > 0);
-
- if ((ptr = FlsGetValue(_fls_index)) != NULL)
- return ptr;
-
- ptr = git__calloc(1, sizeof(git_global_st));
- if (!ptr)
- return NULL;
-
- git_buf_init(&ptr->error_buf, 0);
-
- FlsSetValue(_fls_index, ptr);
- return ptr;
-}
-
-#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
-
-static pthread_key_t _tls_key;
-static pthread_mutex_t _init_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_once_t _once_init = PTHREAD_ONCE_INIT;
-int init_error = 0;
-
-static void cb__free_status(void *st)
-{
- git__global_state_cleanup(st);
- git__free(st);
-}
-
-static void init_once(void)
-{
- if ((init_error = git_mutex_init(&git__mwindow_mutex)) != 0)
- return;
-
- pthread_key_create(&_tls_key, &cb__free_status);
-
- init_error = init_common();
-}
-
-int git_libgit2_init(void)
-{
- int ret, err;
-
- if ((err = pthread_mutex_lock(&_init_mutex)) != 0)
- return err;
-
- ret = git_atomic_inc(&git__n_inits);
- err = pthread_once(&_once_init, init_once);
- err |= pthread_mutex_unlock(&_init_mutex);
-
- if (err || init_error)
- return err | init_error;
-
- return ret;
-}
-
-int git_libgit2_shutdown(void)
-{
- void *ptr = NULL;
- pthread_once_t new_once = PTHREAD_ONCE_INIT;
- int error, ret;
-
- if ((error = pthread_mutex_lock(&_init_mutex)) != 0)
- return error;
-
- if ((ret = git_atomic_dec(&git__n_inits)) != 0)
- goto out;
-
- /* Shut down any subsystems that have global state */
- shutdown_common();
-
- ptr = pthread_getspecific(_tls_key);
- pthread_setspecific(_tls_key, NULL);
-
- git__global_state_cleanup(ptr);
- git__free(ptr);
-
- pthread_key_delete(_tls_key);
- git_mutex_free(&git__mwindow_mutex);
- _once_init = new_once;
-
-out:
- if ((error = pthread_mutex_unlock(&_init_mutex)) != 0)
- return error;
-
- return ret;
-}
-
-git_global_st *git__global_state(void)
-{
- git_global_st *ptr;
-
- assert(git_atomic_get(&git__n_inits) > 0);
-
- if ((ptr = pthread_getspecific(_tls_key)) != NULL)
- return ptr;
-
- ptr = git__calloc(1, sizeof(git_global_st));
- if (!ptr)
- return NULL;
-
- git_buf_init(&ptr->error_buf, 0);
- pthread_setspecific(_tls_key, ptr);
- return ptr;
-}
-
-#else
-
-static git_global_st __state;
-
-int git_libgit2_init(void)
-{
- int ret;
-
- /* Only init subsystems the first time */
- if ((ret = git_atomic_inc(&git__n_inits)) != 1)
- return ret;
-
- if ((ret = init_common()) < 0)
- return ret;
-
- return 1;
-}
-
-int git_libgit2_shutdown(void)
-{
- int ret;
-
- /* Shut down any subsystems that have global state */
- if ((ret = git_atomic_dec(&git__n_inits)) == 0) {
- shutdown_common();
- git__global_state_cleanup(&__state);
- memset(&__state, 0, sizeof(__state));
- }
-
- return ret;
-}
-
-git_global_st *git__global_state(void)
-{
- return &__state;
-}
-
-#endif /* GIT_THREADS */
diff --git a/src/global.h b/src/global.h
deleted file mode 100644
index db41dad1f..000000000
--- a/src/global.h
+++ /dev/null
@@ -1,41 +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 INCLUDE_global_h__
-#define INCLUDE_global_h__
-
-#include "common.h"
-
-#include "mwindow.h"
-#include "hash.h"
-
-typedef struct {
- git_error *last_error;
- git_error error_t;
- git_buf error_buf;
- char oid_fmt[GIT_OID_HEXSZ+1];
-
- /* On Windows, this is the current child thread that was started by
- * `git_thread_create`. This is used to set the thread's exit code
- * when terminated by `git_thread_exit`. It is unused on POSIX.
- */
- git_thread *current_thread;
-} git_global_st;
-
-git_global_st *git__global_state(void);
-
-extern git_mutex git__mwindow_mutex;
-
-#define GIT_GLOBAL (git__global_state())
-
-typedef void (*git_global_shutdown_fn)(void);
-
-extern void git__on_shutdown(git_global_shutdown_fn callback);
-
-extern const char *git_libgit2__user_agent(void);
-extern const char *git_libgit2__ssl_ciphers(void);
-
-#endif
diff --git a/src/hash/sha1/win32.c b/src/hash/sha1/win32.c
index c73695665..b1266cca0 100644
--- a/src/hash/sha1/win32.c
+++ b/src/hash/sha1/win32.c
@@ -7,7 +7,7 @@
#include "win32.h"
-#include "global.h"
+#include "runtime.h"
#include <wincrypt.h>
#include <strsafe.h>
@@ -129,7 +129,8 @@ int git_hash_sha1_global_init(void)
if ((error = hash_cng_prov_init()) < 0)
error = hash_cryptoapi_prov_init();
- git__on_shutdown(sha1_shutdown);
+ if (!error)
+ error = git_runtime_shutdown_register(sha1_shutdown);
return error;
}
diff --git a/src/settings.c b/src/libgit2.c
index 69ebcb7ab..316d89365 100644
--- a/src/settings.c
+++ b/src/libgit2.c
@@ -5,7 +5,33 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "libgit2.h"
+
+#include <git2.h>
+#include "alloc.h"
+#include "cache.h"
#include "common.h"
+#include "filter.h"
+#include "hash.h"
+#include "index.h"
+#include "merge_driver.h"
+#include "pool.h"
+#include "mwindow.h"
+#include "object.h"
+#include "odb.h"
+#include "refs.h"
+#include "runtime.h"
+#include "sysdir.h"
+#include "thread-utils.h"
+#include "threadstate.h"
+#include "git2/global.h"
+#include "streams/registry.h"
+#include "streams/mbedtls.h"
+#include "streams/openssl.h"
+#include "transports/smart.h"
+#include "transports/http.h"
+#include "transports/ssh.h"
+#include "win32/w32_stack.h"
#ifdef GIT_OPENSSL
# include <openssl/err.h>
@@ -15,19 +41,53 @@
# include <mbedtls/error.h>
#endif
-#include <git2.h>
-#include "alloc.h"
-#include "sysdir.h"
-#include "cache.h"
-#include "global.h"
-#include "object.h"
-#include "odb.h"
-#include "refs.h"
-#include "index.h"
-#include "transports/smart.h"
-#include "transports/http.h"
-#include "streams/openssl.h"
-#include "streams/mbedtls.h"
+/* Declarations for tuneable settings */
+extern size_t git_mwindow__window_size;
+extern size_t git_mwindow__mapped_limit;
+extern size_t git_mwindow__file_limit;
+extern size_t git_indexer__max_objects;
+extern bool git_disable_pack_keep_file_checks;
+
+char *git__user_agent;
+char *git__ssl_ciphers;
+
+static void libgit2_settings_global_shutdown(void)
+{
+ git__free(git__user_agent);
+ git__free(git__ssl_ciphers);
+}
+
+static int git_libgit2_settings_global_init(void)
+{
+ return git_runtime_shutdown_register(libgit2_settings_global_shutdown);
+}
+
+int git_libgit2_init(void)
+{
+ static git_runtime_init_fn init_fns[] = {
+ git_allocator_global_init,
+ git_threadstate_global_init,
+ git_threads_global_init,
+ git_hash_global_init,
+ git_sysdir_global_init,
+ git_filter_global_init,
+ git_merge_driver_global_init,
+ git_transport_ssh_global_init,
+ git_stream_registry_global_init,
+ git_openssl_stream_global_init,
+ git_mbedtls_stream_global_init,
+ git_mwindow_global_init,
+ git_pool_global_init,
+ git_libgit2_settings_global_init
+ };
+
+ return git_runtime_init(init_fns, ARRAY_SIZE(init_fns));
+}
+
+int git_libgit2_shutdown(void)
+{
+ return git_runtime_shutdown();
+}
int git_libgit2_version(int *major, int *minor, int *rev)
{
@@ -56,13 +116,6 @@ int git_libgit2_features(void)
;
}
-/* Declarations for tuneable settings */
-extern size_t git_mwindow__window_size;
-extern size_t git_mwindow__mapped_limit;
-extern size_t git_mwindow__file_limit;
-extern size_t git_indexer__max_objects;
-extern bool git_disable_pack_keep_file_checks;
-
static int config_level_to_sysdir(int config_level)
{
int val = -1;
@@ -88,9 +141,6 @@ static int config_level_to_sysdir(int config_level)
return val;
}
-extern char *git__user_agent;
-extern char *git__ssl_ciphers;
-
const char *git_libgit2__user_agent(void)
{
return git__user_agent;
diff --git a/src/libgit2.h b/src/libgit2.h
new file mode 100644
index 000000000..6f92a8318
--- /dev/null
+++ b/src/libgit2.h
@@ -0,0 +1,13 @@
+/*
+ * 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_libgit2_h__
+#define INCLUDE_libgit2_h__
+
+extern const char *git_libgit2__user_agent(void);
+extern const char *git_libgit2__ssl_ciphers(void);
+
+#endif
diff --git a/src/merge_driver.c b/src/merge_driver.c
index 666349b15..b1f574801 100644
--- a/src/merge_driver.c
+++ b/src/merge_driver.c
@@ -8,7 +8,7 @@
#include "merge_driver.h"
#include "vector.h"
-#include "global.h"
+#include "runtime.h"
#include "merge.h"
#include "git2/merge.h"
#include "git2/sys/merge.h"
@@ -209,7 +209,7 @@ int git_merge_driver_global_init(void)
merge_driver_name__binary, &git_merge_driver__binary)) < 0)
goto done;
- git__on_shutdown(git_merge_driver_global_shutdown);
+ error = git_runtime_shutdown_register(git_merge_driver_global_shutdown);
done:
if (error < 0)
diff --git a/src/mwindow.c b/src/mwindow.c
index ac26452f4..a852d6bf2 100644
--- a/src/mwindow.c
+++ b/src/mwindow.c
@@ -10,7 +10,7 @@
#include "vector.h"
#include "futils.h"
#include "map.h"
-#include "global.h"
+#include "runtime.h"
#include "strmap.h"
#include "pack.h"
@@ -29,26 +29,36 @@ size_t git_mwindow__window_size = DEFAULT_WINDOW_SIZE;
size_t git_mwindow__mapped_limit = DEFAULT_MAPPED_LIMIT;
size_t git_mwindow__file_limit = DEFAULT_FILE_LIMIT;
+/* Mutex to control access */
+git_mutex git__mwindow_mutex;
+
/* Whenever you want to read or modify this, grab git__mwindow_mutex */
git_mwindow_ctl git_mwindow__mem_ctl;
/* Global list of mwindow files, to open packs once across repos */
git_strmap *git__pack_cache = NULL;
-static void git_mwindow_files_free(void)
+static void git_mwindow_global_shutdown(void)
{
git_strmap *tmp = git__pack_cache;
+ git_mutex_free(&git__mwindow_mutex);
+
git__pack_cache = NULL;
git_strmap_free(tmp);
}
int git_mwindow_global_init(void)
{
+ int error;
+
assert(!git__pack_cache);
- git__on_shutdown(git_mwindow_files_free);
- return git_strmap_new(&git__pack_cache);
+ if ((error = git_mutex_init(&git__mwindow_mutex)) < 0 ||
+ (error = git_strmap_new(&git__pack_cache)) < 0)
+ return error;
+
+ return git_runtime_shutdown_register(git_mwindow_global_shutdown);
}
int git_mwindow_get_pack(struct git_pack_file **out, const char *path)
diff --git a/src/mwindow.h b/src/mwindow.h
index 1a391b055..7519fc36d 100644
--- a/src/mwindow.h
+++ b/src/mwindow.h
@@ -13,6 +13,8 @@
#include "map.h"
#include "vector.h"
+extern git_mutex git__mwindow_mutex;
+
typedef struct git_mwindow {
struct git_mwindow *next;
git_map window_map;
diff --git a/src/net.c b/src/net.c
index dbde626b5..ac1bc4299 100644
--- a/src/net.c
+++ b/src/net.c
@@ -14,7 +14,7 @@
#include "posix.h"
#include "buffer.h"
#include "http_parser.h"
-#include "global.h"
+#include "runtime.h"
#define DEFAULT_PORT_HTTP "80"
#define DEFAULT_PORT_HTTPS "443"
diff --git a/src/netops.c b/src/netops.c
index 04ae824cc..1ef230293 100644
--- a/src/netops.c
+++ b/src/netops.c
@@ -13,7 +13,7 @@
#include "posix.h"
#include "buffer.h"
#include "http_parser.h"
-#include "global.h"
+#include "runtime.h"
int gitno_recv(gitno_buffer *buf)
{
diff --git a/src/oid.c b/src/oid.c
index 7831aca89..a8ad3d2ee 100644
--- a/src/oid.c
+++ b/src/oid.c
@@ -9,7 +9,7 @@
#include "git2/oid.h"
#include "repository.h"
-#include "global.h"
+#include "threadstate.h"
#include <string.h>
#include <limits.h>
@@ -107,7 +107,7 @@ int git_oid_pathfmt(char *str, const git_oid *oid)
char *git_oid_tostr_s(const git_oid *oid)
{
- char *str = GIT_GLOBAL->oid_fmt;
+ char *str = GIT_THREADSTATE->oid_fmt;
git_oid_nfmt(str, GIT_OID_HEXSZ + 1, oid);
return str;
}
diff --git a/src/runtime.c b/src/runtime.c
new file mode 100644
index 000000000..56110c49a
--- /dev/null
+++ b/src/runtime.c
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+#include "common.h"
+#include "runtime.h"
+
+static git_runtime_shutdown_fn shutdown_callback[32];
+static git_atomic shutdown_callback_count;
+
+static git_atomic init_count;
+
+static int init_common(git_runtime_init_fn init_fns[], size_t cnt)
+{
+ size_t i;
+ int ret;
+
+ /* Initialize subsystems that have global state */
+ for (i = 0; i < cnt; i++) {
+ if ((ret = init_fns[i]()) != 0)
+ break;
+ }
+
+ GIT_MEMORY_BARRIER;
+
+ return ret;
+}
+
+static void shutdown_common(void)
+{
+ git_runtime_shutdown_fn cb;
+ int pos;
+
+ for (pos = git_atomic_get(&shutdown_callback_count);
+ pos > 0;
+ pos = git_atomic_dec(&shutdown_callback_count)) {
+ cb = git__swap(shutdown_callback[pos - 1], NULL);
+
+ if (cb != NULL)
+ cb();
+ }
+}
+
+int git_runtime_shutdown_register(git_runtime_shutdown_fn callback)
+{
+ int count = git_atomic_inc(&shutdown_callback_count);
+
+ if (count > (int)ARRAY_SIZE(shutdown_callback) || count == 0) {
+ git_error_set(GIT_ERROR_INVALID,
+ "too many shutdown callbacks registered");
+ git_atomic_dec(&shutdown_callback_count);
+ return -1;
+ }
+
+ shutdown_callback[count - 1] = callback;
+
+ return 0;
+}
+
+#if defined(GIT_THREADS) && defined(GIT_WIN32)
+
+/*
+ * On Win32, we use a spinlock to provide locking semantics. This is
+ * lighter-weight than a proper critical section.
+ */
+static volatile LONG init_spinlock = 0;
+
+GIT_INLINE(int) init_lock(void)
+{
+ while (InterlockedCompareExchange(&init_spinlock, 1, 0)) { Sleep(0); }
+ return 0;
+}
+
+GIT_INLINE(int) init_unlock(void)
+{
+ InterlockedExchange(&init_spinlock, 0);
+ return 0;
+}
+
+#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
+
+/*
+ * On POSIX, we need to use a proper mutex for locking. We might prefer
+ * a spinlock here, too, but there's no static initializer for a
+ * pthread_spinlock_t.
+ */
+static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+GIT_INLINE(int) init_lock(void)
+{
+ return pthread_mutex_lock(&init_mutex) == 0 ? 0 : -1;
+}
+
+GIT_INLINE(int) init_unlock(void)
+{
+ return pthread_mutex_unlock(&init_mutex) == 0 ? 0 : -1;
+}
+
+#elif defined(GIT_THREADS)
+# error unknown threading model
+#else
+
+# define mutex_lock() 0
+# define mutex_unlock() 0
+
+#endif
+
+int git_runtime_init(git_runtime_init_fn init_fns[], size_t cnt)
+{
+ int ret;
+
+ if (init_lock() < 0)
+ return -1;
+
+ /* Only do work on a 0 -> 1 transition of the refcount */
+ if ((ret = git_atomic_inc(&init_count)) == 1) {
+ if (init_common(init_fns, cnt) < 0)
+ ret = -1;
+ }
+
+ if (init_unlock() < 0)
+ return -1;
+
+ return ret;
+}
+
+int git_runtime_shutdown(void)
+{
+ int ret;
+
+ /* Enter the lock */
+ if (init_lock() < 0)
+ return -1;
+
+ /* Only do work on a 1 -> 0 transition of the refcount */
+ if ((ret = git_atomic_dec(&init_count)) == 0)
+ shutdown_common();
+
+ /* Exit the lock */
+ if (init_unlock() < 0)
+ return -1;
+
+ return ret;
+}
diff --git a/src/runtime.h b/src/runtime.h
new file mode 100644
index 000000000..be2e37a60
--- /dev/null
+++ b/src/runtime.h
@@ -0,0 +1,53 @@
+/*
+ * 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_runtime_h__
+#define INCLUDE_runtime_h__
+
+#include "common.h"
+
+typedef int (*git_runtime_init_fn)(void);
+typedef void (*git_runtime_shutdown_fn)(void);
+
+/**
+ * Start up a new runtime. If this is the first time that this
+ * function is called within the context of the current library
+ * or executable, then the given `init_fns` will be invoked. If
+ * it is not the first time, they will be ignored.
+ *
+ * The given initialization functions _may_ register shutdown
+ * handlers using `git_runtime_shutdown_register` to be notified
+ * when the runtime is shutdown.
+ *
+ * @param init_fns The list of initialization functions to call
+ * @param cnt The number of init_fns
+ * @return The number of initializations performed (including this one) or an error
+ */
+int git_runtime_init(git_runtime_init_fn init_fns[], size_t cnt);
+
+/**
+ * Shut down the runtime. If this is the last shutdown call,
+ * such that there are no remaining `init` calls, then any
+ * shutdown hooks that have been registered will be invoked.
+ *
+ * The number of oustanding initializations will be returned.
+ * If this number is 0, then the runtime is shutdown.
+ *
+ * @return The number of outstanding initializations (after this one) or an error
+ */
+int git_runtime_shutdown(void);
+
+/**
+ * Register a shutdown handler for this runtime. This should be done
+ * by a function invoked by `git_runtime_init` to ensure that the
+ * appropriate locks are taken.
+ *
+ * @param callback The shutdown handler callback
+ * @return 0 or an error code
+ */
+int git_runtime_shutdown_register(git_runtime_shutdown_fn callback);
+
+#endif
diff --git a/src/settings.h b/src/settings.h
new file mode 100644
index 000000000..dc42ce939
--- /dev/null
+++ b/src/settings.h
@@ -0,0 +1,11 @@
+/*
+ * 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.
+ */
+
+extern int git_settings_global_init(void);
+
+extern const char *git_libgit2__user_agent(void);
+extern const char *git_libgit2__ssl_ciphers(void);
diff --git a/src/streams/mbedtls.c b/src/streams/mbedtls.c
index cbe2f681a..00daa5521 100644
--- a/src/streams/mbedtls.c
+++ b/src/streams/mbedtls.c
@@ -11,7 +11,7 @@
#include <ctype.h>
-#include "global.h"
+#include "runtime.h"
#include "stream.h"
#include "streams/socket.h"
#include "netops.h"
@@ -152,9 +152,7 @@ int git_mbedtls_stream_global_init(void)
if (!loaded && crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
loaded = (git_mbedtls__set_cert_location(crtpath, 1) == 0);
- git__on_shutdown(shutdown_ssl);
-
- return 0;
+ return git_runtime_shutdown_register(shutdown_ssl);
cleanup:
mbedtls_ctr_drbg_free(ctr_drbg);
diff --git a/src/streams/openssl.c b/src/streams/openssl.c
index 6a490d17d..0a0c2c5e5 100644
--- a/src/streams/openssl.c
+++ b/src/streams/openssl.c
@@ -11,7 +11,8 @@
#include <ctype.h>
-#include "global.h"
+#include "runtime.h"
+#include "settings.h"
#include "posix.h"
#include "stream.h"
#include "streams/socket.h"
@@ -285,9 +286,7 @@ int git_openssl_stream_global_init(void)
if (init_bio_method() < 0)
goto error;
- git__on_shutdown(shutdown_ssl);
-
- return 0;
+ return git_runtime_shutdown_register(shutdown_ssl);
error:
git_error_set(GIT_ERROR_NET, "could not initialize openssl: %s",
@@ -324,8 +323,8 @@ int git_openssl_set_locking(void)
}
CRYPTO_set_locking_callback(openssl_locking_function);
- git__on_shutdown(shutdown_ssl_locking);
- return 0;
+ return git_runtime_shutdown_register(shutdown_ssl_locking);
+
#elif !defined(OPENSSL_LEGACY_API)
return 0;
#else
diff --git a/src/streams/registry.c b/src/streams/registry.c
index 284431207..b3bf17a4e 100644
--- a/src/streams/registry.c
+++ b/src/streams/registry.c
@@ -9,7 +9,7 @@
#include "streams/registry.h"
-#include "global.h"
+#include "runtime.h"
#include "streams/tls.h"
#include "streams/mbedtls.h"
#include "streams/openssl.h"
@@ -33,8 +33,7 @@ int git_stream_registry_global_init(void)
if (git_rwlock_init(&stream_registry.lock) < 0)
return -1;
- git__on_shutdown(shutdown_stream_registry);
- return 0;
+ return git_runtime_shutdown_register(shutdown_stream_registry);
}
GIT_INLINE(void) stream_registration_cpy(
diff --git a/src/streams/tls.c b/src/streams/tls.c
index 6a251717b..255a4a0f6 100644
--- a/src/streams/tls.c
+++ b/src/streams/tls.c
@@ -8,7 +8,6 @@
#include "git2/errors.h"
#include "common.h"
-#include "global.h"
#include "streams/registry.h"
#include "streams/tls.h"
#include "streams/mbedtls.h"
diff --git a/src/sysdir.c b/src/sysdir.c
index 6dc78c8fd..401b4a55e 100644
--- a/src/sysdir.c
+++ b/src/sysdir.c
@@ -7,7 +7,7 @@
#include "sysdir.h"
-#include "global.h"
+#include "runtime.h"
#include "buffer.h"
#include "path.h"
#include <ctype.h>
@@ -189,9 +189,7 @@ int git_sysdir_global_init(void)
for (i = 0; !error && i < ARRAY_SIZE(git_sysdir__dirs); i++)
error = git_sysdir__dirs[i].guess(&git_sysdir__dirs[i].buf);
- git__on_shutdown(git_sysdir_global_shutdown);
-
- return error;
+ return git_runtime_shutdown_register(git_sysdir_global_shutdown);
}
static int git_sysdir_check_selector(git_sysdir_t which)
diff --git a/src/thread-utils.h b/src/thread-utils.h
index 3311672b4..b4e44b468 100644
--- a/src/thread-utils.h
+++ b/src/thread-utils.h
@@ -235,6 +235,8 @@ GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
#else
+GIT_INLINE(int) git_threads_global_init(void) { return 0; }
+
#define git_thread unsigned int
#define git_thread_create(thread, start_routine, arg) 0
#define git_thread_join(id, status) (void)0
diff --git a/src/threadstate.c b/src/threadstate.c
new file mode 100644
index 000000000..8e17124a2
--- /dev/null
+++ b/src/threadstate.c
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+
+#include "threadstate.h"
+#include "runtime.h"
+
+static void threadstate_dispose(git_threadstate *threadstate);
+
+/**
+ * Handle the thread-local state
+ *
+ * `git_threadstate_global_init` will be called as part
+ * of `git_libgit2_init` (which itself must be called
+ * before calling any other function in the library).
+ *
+ * This function allocates a TLS index (using pthreads
+ * or fiber-local storage in Win32) to store the per-
+ * thread state.
+ *
+ * Any internal method that requires thread-local state
+ * will then call `git_threadstate_get()` which returns a
+ * pointer to the thread-local state structure; this
+ * structure is lazily allocated on each thread.
+ *
+ * This mechanism will register a shutdown handler
+ * (`git_threadstate_global_shutdown`) which will free the
+ * TLS index. This shutdown handler will be called by
+ * `git_libgit2_shutdown`.
+ *
+ * If libgit2 is built without threading support, the
+ * `git_threadstate_get()` call returns a pointer to a single,
+ * statically allocated global state. The `git_thread_`
+ * functions are not available in that case.
+ */
+
+#if defined(GIT_THREADS) && defined(GIT_WIN32)
+
+static DWORD fls_index;
+
+static void git_threadstate_global_shutdown(void)
+{
+ FlsFree(fls_index);
+}
+
+static void WINAPI fls_free(void *threadstate)
+{
+ threadstate_dispose(threadstate);
+ git__free(threadstate);
+}
+
+int git_threadstate_global_init(void)
+{
+ if ((fls_index = FlsAlloc(fls_free)) == FLS_OUT_OF_INDEXES)
+ return -1;
+
+ return git_runtime_shutdown_register(git_threadstate_global_shutdown);
+}
+
+git_threadstate *git_threadstate_get(void)
+{
+ git_threadstate *threadstate;
+
+ if ((threadstate = FlsGetValue(fls_index)) != NULL)
+ return threadstate;
+
+ if ((threadstate = git__calloc(1, sizeof(git_threadstate))) == NULL ||
+ git_buf_init(&threadstate->error_buf, 0) < 0)
+ return NULL;
+
+ FlsSetValue(fls_index, threadstate);
+ return threadstate;
+}
+
+#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
+
+static pthread_key_t tls_key;
+
+static void git_threadstate_global_shutdown(void)
+{
+ git_threadstate *threadstate;
+
+ threadstate = pthread_getspecific(tls_key);
+ pthread_setspecific(tls_key, NULL);
+
+ threadstate_dispose(threadstate);
+ git__free(threadstate);
+
+ pthread_key_delete(tls_key);
+}
+
+static void tls_free(void *threadstate)
+{
+ threadstate_dispose(threadstate);
+ git__free(threadstate);
+}
+
+int git_threadstate_global_init(void)
+{
+ if (pthread_key_create(&tls_key, &tls_free) != 0)
+ return -1;
+
+ return git_runtime_shutdown_register(git_threadstate_global_shutdown);
+}
+
+git_threadstate *git_threadstate_get(void)
+{
+ git_threadstate *threadstate;
+
+ if ((threadstate = pthread_getspecific(tls_key)) != NULL)
+ return threadstate;
+
+ if ((threadstate = git__calloc(1, sizeof(git_threadstate))) == NULL ||
+ git_buf_init(&threadstate->error_buf, 0) < 0)
+ return NULL;
+
+ pthread_setspecific(tls_key, threadstate);
+ return threadstate;
+}
+
+#elif defined(GIT_THREADS)
+# error unknown threading model
+#else
+
+static git_threadstate threadstate;
+
+static void git_threadstate_global_shutdown(void)
+{
+ threadstate_dispose(&threadstate);
+ memset(&threadstate, 0, sizeof(git_threadstate));
+}
+
+int git_threadstate_global_init(void)
+{
+ return git_runtime_shutdown_register(git_tlsdata_global_shutdown);
+}
+
+git_threadstate *git_threadstate_get(void)
+{
+ return &threadstate;
+}
+
+#endif
+
+static void threadstate_dispose(git_threadstate *threadstate)
+{
+ if (!threadstate)
+ return;
+
+ git__free(threadstate->error_t.message);
+ threadstate->error_t.message = NULL;
+}
diff --git a/src/threadstate.h b/src/threadstate.h
new file mode 100644
index 000000000..51810a939
--- /dev/null
+++ b/src/threadstate.h
@@ -0,0 +1,24 @@
+/*
+ * 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_threadstate_h__
+#define INCLUDE_threadstate_h__
+
+#include "common.h"
+
+typedef struct {
+ git_error *last_error;
+ git_error error_t;
+ git_buf error_buf;
+ char oid_fmt[GIT_OID_HEXSZ+1];
+} git_threadstate;
+
+extern int git_threadstate_global_init(void);
+extern git_threadstate *git_threadstate_get(void);
+
+#define GIT_THREADSTATE (git_threadstate_get())
+
+#endif
diff --git a/src/trace.c b/src/trace.c
index ec6a90aad..3acb64398 100644
--- a/src/trace.c
+++ b/src/trace.c
@@ -8,7 +8,7 @@
#include "trace.h"
#include "buffer.h"
-#include "global.h"
+#include "runtime.h"
#include "git2/trace.h"
#ifdef GIT_TRACE
diff --git a/src/transports/http.c b/src/transports/http.c
index 66731b0ce..fb1740c33 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -14,7 +14,6 @@
#include "buffer.h"
#include "net.h"
#include "netops.h"
-#include "global.h"
#include "remote.h"
#include "git2/sys/credential.h"
#include "smart.h"
diff --git a/src/transports/http.h b/src/transports/http.h
index c02109cec..5c360b883 100644
--- a/src/transports/http.h
+++ b/src/transports/http.h
@@ -9,6 +9,7 @@
#define INCLUDE_transports_http_h__
#include "buffer.h"
+#include "settings.h"
#include "httpclient.h"
#define GIT_HTTP_REPLAY_MAX 15
diff --git a/src/transports/httpclient.c b/src/transports/httpclient.c
index ee936c81a..6ec22f837 100644
--- a/src/transports/httpclient.c
+++ b/src/transports/httpclient.c
@@ -10,7 +10,6 @@
#include "http_parser.h"
#include "vector.h"
#include "trace.h"
-#include "global.h"
#include "httpclient.h"
#include "http.h"
#include "auth.h"
diff --git a/src/transports/ssh.c b/src/transports/ssh.c
index 68b3cbeda..f4ed05bb1 100644
--- a/src/transports/ssh.c
+++ b/src/transports/ssh.c
@@ -11,7 +11,7 @@
#include <libssh2.h>
#endif
-#include "global.h"
+#include "runtime.h"
#include "git2.h"
#include "buffer.h"
#include "net.h"
@@ -934,8 +934,7 @@ int git_transport_ssh_global_init(void)
return -1;
}
- git__on_shutdown(shutdown_ssh);
- return 0;
+ return git_runtime_shutdown_register(shutdown_ssh);
#else
diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c
index f9736cd07..2a1f6f26f 100644
--- a/src/transports/winhttp.c
+++ b/src/transports/winhttp.c
@@ -17,7 +17,6 @@
#include "smart.h"
#include "remote.h"
#include "repository.h"
-#include "global.h"
#include "http.h"
#include "git2/sys/credential.h"
diff --git a/src/unix/pthread.h b/src/unix/pthread.h
index 233561b4e..55f4ae227 100644
--- a/src/unix/pthread.h
+++ b/src/unix/pthread.h
@@ -12,7 +12,8 @@ typedef struct {
pthread_t thread;
} git_thread;
-#define git_threads_init() (void)0
+GIT_INLINE(int) git_threads_global_init(void) { return 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) \
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index cacf986e8..5a5e92158 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -14,7 +14,6 @@
#include "utf-conv.h"
#include "repository.h"
#include "reparse.h"
-#include "global.h"
#include "buffer.h"
#include <errno.h>
#include <io.h>
diff --git a/src/win32/thread.c b/src/win32/thread.c
index 42dba7f97..51b005bc8 100644
--- a/src/win32/thread.c
+++ b/src/win32/thread.c
@@ -6,8 +6,7 @@
*/
#include "thread.h"
-
-#include "../global.h"
+#include "runtime.h"
#define CLEAN_THREAD_EXIT 0x6F012842
@@ -19,6 +18,8 @@ static win32_srwlock_fn win32_srwlock_release_shared;
static win32_srwlock_fn win32_srwlock_acquire_exclusive;
static win32_srwlock_fn win32_srwlock_release_exclusive;
+static DWORD fls_index;
+
/* 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
@@ -28,14 +29,19 @@ static DWORD WINAPI git_win32__threadproc(LPVOID lpParameter)
git_thread *thread = lpParameter;
/* Set the current thread for `git_thread_exit` */
- GIT_GLOBAL->current_thread = thread;
+ FlsSetValue(fls_index, thread);
thread->result = thread->proc(thread->param);
return CLEAN_THREAD_EXIT;
}
-int git_threads_init(void)
+static void git_threads_global_shutdown(void)
+{
+ FlsFree(fls_index);
+}
+
+int git_threads_global_init(void)
{
HMODULE hModule = GetModuleHandleW(L"kernel32");
@@ -52,7 +58,10 @@ int git_threads_init(void)
GetProcAddress(hModule, "ReleaseSRWLockExclusive");
}
- return 0;
+ if ((fls_index = FlsAlloc(NULL)) == FLS_OUT_OF_INDEXES)
+ return -1;
+
+ return git_runtime_shutdown_register(git_threads_global_shutdown);
}
int git_thread_create(
@@ -99,8 +108,11 @@ int git_thread_join(
void git_thread_exit(void *value)
{
- assert(GIT_GLOBAL->current_thread);
- GIT_GLOBAL->current_thread->result = value;
+ git_thread *thread = FlsGetValue(fls_index);
+
+ if (thread)
+ thread->result = value;
+
ExitThread(CLEAN_THREAD_EXIT);
}
diff --git a/src/win32/thread.h b/src/win32/thread.h
index 41cbf015b..8305036b4 100644
--- a/src/win32/thread.h
+++ b/src/win32/thread.h
@@ -35,7 +35,7 @@ typedef struct {
} native;
} git_rwlock;
-int git_threads_init(void);
+int git_threads_global_init(void);
int git_thread_create(git_thread *GIT_RESTRICT,
void *(*) (void *),
diff --git a/tests/core/useragent.c b/tests/core/useragent.c
index c6c5220b2..2ce935bf5 100644
--- a/tests/core/useragent.c
+++ b/tests/core/useragent.c
@@ -1,5 +1,5 @@
#include "clar_libgit2.h"
-#include "global.h"
+#include "settings.h"
void test_core_useragent__get(void)
{
diff --git a/tests/pack/filelimit.c b/tests/pack/filelimit.c
index 044679f3b..b39ab7327 100644
--- a/tests/pack/filelimit.c
+++ b/tests/pack/filelimit.c
@@ -1,6 +1,5 @@
#include "clar_libgit2.h"
#include "mwindow.h"
-#include "global.h"
#include <git2.h>
#include "git2/sys/commit.h"
diff --git a/tests/threads/basic.c b/tests/threads/basic.c
index ed4fd2f9b..2d7ddc26b 100644
--- a/tests/threads/basic.c
+++ b/tests/threads/basic.c
@@ -54,6 +54,12 @@ static void *return_normally(void *param)
{
return param;
}
+
+static void *exit_abruptly(void *param)
+{
+ git_thread_exit(param);
+ return NULL;
+}
#endif
void test_threads_basic__exit(void)
@@ -70,7 +76,7 @@ void test_threads_basic__exit(void)
cl_assert_equal_sz(424242, (size_t)result);
/* Ensure that the return value of `git_thread_exit` is returned. */
- cl_git_pass(git_thread_create(&thread, return_normally, (void *)232323));
+ cl_git_pass(git_thread_create(&thread, exit_abruptly, (void *)232323));
cl_git_pass(git_thread_join(&thread, &result));
cl_assert_equal_sz(232323, (size_t)result);
#endif