Unverified Commit 20450cbe by Edward Thomson Committed by GitHub

Merge pull request #5546 from libgit2/ethomson/init

Refactor "global" state
parents e9858645 634c285a
...@@ -6,10 +6,16 @@ ...@@ -6,10 +6,16 @@
*/ */
#include "alloc.h" #include "alloc.h"
#include "runtime.h"
#include "allocators/stdalloc.h" #include "allocators/stdalloc.h"
#include "allocators/win32_crtdbg.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; git_allocator git__allocator;
static int setup_default_allocator(void) static int setup_default_allocator(void)
...@@ -21,8 +27,24 @@ static int setup_default_allocator(void) ...@@ -21,8 +27,24 @@ static int setup_default_allocator(void)
#endif #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) 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 * We don't want to overwrite any allocator which has been set before
* the init function is called. * the init function is called.
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#if defined(GIT_MSVC_CRTDBG) #if defined(GIT_MSVC_CRTDBG)
#include "win32/w32_stack.h"
#include "win32/w32_crtdbg_stacktrace.h" #include "win32/w32_crtdbg_stacktrace.h"
static void *crtdbg__malloc(size_t len, const char *file, int line) static void *crtdbg__malloc(size_t len, const char *file, int line)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include "common.h" #include "common.h"
#include "global.h" #include "threadstate.h"
#include "posix.h" #include "posix.h"
#include "buffer.h" #include "buffer.h"
...@@ -22,18 +22,18 @@ static git_error g_git_oom_error = { ...@@ -22,18 +22,18 @@ static git_error g_git_oom_error = {
static void set_error_from_buffer(int error_class) static void set_error_from_buffer(int error_class)
{ {
git_error *error = &GIT_GLOBAL->error_t; git_error *error = &GIT_THREADSTATE->error_t;
git_buf *buf = &GIT_GLOBAL->error_buf; git_buf *buf = &GIT_THREADSTATE->error_buf;
error->message = buf->ptr; error->message = buf->ptr;
error->klass = error_class; error->klass = error_class;
GIT_GLOBAL->last_error = error; GIT_THREADSTATE->last_error = error;
} }
static void set_error(int error_class, char *string) 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); git_buf_clear(buf);
if (string) { if (string) {
...@@ -46,7 +46,7 @@ static void set_error(int error_class, char *string) ...@@ -46,7 +46,7 @@ static void set_error(int error_class, char *string)
void git_error_set_oom(void) 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, ...) 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) ...@@ -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; DWORD win32_error_code = (error_class == GIT_ERROR_OS) ? GetLastError() : 0;
#endif #endif
int error_code = (error_class == GIT_ERROR_OS) ? errno : 0; 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); git_buf_clear(buf);
if (fmt) { if (fmt) {
...@@ -97,7 +97,7 @@ void git_error_vset(int error_class, const char *fmt, va_list ap) ...@@ -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) 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); assert(string);
...@@ -118,9 +118,9 @@ int git_error_set_str(int error_class, const char *string) ...@@ -118,9 +118,9 @@ int git_error_set_str(int error_class, const char *string)
void git_error_clear(void) void git_error_clear(void)
{ {
if (GIT_GLOBAL->last_error != NULL) { if (GIT_THREADSTATE->last_error != NULL) {
set_error(0, NULL); set_error(0, NULL);
GIT_GLOBAL->last_error = NULL; GIT_THREADSTATE->last_error = NULL;
} }
errno = 0; errno = 0;
...@@ -131,13 +131,13 @@ void git_error_clear(void) ...@@ -131,13 +131,13 @@ void git_error_clear(void)
const git_error *git_error_last(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) int git_error_state_capture(git_error_state *state, int error_code)
{ {
git_error *error = GIT_GLOBAL->last_error; git_error *error = GIT_THREADSTATE->last_error;
git_buf *error_buf = &GIT_GLOBAL->error_buf; git_buf *error_buf = &GIT_THREADSTATE->error_buf;
memset(state, 0, sizeof(git_error_state)); memset(state, 0, sizeof(git_error_state));
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include "futils.h" #include "futils.h"
#include "hash.h" #include "hash.h"
#include "repository.h" #include "repository.h"
#include "global.h" #include "runtime.h"
#include "git2/sys/filter.h" #include "git2/sys/filter.h"
#include "git2/config.h" #include "git2/config.h"
#include "blob.h" #include "blob.h"
...@@ -206,7 +206,7 @@ int git_filter_global_init(void) ...@@ -206,7 +206,7 @@ int git_filter_global_init(void)
GIT_FILTER_IDENT, ident, GIT_FILTER_IDENT_PRIORITY) < 0) GIT_FILTER_IDENT, ident, GIT_FILTER_IDENT_PRIORITY) < 0)
error = -1; error = -1;
git__on_shutdown(git_filter_global_shutdown); error = git_runtime_shutdown_register(git_filter_global_shutdown);
done: done:
if (error) { if (error) {
......
...@@ -7,8 +7,9 @@ ...@@ -7,8 +7,9 @@
#include "futils.h" #include "futils.h"
#include "global.h" #include "runtime.h"
#include "strmap.h" #include "strmap.h"
#include "hash.h"
#include <ctype.h> #include <ctype.h>
#if GIT_WIN32 #if GIT_WIN32
#include "win32/findfile.h" #include "win32/findfile.h"
......
/*
* 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 */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include "win32.h" #include "win32.h"
#include "global.h" #include "runtime.h"
#include <wincrypt.h> #include <wincrypt.h>
#include <strsafe.h> #include <strsafe.h>
...@@ -129,7 +129,8 @@ int git_hash_sha1_global_init(void) ...@@ -129,7 +129,8 @@ int git_hash_sha1_global_init(void)
if ((error = hash_cng_prov_init()) < 0) if ((error = hash_cng_prov_init()) < 0)
error = hash_cryptoapi_prov_init(); error = hash_cryptoapi_prov_init();
git__on_shutdown(sha1_shutdown); if (!error)
error = git_runtime_shutdown_register(sha1_shutdown);
return error; return error;
} }
......
...@@ -5,7 +5,33 @@ ...@@ -5,7 +5,33 @@
* a Linking Exception. For full terms see the included COPYING file. * 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 "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 #ifdef GIT_OPENSSL
# include <openssl/err.h> # include <openssl/err.h>
...@@ -15,19 +41,53 @@ ...@@ -15,19 +41,53 @@
# include <mbedtls/error.h> # include <mbedtls/error.h>
#endif #endif
#include <git2.h> /* Declarations for tuneable settings */
#include "alloc.h" extern size_t git_mwindow__window_size;
#include "sysdir.h" extern size_t git_mwindow__mapped_limit;
#include "cache.h" extern size_t git_mwindow__file_limit;
#include "global.h" extern size_t git_indexer__max_objects;
#include "object.h" extern bool git_disable_pack_keep_file_checks;
#include "odb.h"
#include "refs.h" char *git__user_agent;
#include "index.h" char *git__ssl_ciphers;
#include "transports/smart.h"
#include "transports/http.h" static void libgit2_settings_global_shutdown(void)
#include "streams/openssl.h" {
#include "streams/mbedtls.h" 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) int git_libgit2_version(int *major, int *minor, int *rev)
{ {
...@@ -56,13 +116,6 @@ int git_libgit2_features(void) ...@@ -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) static int config_level_to_sysdir(int config_level)
{ {
int val = -1; int val = -1;
...@@ -88,9 +141,6 @@ static int config_level_to_sysdir(int config_level) ...@@ -88,9 +141,6 @@ static int config_level_to_sysdir(int config_level)
return val; return val;
} }
extern char *git__user_agent;
extern char *git__ssl_ciphers;
const char *git_libgit2__user_agent(void) const char *git_libgit2__user_agent(void)
{ {
return git__user_agent; return git__user_agent;
......
/*
* 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
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include "merge_driver.h" #include "merge_driver.h"
#include "vector.h" #include "vector.h"
#include "global.h" #include "runtime.h"
#include "merge.h" #include "merge.h"
#include "git2/merge.h" #include "git2/merge.h"
#include "git2/sys/merge.h" #include "git2/sys/merge.h"
...@@ -209,7 +209,7 @@ int git_merge_driver_global_init(void) ...@@ -209,7 +209,7 @@ int git_merge_driver_global_init(void)
merge_driver_name__binary, &git_merge_driver__binary)) < 0) merge_driver_name__binary, &git_merge_driver__binary)) < 0)
goto done; goto done;
git__on_shutdown(git_merge_driver_global_shutdown); error = git_runtime_shutdown_register(git_merge_driver_global_shutdown);
done: done:
if (error < 0) if (error < 0)
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include "vector.h" #include "vector.h"
#include "futils.h" #include "futils.h"
#include "map.h" #include "map.h"
#include "global.h" #include "runtime.h"
#include "strmap.h" #include "strmap.h"
#include "pack.h" #include "pack.h"
...@@ -29,26 +29,36 @@ size_t git_mwindow__window_size = DEFAULT_WINDOW_SIZE; ...@@ -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__mapped_limit = DEFAULT_MAPPED_LIMIT;
size_t git_mwindow__file_limit = DEFAULT_FILE_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 */ /* Whenever you want to read or modify this, grab git__mwindow_mutex */
git_mwindow_ctl git_mwindow__mem_ctl; git_mwindow_ctl git_mwindow__mem_ctl;
/* Global list of mwindow files, to open packs once across repos */ /* Global list of mwindow files, to open packs once across repos */
git_strmap *git__pack_cache = NULL; 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_strmap *tmp = git__pack_cache;
git_mutex_free(&git__mwindow_mutex);
git__pack_cache = NULL; git__pack_cache = NULL;
git_strmap_free(tmp); git_strmap_free(tmp);
} }
int git_mwindow_global_init(void) int git_mwindow_global_init(void)
{ {
int error;
assert(!git__pack_cache); assert(!git__pack_cache);
git__on_shutdown(git_mwindow_files_free); if ((error = git_mutex_init(&git__mwindow_mutex)) < 0 ||
return git_strmap_new(&git__pack_cache); (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) int git_mwindow_get_pack(struct git_pack_file **out, const char *path)
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include "map.h" #include "map.h"
#include "vector.h" #include "vector.h"
extern git_mutex git__mwindow_mutex;
typedef struct git_mwindow { typedef struct git_mwindow {
struct git_mwindow *next; struct git_mwindow *next;
git_map window_map; git_map window_map;
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "posix.h" #include "posix.h"
#include "buffer.h" #include "buffer.h"
#include "http_parser.h" #include "http_parser.h"
#include "global.h" #include "runtime.h"
#define DEFAULT_PORT_HTTP "80" #define DEFAULT_PORT_HTTP "80"
#define DEFAULT_PORT_HTTPS "443" #define DEFAULT_PORT_HTTPS "443"
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include "posix.h" #include "posix.h"
#include "buffer.h" #include "buffer.h"
#include "http_parser.h" #include "http_parser.h"
#include "global.h" #include "runtime.h"
int gitno_recv(gitno_buffer *buf) int gitno_recv(gitno_buffer *buf)
{ {
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include "git2/oid.h" #include "git2/oid.h"
#include "repository.h" #include "repository.h"
#include "global.h" #include "threadstate.h"
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
...@@ -107,7 +107,7 @@ int git_oid_pathfmt(char *str, const git_oid *oid) ...@@ -107,7 +107,7 @@ int git_oid_pathfmt(char *str, const git_oid *oid)
char *git_oid_tostr_s(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); git_oid_nfmt(str, GIT_OID_HEXSZ + 1, oid);
return str; return str;
} }
......
/*
* 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;
}
/*
* 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
/*
* 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);
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <ctype.h> #include <ctype.h>
#include "global.h" #include "runtime.h"
#include "stream.h" #include "stream.h"
#include "streams/socket.h" #include "streams/socket.h"
#include "netops.h" #include "netops.h"
...@@ -152,9 +152,7 @@ int git_mbedtls_stream_global_init(void) ...@@ -152,9 +152,7 @@ int git_mbedtls_stream_global_init(void)
if (!loaded && crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) if (!loaded && crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
loaded = (git_mbedtls__set_cert_location(crtpath, 1) == 0); loaded = (git_mbedtls__set_cert_location(crtpath, 1) == 0);
git__on_shutdown(shutdown_ssl); return git_runtime_shutdown_register(shutdown_ssl);
return 0;
cleanup: cleanup:
mbedtls_ctr_drbg_free(ctr_drbg); mbedtls_ctr_drbg_free(ctr_drbg);
......
...@@ -11,7 +11,8 @@ ...@@ -11,7 +11,8 @@
#include <ctype.h> #include <ctype.h>
#include "global.h" #include "runtime.h"
#include "settings.h"
#include "posix.h" #include "posix.h"
#include "stream.h" #include "stream.h"
#include "streams/socket.h" #include "streams/socket.h"
...@@ -285,9 +286,7 @@ int git_openssl_stream_global_init(void) ...@@ -285,9 +286,7 @@ int git_openssl_stream_global_init(void)
if (init_bio_method() < 0) if (init_bio_method() < 0)
goto error; goto error;
git__on_shutdown(shutdown_ssl); return git_runtime_shutdown_register(shutdown_ssl);
return 0;
error: error:
git_error_set(GIT_ERROR_NET, "could not initialize openssl: %s", git_error_set(GIT_ERROR_NET, "could not initialize openssl: %s",
...@@ -324,8 +323,8 @@ int git_openssl_set_locking(void) ...@@ -324,8 +323,8 @@ int git_openssl_set_locking(void)
} }
CRYPTO_set_locking_callback(openssl_locking_function); CRYPTO_set_locking_callback(openssl_locking_function);
git__on_shutdown(shutdown_ssl_locking); return git_runtime_shutdown_register(shutdown_ssl_locking);
return 0;
#elif !defined(OPENSSL_LEGACY_API) #elif !defined(OPENSSL_LEGACY_API)
return 0; return 0;
#else #else
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include "streams/registry.h" #include "streams/registry.h"
#include "global.h" #include "runtime.h"
#include "streams/tls.h" #include "streams/tls.h"
#include "streams/mbedtls.h" #include "streams/mbedtls.h"
#include "streams/openssl.h" #include "streams/openssl.h"
...@@ -33,8 +33,7 @@ int git_stream_registry_global_init(void) ...@@ -33,8 +33,7 @@ int git_stream_registry_global_init(void)
if (git_rwlock_init(&stream_registry.lock) < 0) if (git_rwlock_init(&stream_registry.lock) < 0)
return -1; return -1;
git__on_shutdown(shutdown_stream_registry); return git_runtime_shutdown_register(shutdown_stream_registry);
return 0;
} }
GIT_INLINE(void) stream_registration_cpy( GIT_INLINE(void) stream_registration_cpy(
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include "git2/errors.h" #include "git2/errors.h"
#include "common.h" #include "common.h"
#include "global.h"
#include "streams/registry.h" #include "streams/registry.h"
#include "streams/tls.h" #include "streams/tls.h"
#include "streams/mbedtls.h" #include "streams/mbedtls.h"
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include "sysdir.h" #include "sysdir.h"
#include "global.h" #include "runtime.h"
#include "buffer.h" #include "buffer.h"
#include "path.h" #include "path.h"
#include <ctype.h> #include <ctype.h>
...@@ -189,9 +189,7 @@ int git_sysdir_global_init(void) ...@@ -189,9 +189,7 @@ int git_sysdir_global_init(void)
for (i = 0; !error && i < ARRAY_SIZE(git_sysdir__dirs); i++) for (i = 0; !error && i < ARRAY_SIZE(git_sysdir__dirs); i++)
error = git_sysdir__dirs[i].guess(&git_sysdir__dirs[i].buf); error = git_sysdir__dirs[i].guess(&git_sysdir__dirs[i].buf);
git__on_shutdown(git_sysdir_global_shutdown); return git_runtime_shutdown_register(git_sysdir_global_shutdown);
return error;
} }
static int git_sysdir_check_selector(git_sysdir_t which) static int git_sysdir_check_selector(git_sysdir_t which)
......
...@@ -235,6 +235,8 @@ GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a) ...@@ -235,6 +235,8 @@ GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
#else #else
GIT_INLINE(int) git_threads_global_init(void) { return 0; }
#define git_thread unsigned int #define git_thread unsigned int
#define git_thread_create(thread, start_routine, arg) 0 #define git_thread_create(thread, start_routine, arg) 0
#define git_thread_join(id, status) (void)0 #define git_thread_join(id, status) (void)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 "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;
}
...@@ -4,38 +4,21 @@ ...@@ -4,38 +4,21 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with * This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file. * a Linking Exception. For full terms see the included COPYING file.
*/ */
#ifndef INCLUDE_global_h__ #ifndef INCLUDE_threadstate_h__
#define INCLUDE_global_h__ #define INCLUDE_threadstate_h__
#include "common.h" #include "common.h"
#include "mwindow.h"
#include "hash.h"
typedef struct { typedef struct {
git_error *last_error; git_error *last_error;
git_error error_t; git_error error_t;
git_buf error_buf; git_buf error_buf;
char oid_fmt[GIT_OID_HEXSZ+1]; char oid_fmt[GIT_OID_HEXSZ+1];
} git_threadstate;
/* On Windows, this is the current child thread that was started by extern int git_threadstate_global_init(void);
* `git_thread_create`. This is used to set the thread's exit code extern git_threadstate *git_threadstate_get(void);
* 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); #define GIT_THREADSTATE (git_threadstate_get())
extern const char *git_libgit2__ssl_ciphers(void);
#endif #endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include "trace.h" #include "trace.h"
#include "buffer.h" #include "buffer.h"
#include "global.h" #include "runtime.h"
#include "git2/trace.h" #include "git2/trace.h"
#ifdef GIT_TRACE #ifdef GIT_TRACE
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include "buffer.h" #include "buffer.h"
#include "net.h" #include "net.h"
#include "netops.h" #include "netops.h"
#include "global.h"
#include "remote.h" #include "remote.h"
#include "git2/sys/credential.h" #include "git2/sys/credential.h"
#include "smart.h" #include "smart.h"
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#define INCLUDE_transports_http_h__ #define INCLUDE_transports_http_h__
#include "buffer.h" #include "buffer.h"
#include "settings.h"
#include "httpclient.h" #include "httpclient.h"
#define GIT_HTTP_REPLAY_MAX 15 #define GIT_HTTP_REPLAY_MAX 15
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include "http_parser.h" #include "http_parser.h"
#include "vector.h" #include "vector.h"
#include "trace.h" #include "trace.h"
#include "global.h"
#include "httpclient.h" #include "httpclient.h"
#include "http.h" #include "http.h"
#include "auth.h" #include "auth.h"
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <libssh2.h> #include <libssh2.h>
#endif #endif
#include "global.h" #include "runtime.h"
#include "git2.h" #include "git2.h"
#include "buffer.h" #include "buffer.h"
#include "net.h" #include "net.h"
...@@ -934,8 +934,7 @@ int git_transport_ssh_global_init(void) ...@@ -934,8 +934,7 @@ int git_transport_ssh_global_init(void)
return -1; return -1;
} }
git__on_shutdown(shutdown_ssh); return git_runtime_shutdown_register(shutdown_ssh);
return 0;
#else #else
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include "smart.h" #include "smart.h"
#include "remote.h" #include "remote.h"
#include "repository.h" #include "repository.h"
#include "global.h"
#include "http.h" #include "http.h"
#include "git2/sys/credential.h" #include "git2/sys/credential.h"
......
...@@ -12,7 +12,8 @@ typedef struct { ...@@ -12,7 +12,8 @@ typedef struct {
pthread_t thread; pthread_t thread;
} git_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) \ #define git_thread_create(git_thread_ptr, start_routine, arg) \
pthread_create(&(git_thread_ptr)->thread, NULL, start_routine, arg) pthread_create(&(git_thread_ptr)->thread, NULL, start_routine, arg)
#define git_thread_join(git_thread_ptr, status) \ #define git_thread_join(git_thread_ptr, status) \
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include "utf-conv.h" #include "utf-conv.h"
#include "repository.h" #include "repository.h"
#include "reparse.h" #include "reparse.h"
#include "global.h"
#include "buffer.h" #include "buffer.h"
#include <errno.h> #include <errno.h>
#include <io.h> #include <io.h>
......
...@@ -6,8 +6,7 @@ ...@@ -6,8 +6,7 @@
*/ */
#include "thread.h" #include "thread.h"
#include "runtime.h"
#include "../global.h"
#define CLEAN_THREAD_EXIT 0x6F012842 #define CLEAN_THREAD_EXIT 0x6F012842
...@@ -19,6 +18,8 @@ static win32_srwlock_fn win32_srwlock_release_shared; ...@@ -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_acquire_exclusive;
static win32_srwlock_fn win32_srwlock_release_exclusive; static win32_srwlock_fn win32_srwlock_release_exclusive;
static DWORD fls_index;
/* The thread procedure stub used to invoke the caller's procedure /* The thread procedure stub used to invoke the caller's procedure
* and capture the return value for later collection. Windows will * and capture the return value for later collection. Windows will
* only hold a DWORD, but we need to be able to store an entire * 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) ...@@ -28,14 +29,19 @@ static DWORD WINAPI git_win32__threadproc(LPVOID lpParameter)
git_thread *thread = lpParameter; git_thread *thread = lpParameter;
/* Set the current thread for `git_thread_exit` */ /* Set the current thread for `git_thread_exit` */
GIT_GLOBAL->current_thread = thread; FlsSetValue(fls_index, thread);
thread->result = thread->proc(thread->param); thread->result = thread->proc(thread->param);
return CLEAN_THREAD_EXIT; 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"); HMODULE hModule = GetModuleHandleW(L"kernel32");
...@@ -52,7 +58,10 @@ int git_threads_init(void) ...@@ -52,7 +58,10 @@ int git_threads_init(void)
GetProcAddress(hModule, "ReleaseSRWLockExclusive"); 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( int git_thread_create(
...@@ -99,8 +108,11 @@ int git_thread_join( ...@@ -99,8 +108,11 @@ int git_thread_join(
void git_thread_exit(void *value) void git_thread_exit(void *value)
{ {
assert(GIT_GLOBAL->current_thread); git_thread *thread = FlsGetValue(fls_index);
GIT_GLOBAL->current_thread->result = value;
if (thread)
thread->result = value;
ExitThread(CLEAN_THREAD_EXIT); ExitThread(CLEAN_THREAD_EXIT);
} }
......
...@@ -35,7 +35,7 @@ typedef struct { ...@@ -35,7 +35,7 @@ typedef struct {
} native; } native;
} git_rwlock; } git_rwlock;
int git_threads_init(void); int git_threads_global_init(void);
int git_thread_create(git_thread *GIT_RESTRICT, int git_thread_create(git_thread *GIT_RESTRICT,
void *(*) (void *), void *(*) (void *),
......
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "global.h" #include "settings.h"
void test_core_useragent__get(void) void test_core_useragent__get(void)
{ {
......
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "mwindow.h" #include "mwindow.h"
#include "global.h"
#include <git2.h> #include <git2.h>
#include "git2/sys/commit.h" #include "git2/sys/commit.h"
......
...@@ -54,6 +54,12 @@ static void *return_normally(void *param) ...@@ -54,6 +54,12 @@ static void *return_normally(void *param)
{ {
return param; return param;
} }
static void *exit_abruptly(void *param)
{
git_thread_exit(param);
return NULL;
}
#endif #endif
void test_threads_basic__exit(void) void test_threads_basic__exit(void)
...@@ -70,7 +76,7 @@ void test_threads_basic__exit(void) ...@@ -70,7 +76,7 @@ void test_threads_basic__exit(void)
cl_assert_equal_sz(424242, (size_t)result); cl_assert_equal_sz(424242, (size_t)result);
/* Ensure that the return value of `git_thread_exit` is returned. */ /* 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_git_pass(git_thread_join(&thread, &result));
cl_assert_equal_sz(232323, (size_t)result); cl_assert_equal_sz(232323, (size_t)result);
#endif #endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment