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 "thread-utils.h"
15 git_mutex git__mwindow_mutex
;
17 #define MAX_SHUTDOWN_CB 8
20 # include <openssl/ssl.h>
21 SSL_CTX
*git__ssl_ctx
;
23 static git_mutex
*openssl_locks
;
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
;
31 void git__on_shutdown(git_global_shutdown_fn callback
)
33 int count
= git_atomic_inc(&git__n_shutdown_callbacks
);
34 assert(count
<= MAX_SHUTDOWN_CB
&& count
> 0);
35 git__shutdown_callbacks
[count
- 1] = callback
;
38 static void git__shutdown(void)
42 for (pos
= git_atomic_get(&git__n_shutdown_callbacks
); pos
> 0; pos
= git_atomic_dec(&git__n_shutdown_callbacks
)) {
43 git_global_shutdown_fn cb
= git__swap(git__shutdown_callbacks
[pos
- 1], NULL
);
50 #if defined(GIT_THREADS) && defined(GIT_SSL)
51 void openssl_locking_function(int mode
, int n
, const char *file
, int line
)
58 lock
= mode
& CRYPTO_LOCK
;
61 git_mutex_lock(&openssl_locks
[n
]);
63 git_mutex_unlock(&openssl_locks
[n
]);
67 static void shutdown_ssl(void)
69 git__free(openssl_locks
);
73 static void init_ssl(void)
76 SSL_load_error_strings();
77 OpenSSL_add_ssl_algorithms();
79 * Load SSLv{2,3} and TLSv1 so that we can talk with servers
80 * which use the SSL hellos, which are often used for
81 * compatibility. We then disable SSL so we only allow OpenSSL
82 * to speak TLSv1 to perform the encryption itself.
84 git__ssl_ctx
= SSL_CTX_new(SSLv23_method());
85 SSL_CTX_set_options(git__ssl_ctx
,
86 SSL_OP_NO_SSLv2
| SSL_OP_NO_SSLv3
87 /* Older OpenSSL and MacOS OpenSSL doesn't have this */
88 # ifdef SSL_OP_NO_COMPRESSION
89 | SSL_OP_NO_COMPRESSION
92 SSL_CTX_set_mode(git__ssl_ctx
, SSL_MODE_AUTO_RETRY
);
93 SSL_CTX_set_verify(git__ssl_ctx
, SSL_VERIFY_NONE
, NULL
);
94 if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx
)) {
95 SSL_CTX_free(git__ssl_ctx
);
103 num_locks
= CRYPTO_num_locks();
104 openssl_locks
= git__calloc(num_locks
, sizeof(git_mutex
));
105 if (openssl_locks
== NULL
) {
106 SSL_CTX_free(git__ssl_ctx
);
110 for (i
= 0; i
< num_locks
; i
++) {
111 if (git_mutex_init(&openssl_locks
[i
]) != 0) {
112 SSL_CTX_free(git__ssl_ctx
);
117 CRYPTO_set_locking_callback(openssl_locking_function
);
120 git__on_shutdown(shutdown_ssl
);
126 * Handle the global state with TLS
128 * If libgit2 is built with GIT_THREADS enabled,
129 * the `git_threads_init()` function must be called
130 * before calling any other function of the library.
132 * This function allocates a TLS index (using pthreads
133 * or the native Win32 API) to store the global state
134 * on a per-thread basis.
136 * Any internal method that requires global state will
137 * then call `git__global_state()` which returns a pointer
138 * to the global state structure; this pointer is lazily
139 * allocated on each thread.
141 * Before shutting down the library, the
142 * `git_threads_shutdown` method must be called to free
143 * the previously reserved TLS index.
145 * If libgit2 is built without threading support, the
146 * `git__global_statestate()` call returns a pointer to a single,
147 * statically allocated global state. The `git_thread_`
148 * functions are not available in that case.
152 * `git_threads_init()` allows subsystems to perform global setup,
153 * which may take place in the global scope. An explicit memory
154 * fence exists at the exit of `git_threads_init()`. Without this,
155 * CPU cores are free to reorder cache invalidation of `_tls_init`
156 * before cache invalidation of the subsystems' newly written global
159 #if defined(GIT_THREADS) && defined(GIT_WIN32)
161 static DWORD _tls_index
;
162 static volatile LONG _mutex
= 0;
164 static int synchronized_threads_init(void)
168 _tls_index
= TlsAlloc();
169 if (git_mutex_init(&git__mwindow_mutex
))
172 /* Initialize any other subsystems that have global state */
173 if ((error
= git_hash_global_init()) >= 0)
174 error
= git_sysdir_global_init();
176 win32_pthread_initialize();
181 int git_threads_init(void)
186 while (InterlockedCompareExchange(&_mutex
, 1, 0)) { Sleep(0); }
188 /* Only do work on a 0 -> 1 transition of the refcount */
189 if (1 == git_atomic_inc(&git__n_inits
))
190 error
= synchronized_threads_init();
193 InterlockedExchange(&_mutex
, 0);
198 static void synchronized_threads_shutdown(void)
200 /* Shut down any subsystems that have global state */
203 git_mutex_free(&git__mwindow_mutex
);
206 void git_threads_shutdown(void)
209 while (InterlockedCompareExchange(&_mutex
, 1, 0)) { Sleep(0); }
211 /* Only do work on a 1 -> 0 transition of the refcount */
212 if (0 == git_atomic_dec(&git__n_inits
))
213 synchronized_threads_shutdown();
216 InterlockedExchange(&_mutex
, 0);
219 git_global_st
*git__global_state(void)
223 assert(git_atomic_get(&git__n_inits
) > 0);
225 if ((ptr
= TlsGetValue(_tls_index
)) != NULL
)
228 ptr
= git__malloc(sizeof(git_global_st
));
232 memset(ptr
, 0x0, sizeof(git_global_st
));
233 TlsSetValue(_tls_index
, ptr
);
237 #elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
239 static pthread_key_t _tls_key
;
240 static pthread_once_t _once_init
= PTHREAD_ONCE_INIT
;
243 static void cb__free_status(void *st
)
245 git_global_st
*state
= (git_global_st
*) st
;
246 git__free(state
->error_t
.message
);
251 static void init_once(void)
253 if ((init_error
= git_mutex_init(&git__mwindow_mutex
)) != 0)
255 pthread_key_create(&_tls_key
, &cb__free_status
);
258 /* Initialize any other subsystems that have global state */
259 if ((init_error
= git_hash_global_init()) >= 0)
260 init_error
= git_sysdir_global_init();
262 /* OpenSSL needs to be initialized from the main thread */
268 int git_threads_init(void)
270 pthread_once(&_once_init
, init_once
);
271 git_atomic_inc(&git__n_inits
);
275 void git_threads_shutdown(void)
278 pthread_once_t new_once
= PTHREAD_ONCE_INIT
;
280 if (git_atomic_dec(&git__n_inits
) > 0) return;
282 /* Shut down any subsystems that have global state */
285 ptr
= pthread_getspecific(_tls_key
);
286 pthread_setspecific(_tls_key
, NULL
);
289 pthread_key_delete(_tls_key
);
290 git_mutex_free(&git__mwindow_mutex
);
291 _once_init
= new_once
;
294 git_global_st
*git__global_state(void)
298 assert(git_atomic_get(&git__n_inits
) > 0);
300 if ((ptr
= pthread_getspecific(_tls_key
)) != NULL
)
303 ptr
= git__malloc(sizeof(git_global_st
));
307 memset(ptr
, 0x0, sizeof(git_global_st
));
308 pthread_setspecific(_tls_key
, ptr
);
314 static git_global_st __state
;
316 int git_threads_init(void)
318 static int ssl_inited
= 0;
325 git_atomic_inc(&git__n_inits
);
329 void git_threads_shutdown(void)
331 /* Shut down any subsystems that have global state */
332 if (0 == git_atomic_dec(&git__n_inits
))
336 git_global_st
*git__global_state(void)
341 #endif /* GIT_THREADS */