2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
12 #include "merge_driver.h"
13 #include "openssl_stream.h"
14 #include "thread-utils.h"
15 #include "git2/global.h"
16 #include "transports/ssh.h"
18 #if defined(GIT_MSVC_CRTDBG)
19 #include "win32/w32_stack.h"
20 #include "win32/w32_crtdbg_stacktrace.h"
23 git_mutex git__mwindow_mutex
;
25 #define MAX_SHUTDOWN_CB 8
27 static git_global_shutdown_fn git__shutdown_callbacks
[MAX_SHUTDOWN_CB
];
28 static git_atomic git__n_shutdown_callbacks
;
29 static git_atomic git__n_inits
;
30 char *git__user_agent
;
31 char *git__ssl_ciphers
;
33 void git__on_shutdown(git_global_shutdown_fn callback
)
35 int count
= git_atomic_inc(&git__n_shutdown_callbacks
);
36 assert(count
<= MAX_SHUTDOWN_CB
&& count
> 0);
37 git__shutdown_callbacks
[count
- 1] = callback
;
40 static void git__global_state_cleanup(git_global_st
*st
)
45 git__free(st
->error_t
.message
);
46 st
->error_t
.message
= NULL
;
49 static int init_common(void)
53 /* Initialize the CRT debug allocator first, before our first malloc */
54 #if defined(GIT_MSVC_CRTDBG)
55 git_win32__crtdbg_stacktrace_init();
56 git_win32__stack_init();
59 /* Initialize any other subsystems that have global state */
60 if ((ret
= git_hash_global_init()) == 0 &&
61 (ret
= git_sysdir_global_init()) == 0 &&
62 (ret
= git_filter_global_init()) == 0 &&
63 (ret
= git_merge_driver_global_init()) == 0 &&
64 (ret
= git_transport_ssh_global_init()) == 0)
65 ret
= git_openssl_stream_global_init();
72 static void shutdown_common(void)
76 /* Shutdown subsystems that have registered */
77 for (pos
= git_atomic_get(&git__n_shutdown_callbacks
);
79 pos
= git_atomic_dec(&git__n_shutdown_callbacks
)) {
81 git_global_shutdown_fn cb
= git__swap(
82 git__shutdown_callbacks
[pos
- 1], NULL
);
88 git__free(git__user_agent
);
89 git__free(git__ssl_ciphers
);
91 #if defined(GIT_MSVC_CRTDBG)
92 git_win32__crtdbg_stacktrace_cleanup();
93 git_win32__stack_cleanup();
98 * Handle the global state with TLS
100 * If libgit2 is built with GIT_THREADS enabled,
101 * the `git_libgit2_init()` function must be called
102 * before calling any other function of the library.
104 * This function allocates a TLS index (using pthreads
105 * or the native Win32 API) to store the global state
106 * on a per-thread basis.
108 * Any internal method that requires global state will
109 * then call `git__global_state()` which returns a pointer
110 * to the global state structure; this pointer is lazily
111 * allocated on each thread.
113 * Before shutting down the library, the
114 * `git_libgit2_shutdown` method must be called to free
115 * the previously reserved TLS index.
117 * If libgit2 is built without threading support, the
118 * `git__global_statestate()` call returns a pointer to a single,
119 * statically allocated global state. The `git_thread_`
120 * functions are not available in that case.
124 * `git_libgit2_init()` allows subsystems to perform global setup,
125 * which may take place in the global scope. An explicit memory
126 * fence exists at the exit of `git_libgit2_init()`. Without this,
127 * CPU cores are free to reorder cache invalidation of `_tls_init`
128 * before cache invalidation of the subsystems' newly written global
131 #if defined(GIT_THREADS) && defined(GIT_WIN32)
133 static DWORD _tls_index
;
134 static volatile LONG _mutex
= 0;
136 static int synchronized_threads_init(void)
140 _tls_index
= TlsAlloc();
142 win32_pthread_initialize();
144 if (git_mutex_init(&git__mwindow_mutex
))
147 error
= init_common();
152 int git_libgit2_init(void)
157 while (InterlockedCompareExchange(&_mutex
, 1, 0)) { Sleep(0); }
159 /* Only do work on a 0 -> 1 transition of the refcount */
160 if ((ret
= git_atomic_inc(&git__n_inits
)) == 1) {
161 if (synchronized_threads_init() < 0)
166 InterlockedExchange(&_mutex
, 0);
171 int git_libgit2_shutdown(void)
176 while (InterlockedCompareExchange(&_mutex
, 1, 0)) { Sleep(0); }
178 /* Only do work on a 1 -> 0 transition of the refcount */
179 if ((ret
= git_atomic_dec(&git__n_inits
)) == 0) {
182 git__free_tls_data();
185 git_mutex_free(&git__mwindow_mutex
);
189 InterlockedExchange(&_mutex
, 0);
194 git_global_st
*git__global_state(void)
198 assert(git_atomic_get(&git__n_inits
) > 0);
200 if ((ptr
= TlsGetValue(_tls_index
)) != NULL
)
203 ptr
= git__calloc(1, sizeof(git_global_st
));
207 git_buf_init(&ptr
->error_buf
, 0);
209 TlsSetValue(_tls_index
, ptr
);
214 * Free the TLS data associated with this thread.
215 * This should only be used by the thread as it
218 void git__free_tls_data(void)
220 void *ptr
= TlsGetValue(_tls_index
);
224 git__global_state_cleanup(ptr
);
226 TlsSetValue(_tls_index
, NULL
);
229 BOOL WINAPI
DllMain(HINSTANCE hInstDll
, DWORD fdwReason
, LPVOID lpvReserved
)
231 GIT_UNUSED(hInstDll
);
232 GIT_UNUSED(lpvReserved
);
234 /* This is how Windows lets us know our thread is being shut down */
235 if (fdwReason
== DLL_THREAD_DETACH
) {
236 git__free_tls_data();
240 * Windows pays attention to this during library loading. We don't do anything
241 * so we trivially succeed.
246 #elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
248 static pthread_key_t _tls_key
;
249 static pthread_once_t _once_init
= PTHREAD_ONCE_INIT
;
252 static void cb__free_status(void *st
)
254 git__global_state_cleanup(st
);
258 static void init_once(void)
260 if ((init_error
= git_mutex_init(&git__mwindow_mutex
)) != 0)
263 pthread_key_create(&_tls_key
, &cb__free_status
);
265 init_error
= init_common();
268 int git_libgit2_init(void)
272 ret
= git_atomic_inc(&git__n_inits
);
273 pthread_once(&_once_init
, init_once
);
275 return init_error
? init_error
: ret
;
278 int git_libgit2_shutdown(void)
281 pthread_once_t new_once
= PTHREAD_ONCE_INIT
;
284 if ((ret
= git_atomic_dec(&git__n_inits
)) != 0)
287 /* Shut down any subsystems that have global state */
290 ptr
= pthread_getspecific(_tls_key
);
291 pthread_setspecific(_tls_key
, NULL
);
293 git__global_state_cleanup(ptr
);
296 pthread_key_delete(_tls_key
);
297 git_mutex_free(&git__mwindow_mutex
);
298 _once_init
= new_once
;
303 git_global_st
*git__global_state(void)
307 assert(git_atomic_get(&git__n_inits
) > 0);
309 if ((ptr
= pthread_getspecific(_tls_key
)) != NULL
)
312 ptr
= git__calloc(1, sizeof(git_global_st
));
316 git_buf_init(&ptr
->error_buf
, 0);
317 pthread_setspecific(_tls_key
, ptr
);
323 static git_global_st __state
;
325 int git_libgit2_init(void)
329 /* Only init SSL the first time */
330 if ((ret
= git_atomic_inc(&git__n_inits
)) != 1)
333 if ((ret
= init_common()) < 0)
339 int git_libgit2_shutdown(void)
343 /* Shut down any subsystems that have global state */
344 if ((ret
= git_atomic_dec(&git__n_inits
)) == 0) {
346 git__global_state_cleanup(&__state
);
352 git_global_st
*git__global_state(void)
357 #endif /* GIT_THREADS */