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/threads.h"
12 #include "git2/global.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__shutdown(void)
43 for (pos
= git_atomic_get(&git__n_shutdown_callbacks
); pos
> 0; pos
= git_atomic_dec(&git__n_shutdown_callbacks
)) {
44 git_global_shutdown_fn cb
= git__swap(git__shutdown_callbacks
[pos
- 1], NULL
);
51 #if defined(GIT_THREADS) && defined(GIT_SSL)
52 void openssl_locking_function(int mode
, int n
, const char *file
, int line
)
59 lock
= mode
& CRYPTO_LOCK
;
62 git_mutex_lock(&openssl_locks
[n
]);
64 git_mutex_unlock(&openssl_locks
[n
]);
68 static void shutdown_ssl_locking(void)
72 num_locks
= CRYPTO_num_locks();
73 CRYPTO_set_locking_callback(NULL
);
75 for (i
= 0; i
< num_locks
; ++i
)
76 git_mutex_free(openssl_locks
);
77 git__free(openssl_locks
);
81 static void init_ssl(void)
84 long ssl_opts
= SSL_OP_NO_SSLv2
| SSL_OP_NO_SSLv3
;
86 /* Older OpenSSL and MacOS OpenSSL doesn't have this */
87 #ifdef SSL_OP_NO_COMPRESSION
88 ssl_opts
|= SSL_OP_NO_COMPRESSION
;
91 SSL_load_error_strings();
92 OpenSSL_add_ssl_algorithms();
94 * Load SSLv{2,3} and TLSv1 so that we can talk with servers
95 * which use the SSL hellos, which are often used for
96 * compatibility. We then disable SSL so we only allow OpenSSL
97 * to speak TLSv1 to perform the encryption itself.
99 git__ssl_ctx
= SSL_CTX_new(SSLv23_method());
100 SSL_CTX_set_options(git__ssl_ctx
, ssl_opts
);
101 SSL_CTX_set_mode(git__ssl_ctx
, SSL_MODE_AUTO_RETRY
);
102 SSL_CTX_set_verify(git__ssl_ctx
, SSL_VERIFY_NONE
, NULL
);
103 if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx
)) {
104 SSL_CTX_free(git__ssl_ctx
);
110 int git_openssl_set_locking(void)
116 num_locks
= CRYPTO_num_locks();
117 openssl_locks
= git__calloc(num_locks
, sizeof(git_mutex
));
118 GITERR_CHECK_ALLOC(openssl_locks
);
120 for (i
= 0; i
< num_locks
; i
++) {
121 if (git_mutex_init(&openssl_locks
[i
]) != 0) {
122 giterr_set(GITERR_SSL
, "failed to initialize openssl locks");
127 CRYPTO_set_locking_callback(openssl_locking_function
);
128 git__on_shutdown(shutdown_ssl_locking
);
131 giterr_set(GITERR_THREAD
, "libgit2 as not built with threads");
134 giterr_set(GITERR_SSL
, "libgit2 was not built with OpenSSL support");
140 * Handle the global state with TLS
142 * If libgit2 is built with GIT_THREADS enabled,
143 * the `git_libgit2_init()` function must be called
144 * before calling any other function of the library.
146 * This function allocates a TLS index (using pthreads
147 * or the native Win32 API) to store the global state
148 * on a per-thread basis.
150 * Any internal method that requires global state will
151 * then call `git__global_state()` which returns a pointer
152 * to the global state structure; this pointer is lazily
153 * allocated on each thread.
155 * Before shutting down the library, the
156 * `git_libgit2_shutdown` method must be called to free
157 * the previously reserved TLS index.
159 * If libgit2 is built without threading support, the
160 * `git__global_statestate()` call returns a pointer to a single,
161 * statically allocated global state. The `git_thread_`
162 * functions are not available in that case.
166 * `git_libgit2_init()` allows subsystems to perform global setup,
167 * which may take place in the global scope. An explicit memory
168 * fence exists at the exit of `git_libgit2_init()`. Without this,
169 * CPU cores are free to reorder cache invalidation of `_tls_init`
170 * before cache invalidation of the subsystems' newly written global
173 #if defined(GIT_THREADS) && defined(GIT_WIN32)
175 static DWORD _tls_index
;
176 static volatile LONG _mutex
= 0;
178 static int synchronized_threads_init(void)
182 _tls_index
= TlsAlloc();
183 if (git_mutex_init(&git__mwindow_mutex
))
186 /* Initialize any other subsystems that have global state */
187 if ((error
= git_hash_global_init()) >= 0)
188 error
= git_sysdir_global_init();
190 win32_pthread_initialize();
195 int git_libgit2_init(void)
200 while (InterlockedCompareExchange(&_mutex
, 1, 0)) { Sleep(0); }
202 /* Only do work on a 0 -> 1 transition of the refcount */
203 if (1 == git_atomic_inc(&git__n_inits
))
204 error
= synchronized_threads_init();
207 InterlockedExchange(&_mutex
, 0);
212 static void synchronized_threads_shutdown(void)
214 /* Shut down any subsystems that have global state */
217 git_mutex_free(&git__mwindow_mutex
);
220 void git_libgit2_shutdown(void)
223 while (InterlockedCompareExchange(&_mutex
, 1, 0)) { Sleep(0); }
225 /* Only do work on a 1 -> 0 transition of the refcount */
226 if (0 == git_atomic_dec(&git__n_inits
))
227 synchronized_threads_shutdown();
230 InterlockedExchange(&_mutex
, 0);
233 git_global_st
*git__global_state(void)
237 assert(git_atomic_get(&git__n_inits
) > 0);
239 if ((ptr
= TlsGetValue(_tls_index
)) != NULL
)
242 ptr
= git__malloc(sizeof(git_global_st
));
246 memset(ptr
, 0x0, sizeof(git_global_st
));
247 TlsSetValue(_tls_index
, ptr
);
251 #elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
253 static pthread_key_t _tls_key
;
254 static pthread_once_t _once_init
= PTHREAD_ONCE_INIT
;
257 static void cb__free_status(void *st
)
259 git_global_st
*state
= (git_global_st
*) st
;
260 git__free(state
->error_t
.message
);
265 static void init_once(void)
267 if ((init_error
= git_mutex_init(&git__mwindow_mutex
)) != 0)
269 pthread_key_create(&_tls_key
, &cb__free_status
);
272 /* Initialize any other subsystems that have global state */
273 if ((init_error
= git_hash_global_init()) >= 0)
274 init_error
= git_sysdir_global_init();
276 /* OpenSSL needs to be initialized from the main thread */
282 int git_libgit2_init(void)
284 pthread_once(&_once_init
, init_once
);
285 git_atomic_inc(&git__n_inits
);
289 void git_libgit2_shutdown(void)
292 pthread_once_t new_once
= PTHREAD_ONCE_INIT
;
294 if (git_atomic_dec(&git__n_inits
) > 0) return;
296 /* Shut down any subsystems that have global state */
299 ptr
= pthread_getspecific(_tls_key
);
300 pthread_setspecific(_tls_key
, NULL
);
303 pthread_key_delete(_tls_key
);
304 git_mutex_free(&git__mwindow_mutex
);
305 _once_init
= new_once
;
308 git_global_st
*git__global_state(void)
312 assert(git_atomic_get(&git__n_inits
) > 0);
314 if ((ptr
= pthread_getspecific(_tls_key
)) != NULL
)
317 ptr
= git__malloc(sizeof(git_global_st
));
321 memset(ptr
, 0x0, sizeof(git_global_st
));
322 pthread_setspecific(_tls_key
, ptr
);
328 static git_global_st __state
;
330 int git_libgit2_init(void)
332 static int ssl_inited
= 0;
339 git_atomic_inc(&git__n_inits
);
343 void git_libgit2_shutdown(void)
345 /* Shut down any subsystems that have global state */
346 if (0 == git_atomic_dec(&git__n_inits
))
350 git_global_st
*git__global_state(void)
355 #endif /* GIT_THREADS */