1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
4  * This file is part of libgit2, distributed under the GNU GPL v2 with
5  * a Linking Exception. For full terms see the included COPYING file.
6  */
7 
8 #include "threadstate.h"
9 #include "runtime.h"
10 
11 /**
12  * Handle the thread-local state
13  *
14  * `git_threadstate_global_init` will be called as part
15  * of `git_libgit2_init` (which itself must be called
16  * before calling any other function in the library).
17  *
18  * This function allocates a TLS index to store the per-
19  * thread state.
20  *
21  * Any internal method that requires thread-local state
22  * will then call `git_threadstate_get()` which returns a
23  * pointer to the thread-local state structure; this
24  * structure is lazily allocated on each thread.
25  *
26  * This mechanism will register a shutdown handler
27  * (`git_threadstate_global_shutdown`) which will free the
28  * TLS index.  This shutdown handler will be called by
29  * `git_libgit2_shutdown`.
30  */
31 
32 static git_tlsdata_key tls_key;
33 
threadstate_dispose(git_threadstate * threadstate)34 static void threadstate_dispose(git_threadstate *threadstate)
35 {
36 	if (!threadstate)
37 		return;
38 
39 	git__free(threadstate->error_t.message);
40 	threadstate->error_t.message = NULL;
41 }
42 
threadstate_free(void * threadstate)43 static void GIT_SYSTEM_CALL threadstate_free(void *threadstate)
44 {
45 	threadstate_dispose(threadstate);
46 	git__free(threadstate);
47 }
48 
git_threadstate_global_shutdown(void)49 static void git_threadstate_global_shutdown(void)
50 {
51 	git_threadstate *threadstate;
52 
53 	threadstate = git_tlsdata_get(tls_key);
54 	git_tlsdata_set(tls_key, NULL);
55 
56 	threadstate_dispose(threadstate);
57 	git__free(threadstate);
58 
59 	git_tlsdata_dispose(tls_key);
60 }
61 
git_threadstate_global_init(void)62 int git_threadstate_global_init(void)
63 {
64 	if (git_tlsdata_init(&tls_key, &threadstate_free) != 0)
65 		return -1;
66 
67 	return git_runtime_shutdown_register(git_threadstate_global_shutdown);
68 }
69 
git_threadstate_get(void)70 git_threadstate *git_threadstate_get(void)
71 {
72 	git_threadstate *threadstate;
73 
74 	if ((threadstate = git_tlsdata_get(tls_key)) != NULL)
75 		return threadstate;
76 
77 	if ((threadstate = git__calloc(1, sizeof(git_threadstate))) == NULL ||
78 	    git_buf_init(&threadstate->error_buf, 0) < 0)
79 		return NULL;
80 
81 	git_tlsdata_set(tls_key, threadstate);
82 	return threadstate;
83 }
84