diff options
Diffstat (limited to 'src/libgit2/threadstate.c')
-rw-r--r-- | src/libgit2/threadstate.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/src/libgit2/threadstate.c b/src/libgit2/threadstate.c new file mode 100644 index 000000000..9e3ef5818 --- /dev/null +++ b/src/libgit2/threadstate.c @@ -0,0 +1,84 @@ +/* + * 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" + +/** + * 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 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`. + */ + +static git_tlsdata_key tls_key; + +static void threadstate_dispose(git_threadstate *threadstate) +{ + if (!threadstate) + return; + + if (threadstate->error_t.message != git_str__initstr) + git__free(threadstate->error_t.message); + threadstate->error_t.message = NULL; +} + +static void GIT_SYSTEM_CALL threadstate_free(void *threadstate) +{ + threadstate_dispose(threadstate); + git__free(threadstate); +} + +static void git_threadstate_global_shutdown(void) +{ + git_threadstate *threadstate; + + threadstate = git_tlsdata_get(tls_key); + git_tlsdata_set(tls_key, NULL); + + threadstate_dispose(threadstate); + git__free(threadstate); + + git_tlsdata_dispose(tls_key); +} + +int git_threadstate_global_init(void) +{ + if (git_tlsdata_init(&tls_key, &threadstate_free) != 0) + return -1; + + return git_runtime_shutdown_register(git_threadstate_global_shutdown); +} + +git_threadstate *git_threadstate_get(void) +{ + git_threadstate *threadstate; + + if ((threadstate = git_tlsdata_get(tls_key)) != NULL) + return threadstate; + + if ((threadstate = git__calloc(1, sizeof(git_threadstate))) == NULL || + git_str_init(&threadstate->error_buf, 0) < 0) + return NULL; + + git_tlsdata_set(tls_key, threadstate); + return threadstate; +} |