Line Flow Count Block(s) Source
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 "global.h"
9 -
10 - #include "alloc.h"
11 - #include "hash.h"
12 - #include "sysdir.h"
13 - #include "filter.h"
14 - #include "merge_driver.h"
15 - #include "streams/registry.h"
16 - #include "streams/mbedtls.h"
17 - #include "streams/openssl.h"
18 - #include "thread-utils.h"
19 - #include "git2/global.h"
20 - #include "transports/ssh.h"
21 -
22 - #if defined(GIT_MSVC_CRTDBG)
23 - #include "win32/w32_stack.h"
24 - #include "win32/w32_crtdbg_stacktrace.h"
25 - #endif
26 -
27 - git_mutex git__mwindow_mutex;
28 -
29 - typedef int (*git_global_init_fn)(void);
30 -
31 - static git_global_init_fn git__init_callbacks[] = {
32 - git_allocator_global_init,
33 - git_hash_global_init,
34 - git_sysdir_global_init,
35 - git_filter_global_init,
36 - git_merge_driver_global_init,
37 - git_transport_ssh_global_init,
38 - git_stream_registry_global_init,
39 - git_openssl_stream_global_init,
40 - git_mbedtls_stream_global_init,
41 - git_mwindow_global_init
42 - };
43 -
44 - static git_global_shutdown_fn git__shutdown_callbacks[ARRAY_SIZE(git__init_callbacks)];
45 -
46 - static git_atomic git__n_shutdown_callbacks;
47 - static git_atomic git__n_inits;
48 - char *git__user_agent;
49 - char *git__ssl_ciphers;
50 -
51 54 2 void git__on_shutdown(git_global_shutdown_fn callback)
52 - {
53 54 2 int count = git_atomic_inc(&git__n_shutdown_callbacks);
54 54 3-5 assert(count <= (int) ARRAY_SIZE(git__shutdown_callbacks) && count > 0);
55 54 6 git__shutdown_callbacks[count - 1] = callback;
56 54 6 }
57 -
58 8319 2 static void git__global_state_cleanup(git_global_st *st)
59 - {
60 8319 2 if (!st)
61 8334 3,6 return;
62 -
63 8319 4 git__free(st->error_t.message);
64 8334 5 st->error_t.message = NULL;
65 - }
66 -
67 9 2 static int init_common(void)
68 - {
69 - size_t i;
70 - int ret;
71 -
72 - /* Initialize the CRT debug allocator first, before our first malloc */
73 - #if defined(GIT_MSVC_CRTDBG)
74 - git_win32__crtdbg_stacktrace_init();
75 - git_win32__stack_init();
76 - #endif
77 -
78 - /* Initialize subsystems that have global state */
79 99 2,6,7 for (i = 0; i < ARRAY_SIZE(git__init_callbacks); i++)
80 90 3,4 if ((ret = git__init_callbacks[i]()) != 0)
81 ##### 5 break;
82 -
83 9 8 GIT_MEMORY_BARRIER;
84 -
85 9 8 return ret;
86 - }
87 -
88 9 2 static void shutdown_common(void)
89 - {
90 - int pos;
91 -
92 - /* Shutdown subsystems that have registered */
93 63 2,7 for (pos = git_atomic_get(&git__n_shutdown_callbacks);
94 - pos > 0;
95 54 6 pos = git_atomic_dec(&git__n_shutdown_callbacks)) {
96 -
97 54 3 git_global_shutdown_fn cb = git__swap(
98 - git__shutdown_callbacks[pos - 1], NULL);
99 -
100 54 4 if (cb != NULL)
101 54 5 cb();
102 - }
103 -
104 9 8 git__free(git__user_agent);
105 9 9 git__free(git__ssl_ciphers);
106 9 10 }
107 -
108 - /**
109 - * Handle the global state with TLS
110 - *
111 - * If libgit2 is built with GIT_THREADS enabled,
112 - * the `git_libgit2_init()` function must be called
113 - * before calling any other function of the library.
114 - *
115 - * This function allocates a TLS index (using pthreads
116 - * or the native Win32 API) to store the global state
117 - * on a per-thread basis.
118 - *
119 - * Any internal method that requires global state will
120 - * then call `git__global_state()` which returns a pointer
121 - * to the global state structure; this pointer is lazily
122 - * allocated on each thread.
123 - *
124 - * Before shutting down the library, the
125 - * `git_libgit2_shutdown` method must be called to free
126 - * the previously reserved TLS index.
127 - *
128 - * If libgit2 is built without threading support, the
129 - * `git__global_statestate()` call returns a pointer to a single,
130 - * statically allocated global state. The `git_thread_`
131 - * functions are not available in that case.
132 - */
133 -
134 - /*
135 - * `git_libgit2_init()` allows subsystems to perform global setup,
136 - * which may take place in the global scope. An explicit memory
137 - * fence exists at the exit of `git_libgit2_init()`. Without this,
138 - * CPU cores are free to reorder cache invalidation of `_tls_init`
139 - * before cache invalidation of the subsystems' newly written global
140 - * state.
141 - */
142 - #if defined(GIT_THREADS) && defined(GIT_WIN32)
143 -
144 - static DWORD _fls_index;
145 - static volatile LONG _mutex = 0;
146 -
147 - static void WINAPI fls_free(void *st)
148 - {
149 - git__global_state_cleanup(st);
150 - git__free(st);
151 - }
152 -
153 - static int synchronized_threads_init(void)
154 - {
155 - int error;
156 -
157 - if ((_fls_index = FlsAlloc(fls_free)) == FLS_OUT_OF_INDEXES)
158 - return -1;
159 -
160 - git_threads_init();
161 -
162 - if (git_mutex_init(&git__mwindow_mutex))
163 - return -1;
164 -
165 - error = init_common();
166 -
167 - return error;
168 - }
169 -
170 - int git_libgit2_init(void)
171 - {
172 - int ret;
173 -
174 - /* Enter the lock */
175 - while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); }
176 -
177 - /* Only do work on a 0 -> 1 transition of the refcount */
178 - if ((ret = git_atomic_inc(&git__n_inits)) == 1) {
179 - if (synchronized_threads_init() < 0)
180 - ret = -1;
181 - }
182 -
183 - /* Exit the lock */
184 - InterlockedExchange(&_mutex, 0);
185 -
186 - return ret;
187 - }
188 -
189 - int git_libgit2_shutdown(void)
190 - {
191 - int ret;
192 -
193 - /* Enter the lock */
194 - while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); }
195 -
196 - /* Only do work on a 1 -> 0 transition of the refcount */
197 - if ((ret = git_atomic_dec(&git__n_inits)) == 0) {
198 - shutdown_common();
199 -
200 - FlsFree(_fls_index);
201 - git_mutex_free(&git__mwindow_mutex);
202 -
203 - #if defined(GIT_MSVC_CRTDBG)
204 - git_win32__crtdbg_stacktrace_cleanup();
205 - git_win32__stack_cleanup();
206 - #endif
207 - }
208 -
209 - /* Exit the lock */
210 - InterlockedExchange(&_mutex, 0);
211 -
212 - return ret;
213 - }
214 -
215 - git_global_st *git__global_state(void)
216 - {
217 - git_global_st *ptr;
218 -
219 - assert(git_atomic_get(&git__n_inits) > 0);
220 -
221 - if ((ptr = FlsGetValue(_fls_index)) != NULL)
222 - return ptr;
223 -
224 - ptr = git__calloc(1, sizeof(git_global_st));
225 - if (!ptr)
226 - return NULL;
227 -
228 - git_buf_init(&ptr->error_buf, 0);
229 -
230 - FlsSetValue(_fls_index, ptr);
231 - return ptr;
232 - }
233 -
234 - #elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
235 -
236 - static pthread_key_t _tls_key;
237 - static pthread_mutex_t _init_mutex = PTHREAD_MUTEX_INITIALIZER;
238 - static pthread_once_t _once_init = PTHREAD_ONCE_INIT;
239 - int init_error = 0;
240 -
241 8312 2 static void cb__free_status(void *st)
242 - {
243 8312 2 git__global_state_cleanup(st);
244 8326 3 git__free(st);
245 8327 4 }
246 -
247 9 2 static void init_once(void)
248 - {
249 9 2,3 if ((init_error = git_mutex_init(&git__mwindow_mutex)) != 0)
250 9 4,8 return;
251 -
252 9 5 pthread_key_create(&_tls_key, &cb__free_status);
253 -
254 9 6 init_error = init_common();
255 - }
256 -
257 212 2 int git_libgit2_init(void)
258 - {
259 - int ret, err;
260 -
261 213 2,3 if ((err = pthread_mutex_lock(&_init_mutex)) != 0)
262 ##### 4 return err;
263 -
264 213 5 ret = git_atomic_inc(&git__n_inits);
265 213 6 err = pthread_once(&_once_init, init_once);
266 213 7 err |= pthread_mutex_unlock(&_init_mutex);
267 -
268 213 8,9 if (err || init_error)
269 ##### 10 return err | init_error;
270 -
271 213 11 return ret;
272 - }
273 -
274 213 2 int git_libgit2_shutdown(void)
275 - {
276 213 2 void *ptr = NULL;
277 213 2 pthread_once_t new_once = PTHREAD_ONCE_INIT;
278 - int error, ret;
279 -
280 213 2,3 if ((error = pthread_mutex_lock(&_init_mutex)) != 0)
281 ##### 4 return error;
282 -
283 213 5,6 if ((ret = git_atomic_dec(&git__n_inits)) != 0)
284 204 7 goto out;
285 -
286 - /* Shut down any subsystems that have global state */
287 9 8 shutdown_common();
288 -
289 9 9 ptr = pthread_getspecific(_tls_key);
290 9 10 pthread_setspecific(_tls_key, NULL);
291 -
292 9 11 git__global_state_cleanup(ptr);
293 9 12 git__free(ptr);
294 -
295 9 13 pthread_key_delete(_tls_key);
296 9 14 git_mutex_free(&git__mwindow_mutex);
297 9 15 _once_init = new_once;
298 -
299 - out:
300 213 16,17 if ((error = pthread_mutex_unlock(&_init_mutex)) != 0)
301 ##### 18 return error;
302 -
303 213 19 return ret;
304 - }
305 -
306 3111349 2 git_global_st *git__global_state(void)
307 - {
308 - git_global_st *ptr;
309 -
310 3111349 2-4 assert(git_atomic_get(&git__n_inits) > 0);
311 -
312 3110187 5,6 if ((ptr = pthread_getspecific(_tls_key)) != NULL)
313 3101847 7 return ptr;
314 -
315 8340 8 ptr = git__calloc(1, sizeof(git_global_st));
316 8331 9 if (!ptr)
317 ##### 10 return NULL;
318 -
319 8331 11 git_buf_init(&ptr->error_buf, 0);
320 8348 12 pthread_setspecific(_tls_key, ptr);
321 8345 13 return ptr;
322 - }
323 -
324 - #else
325 -
326 - static git_global_st __state;
327 -
328 - int git_libgit2_init(void)
329 - {
330 - int ret;
331 -
332 - /* Only init subsystems the first time */
333 - if ((ret = git_atomic_inc(&git__n_inits)) != 1)
334 - return ret;
335 -
336 - if ((ret = init_common()) < 0)
337 - return ret;
338 -
339 - return 1;
340 - }
341 -
342 - int git_libgit2_shutdown(void)
343 - {
344 - int ret;
345 -
346 - /* Shut down any subsystems that have global state */
347 - if ((ret = git_atomic_dec(&git__n_inits)) == 0) {
348 - shutdown_common();
349 - git__global_state_cleanup(&__state);
350 - memset(&__state, 0, sizeof(__state));
351 - }
352 -
353 - return ret;
354 - }
355 -
356 - git_global_st *git__global_state(void)
357 - {
358 - return &__state;
359 - }
360 -
361 - #endif /* GIT_THREADS */