summaryrefslogtreecommitdiff
path: root/src/libgit2/threadstate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libgit2/threadstate.c')
-rw-r--r--src/libgit2/threadstate.c84
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;
+}