Commit e316b0d3 by Edward Thomson

runtime: move init/shutdown into the "runtime"

Provide a mechanism for system components to register for initialization
and shutdown of the libgit2 runtime.
parent 8970acb7
......@@ -6,6 +6,7 @@
*/
#include "alloc.h"
#include "runtime.h"
#include "allocators/stdalloc.h"
#include "allocators/win32_crtdbg.h"
......@@ -40,7 +41,8 @@ int git_allocator_global_init(void)
git_win32__crtdbg_stacktrace_init();
git_win32__stack_init();
git__on_shutdown(allocator_global_shutdown);
if (git_runtime_shutdown_register(allocator_global_shutdown) < 0)
return -1;
#endif
/*
......
......@@ -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) {
......
......@@ -7,7 +7,7 @@
#include "futils.h"
#include "global.h"
#include "runtime.h"
#include "strmap.h"
#include "hash.h"
#include <ctype.h>
......
......@@ -5,7 +5,7 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "global.h"
#include "runtime.h"
#include "alloc.h"
#include "threadstate.h"
......@@ -24,159 +24,29 @@
#include "transports/ssh.h"
#include "win32/w32_stack.h"
typedef int (*git_global_init_fn)(void);
static git_global_init_fn git__init_callbacks[] = {
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_settings_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;
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 int init_common(void)
{
size_t i;
int ret;
/* 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_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)
/*
* 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 mutex = PTHREAD_MUTEX_INITIALIZER;
GIT_INLINE(int) init_lock(void)
{
return pthread_mutex_lock(&mutex) == 0 ? 0 : -1;
}
GIT_INLINE(int) init_unlock(void)
{
return pthread_mutex_unlock(&mutex) == 0 ? 0 : -1;
}
#elif defined(GIT_THREADS)
# error unknown threading model
#else
# define init_lock() 0
# define init_unlock() 0
#endif
int git_libgit2_init(void)
{
int ret;
if (init_lock() < 0)
return -1;
/* Only do work on a 0 -> 1 transition of the refcount */
if ((ret = git_atomic_inc(&git__n_inits)) == 1) {
if (init_common() < 0)
ret = -1;
}
if (init_unlock() < 0)
return -1;
return ret;
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_settings_global_init
};
return git_runtime_init(init_fns, ARRAY_SIZE(init_fns));
}
int git_libgit2_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(&git__n_inits)) == 0)
shutdown_common();
/* Exit the lock */
if (init_unlock() < 0)
return -1;
return ret;
return git_runtime_shutdown();
}
/*
* 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"
typedef void (*git_global_shutdown_fn)(void);
extern void git__on_shutdown(git_global_shutdown_fn callback);
#endif
......@@ -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;
}
......
......@@ -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)
......
......@@ -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"
......@@ -50,14 +50,15 @@ static void git_mwindow_global_shutdown(void)
int git_mwindow_global_init(void)
{
assert(!git__pack_cache);
int error;
git__on_shutdown(git_mwindow_global_shutdown);
assert(!git__pack_cache);
if (git_mutex_init(&git__mwindow_mutex) != 0)
return -1;
if ((error = git_mutex_init(&git__mwindow_mutex)) < 0 ||
(error = git_strmap_new(&git__pack_cache)) < 0)
return error;
return git_strmap_new(&git__pack_cache);
return git_runtime_shutdown_register(git_mwindow_global_shutdown);
}
int git_mwindow_get_pack(struct git_pack_file **out, const char *path)
......
......@@ -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"
......
......@@ -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)
{
......
/*
* 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
......@@ -19,7 +19,7 @@
#include "alloc.h"
#include "sysdir.h"
#include "cache.h"
#include "global.h"
#include "runtime.h"
#include "object.h"
#include "odb.h"
#include "refs.h"
......@@ -47,8 +47,7 @@ static void git_settings_global_shutdown(void)
int git_settings_global_init(void)
{
git__on_shutdown(git_settings_global_shutdown);
return 0;
return git_runtime_shutdown_register(git_settings_global_shutdown);
}
int git_libgit2_version(int *major, int *minor, int *rev)
......
......@@ -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);
......
......@@ -11,7 +11,7 @@
#include <ctype.h>
#include "global.h"
#include "runtime.h"
#include "settings.h"
#include "posix.h"
#include "stream.h"
......@@ -286,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",
......@@ -325,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
......
......@@ -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(
......
......@@ -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"
......
......@@ -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)
......
......@@ -6,7 +6,7 @@
*/
#include "threadstate.h"
#include "global.h"
#include "runtime.h"
static void threadstate_dispose(git_threadstate *threadstate);
......@@ -57,9 +57,7 @@ int git_threadstate_global_init(void)
if ((fls_index = FlsAlloc(fls_free)) == FLS_OUT_OF_INDEXES)
return -1;
git__on_shutdown(git_threadstate_global_shutdown);
return 0;
return git_runtime_shutdown_register(git_threadstate_global_shutdown);
}
git_threadstate *git_threadstate_get(void)
......@@ -105,9 +103,7 @@ int git_threadstate_global_init(void)
if (pthread_key_create(&tls_key, &tls_free) != 0)
return -1;
git__on_shutdown(git_threadstate_global_shutdown);
return 0;
return git_runtime_shutdown_register(git_threadstate_global_shutdown);
}
git_threadstate *git_threadstate_get(void)
......@@ -134,14 +130,12 @@ static git_threadstate threadstate;
static void git_threadstate_global_shutdown(void)
{
threadstate_dispose(&threadstate);
memset(&threadstate, 0, sizeof(git_threadstate);
memset(&threadstate, 0, sizeof(git_threadstate));
}
int git_threadstate_global_init(void)
{
git__on_shutdown(git_threadstate_global_shutdown);
return 0;
return git_runtime_shutdown_register(git_tlsdata_global_shutdown);
}
git_threadstate *git_threadstate_get(void)
......
......@@ -8,7 +8,7 @@
#include "trace.h"
#include "buffer.h"
#include "global.h"
#include "runtime.h"
#include "git2/trace.h"
#ifdef GIT_TRACE
......
......@@ -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"
......
......@@ -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"
......
......@@ -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
......
......@@ -17,7 +17,6 @@
#include "smart.h"
#include "remote.h"
#include "repository.h"
#include "global.h"
#include "http.h"
#include "git2/sys/credential.h"
......
......@@ -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>
......
......@@ -6,6 +6,7 @@
*/
#include "thread.h"
#include "runtime.h"
#define CLEAN_THREAD_EXIT 0x6F012842
......@@ -60,9 +61,7 @@ int git_threads_global_init(void)
if ((fls_index = FlsAlloc(NULL)) == FLS_OUT_OF_INDEXES)
return -1;
git__on_shutdown(git_threads_global_shutdown);
return 0;
return git_runtime_shutdown_register(git_threads_global_shutdown);
}
int git_thread_create(
......
#include "clar_libgit2.h"
#include "mwindow.h"
#include "global.h"
#include <git2.h>
#include "git2/sys/commit.h"
......
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