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.
11 #include "git2/global.h"
12 #include "git2/sys/openssl.h"
13 #include "thread-utils.h"
16 git_mutex git__mwindow_mutex
;
18 #define MAX_SHUTDOWN_CB 8
21 # include <openssl/ssl.h>
22 SSL_CTX
*git__ssl_ctx
;
24 static git_mutex
*openssl_locks
;
28 static git_global_shutdown_fn git__shutdown_callbacks
[MAX_SHUTDOWN_CB
];
29 static git_atomic git__n_shutdown_callbacks
;
30 static git_atomic git__n_inits
;
32 void git__on_shutdown(git_global_shutdown_fn callback
)
34 int count
= git_atomic_inc(&git__n_shutdown_callbacks
);
35 assert(count
<= MAX_SHUTDOWN_CB
&& count
> 0);
36 git__shutdown_callbacks
[count
- 1] = callback
;
39 static void git__global_state_cleanup(git_global_st
*st
)
44 git__free(st
->error_t
.message
);
45 st
->error_t
.message
= NULL
;
48 static void git__shutdown(void)
52 /* Shutdown subsystems that have registered */
53 for (pos
= git_atomic_get(&git__n_shutdown_callbacks
); pos
> 0; pos
= git_atomic_dec(&git__n_shutdown_callbacks
)) {
54 git_global_shutdown_fn cb
= git__swap(git__shutdown_callbacks
[pos
- 1], NULL
);
60 #if defined(GIT_THREADS) && defined(GIT_SSL)
61 void openssl_locking_function(int mode
, int n
, const char *file
, int line
)
68 lock
= mode
& CRYPTO_LOCK
;
71 git_mutex_lock(&openssl_locks
[n
]);
73 git_mutex_unlock(&openssl_locks
[n
]);
77 static void shutdown_ssl_locking(void)
81 num_locks
= CRYPTO_num_locks();
82 CRYPTO_set_locking_callback(NULL
);
84 for (i
= 0; i
< num_locks
; ++i
)
85 git_mutex_free(openssl_locks
);
86 git__free(openssl_locks
);
90 static void init_ssl(void)
93 long ssl_opts
= SSL_OP_NO_SSLv2
| SSL_OP_NO_SSLv3
;
95 /* Older OpenSSL and MacOS OpenSSL doesn't have this */
96 #ifdef SSL_OP_NO_COMPRESSION
97 ssl_opts
|= SSL_OP_NO_COMPRESSION
;
100 SSL_load_error_strings();
101 OpenSSL_add_ssl_algorithms();
103 * Load SSLv{2,3} and TLSv1 so that we can talk with servers
104 * which use the SSL hellos, which are often used for
105 * compatibility. We then disable SSL so we only allow OpenSSL
106 * to speak TLSv1 to perform the encryption itself.
108 git__ssl_ctx
= SSL_CTX_new(SSLv23_method());
109 SSL_CTX_set_options(git__ssl_ctx
, ssl_opts
);
110 SSL_CTX_set_mode(git__ssl_ctx
, SSL_MODE_AUTO_RETRY
);
111 SSL_CTX_set_verify(git__ssl_ctx
, SSL_VERIFY_NONE
, NULL
);
112 if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx
)) {
113 SSL_CTX_free(git__ssl_ctx
);
119 int git_openssl_set_locking(void)
125 num_locks
= CRYPTO_num_locks();
126 openssl_locks
= git__calloc(num_locks
, sizeof(git_mutex
));
127 GITERR_CHECK_ALLOC(openssl_locks
);
129 for (i
= 0; i
< num_locks
; i
++) {
130 if (git_mutex_init(&openssl_locks
[i
]) != 0) {
131 giterr_set(GITERR_SSL
, "failed to initialize openssl locks");
136 CRYPTO_set_locking_callback(openssl_locking_function
);
137 git__on_shutdown(shutdown_ssl_locking
);
140 giterr_set(GITERR_THREAD
, "libgit2 as not built with threads");
144 giterr_set(GITERR_SSL
, "libgit2 was not built with OpenSSL support");
150 * Handle the global state with TLS
152 * If libgit2 is built with GIT_THREADS enabled,
153 * the `git_libgit2_init()` function must be called
154 * before calling any other function of the library.
156 * This function allocates a TLS index (using pthreads
157 * or the native Win32 API) to store the global state
158 * on a per-thread basis.
160 * Any internal method that requires global state will
161 * then call `git__global_state()` which returns a pointer
162 * to the global state structure; this pointer is lazily
163 * allocated on each thread.
165 * Before shutting down the library, the
166 * `git_libgit2_shutdown` method must be called to free
167 * the previously reserved TLS index.
169 * If libgit2 is built without threading support, the
170 * `git__global_statestate()` call returns a pointer to a single,
171 * statically allocated global state. The `git_thread_`
172 * functions are not available in that case.
176 * `git_libgit2_init()` allows subsystems to perform global setup,
177 * which may take place in the global scope. An explicit memory
178 * fence exists at the exit of `git_libgit2_init()`. Without this,
179 * CPU cores are free to reorder cache invalidation of `_tls_init`
180 * before cache invalidation of the subsystems' newly written global
183 #if defined(GIT_THREADS) && defined(GIT_WIN32)
185 static DWORD _tls_index
;
186 static volatile LONG _mutex
= 0;
188 static int synchronized_threads_init(void)
192 _tls_index
= TlsAlloc();
193 if (git_mutex_init(&git__mwindow_mutex
))
196 /* Initialize any other subsystems that have global state */
197 if ((error
= git_hash_global_init()) >= 0)
198 error
= git_sysdir_global_init();
200 win32_pthread_initialize();
205 int git_libgit2_init(void)
210 while (InterlockedCompareExchange(&_mutex
, 1, 0)) { Sleep(0); }
212 /* Only do work on a 0 -> 1 transition of the refcount */
213 if ((ret
= git_atomic_inc(&git__n_inits
)) == 1) {
214 if (synchronized_threads_init() < 0)
219 InterlockedExchange(&_mutex
, 0);
224 static void synchronized_threads_shutdown(void)
226 /* Shut down any subsystems that have global state */
229 git__free_tls_data();
232 git_mutex_free(&git__mwindow_mutex
);
235 int git_libgit2_shutdown(void)
240 while (InterlockedCompareExchange(&_mutex
, 1, 0)) { Sleep(0); }
242 /* Only do work on a 1 -> 0 transition of the refcount */
243 if ((ret
= git_atomic_dec(&git__n_inits
)) == 0)
244 synchronized_threads_shutdown();
247 InterlockedExchange(&_mutex
, 0);
252 git_global_st
*git__global_state(void)
256 assert(git_atomic_get(&git__n_inits
) > 0);
258 if ((ptr
= TlsGetValue(_tls_index
)) != NULL
)
261 ptr
= git__malloc(sizeof(git_global_st
));
265 memset(ptr
, 0x0, sizeof(git_global_st
));
266 TlsSetValue(_tls_index
, ptr
);
271 * Free the TLS data associated with this thread.
272 * This should only be used by the thread as it
275 void git__free_tls_data(void)
277 void *ptr
= TlsGetValue(_tls_index
);
281 git__global_state_cleanup(ptr
);
283 TlsSetValue(_tls_index
, NULL
);
286 #elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
288 static pthread_key_t _tls_key
;
289 static pthread_once_t _once_init
= PTHREAD_ONCE_INIT
;
292 static void cb__free_status(void *st
)
294 git__global_state_cleanup(st
);
298 static void init_once(void)
300 if ((init_error
= git_mutex_init(&git__mwindow_mutex
)) != 0)
302 pthread_key_create(&_tls_key
, &cb__free_status
);
305 /* Initialize any other subsystems that have global state */
306 if ((init_error
= git_hash_global_init()) >= 0)
307 init_error
= git_sysdir_global_init();
309 /* OpenSSL needs to be initialized from the main thread */
315 int git_libgit2_init(void)
319 pthread_once(&_once_init
, init_once
);
320 ret
= git_atomic_inc(&git__n_inits
);
322 return init_error
? init_error
: ret
;
325 int git_libgit2_shutdown(void)
328 pthread_once_t new_once
= PTHREAD_ONCE_INIT
;
331 if ((ret
= git_atomic_dec(&git__n_inits
)) != 0)
334 /* Shut down any subsystems that have global state */
337 ptr
= pthread_getspecific(_tls_key
);
338 pthread_setspecific(_tls_key
, NULL
);
340 git__global_state_cleanup(ptr
);
343 pthread_key_delete(_tls_key
);
344 git_mutex_free(&git__mwindow_mutex
);
345 _once_init
= new_once
;
350 git_global_st
*git__global_state(void)
354 assert(git_atomic_get(&git__n_inits
) > 0);
356 if ((ptr
= pthread_getspecific(_tls_key
)) != NULL
)
359 ptr
= git__malloc(sizeof(git_global_st
));
363 memset(ptr
, 0x0, sizeof(git_global_st
));
364 pthread_setspecific(_tls_key
, ptr
);
370 static git_global_st __state
;
372 int git_libgit2_init(void)
374 static int ssl_inited
= 0;
381 return git_atomic_inc(&git__n_inits
);
384 int git_libgit2_shutdown(void)
388 /* Shut down any subsystems that have global state */
389 if ((ret
= git_atomic_dec(&git__n_inits
)) != 0)
393 git__global_state_cleanup(&__state
);
398 git_global_st
*git__global_state(void)
403 #endif /* GIT_THREADS */