]> git.proxmox.com Git - libgit2.git/blame - src/global.c
Merge pull request #2741 from ethomson/fetch-twice
[libgit2.git] / src / global.c
CommitLineData
a15c550d 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
a15c550d
VM
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#include "common.h"
8#include "global.h"
7ebefd22 9#include "hash.h"
83634d38 10#include "sysdir.h"
41954a49 11#include "git2/threads.h"
799e22ea 12#include "git2/global.h"
a15c550d
VM
13#include "thread-utils.h"
14
8cef828d
CMN
15
16git_mutex git__mwindow_mutex;
17
a3aa5f4d
RB
18#define MAX_SHUTDOWN_CB 8
19
cf15ac8a
CMN
20#ifdef GIT_SSL
21# include <openssl/ssl.h>
22SSL_CTX *git__ssl_ctx;
f59a34d2 23# ifdef GIT_THREADS
081e76ba 24static git_mutex *openssl_locks;
f59a34d2 25# endif
cf15ac8a
CMN
26#endif
27
3816debc
RB
28static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB];
29static git_atomic git__n_shutdown_callbacks;
30static git_atomic git__n_inits;
a3aa5f4d
RB
31
32void git__on_shutdown(git_global_shutdown_fn callback)
33{
34 int count = git_atomic_inc(&git__n_shutdown_callbacks);
001befcd 35 assert(count <= MAX_SHUTDOWN_CB && count > 0);
a3aa5f4d
RB
36 git__shutdown_callbacks[count - 1] = callback;
37}
38
39static void git__shutdown(void)
40{
41 int pos;
42
0bf5430d
AG
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);
45 if (cb != NULL)
46 cb();
47 }
001befcd 48
a3aa5f4d
RB
49}
50
081e76ba
CMN
51#if defined(GIT_THREADS) && defined(GIT_SSL)
52void openssl_locking_function(int mode, int n, const char *file, int line)
53{
54 int lock;
55
56 GIT_UNUSED(file);
57 GIT_UNUSED(line);
58
59 lock = mode & CRYPTO_LOCK;
60
61 if (lock) {
62 git_mutex_lock(&openssl_locks[n]);
63 } else {
64 git_mutex_unlock(&openssl_locks[n]);
65 }
66}
081e76ba 67
fe6b51ae 68static void shutdown_ssl_locking(void)
50aae000 69{
d6ecc311
UM
70 int num_locks, i;
71
72 num_locks = CRYPTO_num_locks();
e0836577 73 CRYPTO_set_locking_callback(NULL);
d6ecc311
UM
74
75 for (i = 0; i < num_locks; ++i)
76 git_mutex_free(openssl_locks);
50aae000
ET
77 git__free(openssl_locks);
78}
79#endif
081e76ba 80
8f897b6f
CMN
81static void init_ssl(void)
82{
83#ifdef GIT_SSL
bc48bcdc
JG
84 long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
85
86 /* Older OpenSSL and MacOS OpenSSL doesn't have this */
87#ifdef SSL_OP_NO_COMPRESSION
88 ssl_opts |= SSL_OP_NO_COMPRESSION;
89#endif
90
8f897b6f
CMN
91 SSL_load_error_strings();
92 OpenSSL_add_ssl_algorithms();
f0f97370
CMN
93 /*
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.
98 */
8f897b6f 99 git__ssl_ctx = SSL_CTX_new(SSLv23_method());
bc48bcdc 100 SSL_CTX_set_options(git__ssl_ctx, ssl_opts);
081e76ba
CMN
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);
105 git__ssl_ctx = NULL;
106 }
fe6b51ae
CMN
107#endif
108}
081e76ba 109
fe6b51ae
CMN
110int git_openssl_set_locking(void)
111{
112#ifdef GIT_SSL
081e76ba 113# ifdef GIT_THREADS
fe6b51ae 114 int num_locks, i;
081e76ba 115
fe6b51ae
CMN
116 num_locks = CRYPTO_num_locks();
117 openssl_locks = git__calloc(num_locks, sizeof(git_mutex));
118 GITERR_CHECK_ALLOC(openssl_locks);
081e76ba 119
fe6b51ae
CMN
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");
123 return -1;
124 }
081e76ba 125 }
50aae000 126
fe6b51ae
CMN
127 CRYPTO_set_locking_callback(openssl_locking_function);
128 git__on_shutdown(shutdown_ssl_locking);
129 return 0;
130# else
131 giterr_set(GITERR_THREAD, "libgit2 as not built with threads");
132 return -1;
081e76ba 133# endif
fe6b51ae
CMN
134 giterr_set(GITERR_SSL, "libgit2 was not built with OpenSSL support");
135 return -1;
8f897b6f
CMN
136#endif
137}
138
a15c550d
VM
139/**
140 * Handle the global state with TLS
141 *
142 * If libgit2 is built with GIT_THREADS enabled,
799e22ea 143 * the `git_libgit2_init()` function must be called
a15c550d
VM
144 * before calling any other function of the library.
145 *
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.
149 *
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.
154 *
155 * Before shutting down the library, the
799e22ea 156 * `git_libgit2_shutdown` method must be called to free
a15c550d
VM
157 * the previously reserved TLS index.
158 *
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.
163 */
164
7ebefd22 165/*
799e22ea 166 * `git_libgit2_init()` allows subsystems to perform global setup,
7ebefd22 167 * which may take place in the global scope. An explicit memory
799e22ea 168 * fence exists at the exit of `git_libgit2_init()`. Without this,
7ebefd22
ET
169 * CPU cores are free to reorder cache invalidation of `_tls_init`
170 * before cache invalidation of the subsystems' newly written global
171 * state.
172 */
a15c550d
VM
173#if defined(GIT_THREADS) && defined(GIT_WIN32)
174
175static DWORD _tls_index;
6e94a1ef 176static volatile LONG _mutex = 0;
e411b74e 177
fb591767 178static int synchronized_threads_init(void)
a15c550d 179{
7ebefd22
ET
180 int error;
181
a15c550d 182 _tls_index = TlsAlloc();
1a42dd17
RB
183 if (git_mutex_init(&git__mwindow_mutex))
184 return -1;
7ebefd22
ET
185
186 /* Initialize any other subsystems that have global state */
e411b74e 187 if ((error = git_hash_global_init()) >= 0)
83634d38 188 error = git_sysdir_global_init();
7ebefd22 189
43095341 190 win32_pthread_initialize();
cdc95a0d 191
e411b74e
BS
192 return error;
193}
194
799e22ea 195int git_libgit2_init(void)
e411b74e 196{
cdc95a0d
PK
197 int error = 0;
198
199 /* Enter the lock */
200 while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); }
e411b74e 201
cdc95a0d 202 /* Only do work on a 0 -> 1 transition of the refcount */
3816debc 203 if (1 == git_atomic_inc(&git__n_inits))
e411b74e 204 error = synchronized_threads_init();
43095341 205
cdc95a0d
PK
206 /* Exit the lock */
207 InterlockedExchange(&_mutex, 0);
208
7ebefd22 209 return error;
a15c550d
VM
210}
211
fb591767 212static void synchronized_threads_shutdown(void)
a15c550d 213{
43095341 214 /* Shut down any subsystems that have global state */
a3aa5f4d 215 git__shutdown();
a15c550d 216 TlsFree(_tls_index);
43095341 217 git_mutex_free(&git__mwindow_mutex);
e411b74e
BS
218}
219
799e22ea 220void git_libgit2_shutdown(void)
e411b74e 221{
cdc95a0d
PK
222 /* Enter the lock */
223 while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); }
e411b74e 224
cdc95a0d 225 /* Only do work on a 1 -> 0 transition of the refcount */
3816debc 226 if (0 == git_atomic_dec(&git__n_inits))
e411b74e 227 synchronized_threads_shutdown();
cdc95a0d
PK
228
229 /* Exit the lock */
230 InterlockedExchange(&_mutex, 0);
a15c550d
VM
231}
232
233git_global_st *git__global_state(void)
234{
235 void *ptr;
236
3816debc 237 assert(git_atomic_get(&git__n_inits) > 0);
93b5fabc 238
a15c550d
VM
239 if ((ptr = TlsGetValue(_tls_index)) != NULL)
240 return ptr;
241
2bc8fa02 242 ptr = git__malloc(sizeof(git_global_st));
a15c550d
VM
243 if (!ptr)
244 return NULL;
245
246 memset(ptr, 0x0, sizeof(git_global_st));
247 TlsSetValue(_tls_index, ptr);
248 return ptr;
249}
250
251#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
252
253static pthread_key_t _tls_key;
e411b74e
BS
254static pthread_once_t _once_init = PTHREAD_ONCE_INIT;
255int init_error = 0;
a15c550d
VM
256
257static void cb__free_status(void *st)
258{
fdea219a
CMN
259 git_global_st *state = (git_global_st *) st;
260 git__free(state->error_t.message);
261
2bc8fa02 262 git__free(st);
a15c550d
VM
263}
264
e411b74e 265static void init_once(void)
a15c550d 266{
e411b74e
BS
267 if ((init_error = git_mutex_init(&git__mwindow_mutex)) != 0)
268 return;
a15c550d 269 pthread_key_create(&_tls_key, &cb__free_status);
7ebefd22 270
cf15ac8a 271
7ebefd22 272 /* Initialize any other subsystems that have global state */
e411b74e 273 if ((init_error = git_hash_global_init()) >= 0)
83634d38 274 init_error = git_sysdir_global_init();
7ebefd22 275
cf15ac8a
CMN
276 /* OpenSSL needs to be initialized from the main thread */
277 init_ssl();
278
7ebefd22 279 GIT_MEMORY_BARRIER;
e411b74e 280}
7ebefd22 281
799e22ea 282int git_libgit2_init(void)
e411b74e
BS
283{
284 pthread_once(&_once_init, init_once);
285 git_atomic_inc(&git__n_inits);
286 return init_error;
a15c550d
VM
287}
288
799e22ea 289void git_libgit2_shutdown(void)
a15c550d 290{
efaa342c 291 void *ptr = NULL;
e411b74e
BS
292 pthread_once_t new_once = PTHREAD_ONCE_INIT;
293
294 if (git_atomic_dec(&git__n_inits) > 0) return;
295
a3aa5f4d
RB
296 /* Shut down any subsystems that have global state */
297 git__shutdown();
298
efaa342c 299 ptr = pthread_getspecific(_tls_key);
e411b74e
BS
300 pthread_setspecific(_tls_key, NULL);
301 git__free(ptr);
53607868 302
a15c550d 303 pthread_key_delete(_tls_key);
c3320aca 304 git_mutex_free(&git__mwindow_mutex);
e411b74e 305 _once_init = new_once;
a15c550d
VM
306}
307
308git_global_st *git__global_state(void)
309{
310 void *ptr;
311
3816debc 312 assert(git_atomic_get(&git__n_inits) > 0);
93b5fabc 313
a15c550d
VM
314 if ((ptr = pthread_getspecific(_tls_key)) != NULL)
315 return ptr;
316
2bc8fa02 317 ptr = git__malloc(sizeof(git_global_st));
a15c550d
VM
318 if (!ptr)
319 return NULL;
320
321 memset(ptr, 0x0, sizeof(git_global_st));
322 pthread_setspecific(_tls_key, ptr);
323 return ptr;
324}
325
326#else
327
328static git_global_st __state;
329
799e22ea 330int git_libgit2_init(void)
a15c550d 331{
e6b0ae7a
CMN
332 static int ssl_inited = 0;
333
334 if (!ssl_inited) {
335 init_ssl();
336 ssl_inited = 1;
337 }
338
3816debc 339 git_atomic_inc(&git__n_inits);
7ebefd22 340 return 0;
a15c550d
VM
341}
342
799e22ea 343void git_libgit2_shutdown(void)
a15c550d 344{
41954a49 345 /* Shut down any subsystems that have global state */
3816debc
RB
346 if (0 == git_atomic_dec(&git__n_inits))
347 git__shutdown();
a15c550d
VM
348}
349
350git_global_st *git__global_state(void)
351{
352 return &__state;
353}
354
355#endif /* GIT_THREADS */