]> git.proxmox.com Git - libgit2.git/blame - src/global.c
ssl: init also without threads
[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"
a15c550d
VM
12#include "thread-utils.h"
13
8cef828d
CMN
14
15git_mutex git__mwindow_mutex;
16
a3aa5f4d
RB
17#define MAX_SHUTDOWN_CB 8
18
cf15ac8a
CMN
19#ifdef GIT_SSL
20# include <openssl/ssl.h>
21SSL_CTX *git__ssl_ctx;
22#endif
23
1d3364ac
CMN
24git_mutex git__ssl_mutex;
25git_atomic git__ssl_init;
26
3816debc
RB
27static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB];
28static git_atomic git__n_shutdown_callbacks;
29static git_atomic git__n_inits;
a3aa5f4d
RB
30
31void git__on_shutdown(git_global_shutdown_fn callback)
32{
33 int count = git_atomic_inc(&git__n_shutdown_callbacks);
001befcd 34 assert(count <= MAX_SHUTDOWN_CB && count > 0);
a3aa5f4d
RB
35 git__shutdown_callbacks[count - 1] = callback;
36}
37
38static void git__shutdown(void)
39{
40 int pos;
41
0bf5430d
AG
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);
44 if (cb != NULL)
45 cb();
46 }
001befcd 47
a3aa5f4d
RB
48}
49
8f897b6f
CMN
50static void init_ssl(void)
51{
52#ifdef GIT_SSL
53 SSL_load_error_strings();
54 OpenSSL_add_ssl_algorithms();
55 git__ssl_ctx = SSL_CTX_new(SSLv23_method());
56#endif
57}
58
a15c550d
VM
59/**
60 * Handle the global state with TLS
61 *
62 * If libgit2 is built with GIT_THREADS enabled,
63 * the `git_threads_init()` function must be called
64 * before calling any other function of the library.
65 *
66 * This function allocates a TLS index (using pthreads
67 * or the native Win32 API) to store the global state
68 * on a per-thread basis.
69 *
70 * Any internal method that requires global state will
71 * then call `git__global_state()` which returns a pointer
72 * to the global state structure; this pointer is lazily
73 * allocated on each thread.
74 *
75 * Before shutting down the library, the
76 * `git_threads_shutdown` method must be called to free
77 * the previously reserved TLS index.
78 *
79 * If libgit2 is built without threading support, the
80 * `git__global_statestate()` call returns a pointer to a single,
81 * statically allocated global state. The `git_thread_`
82 * functions are not available in that case.
83 */
84
7ebefd22
ET
85/*
86 * `git_threads_init()` allows subsystems to perform global setup,
87 * which may take place in the global scope. An explicit memory
88 * fence exists at the exit of `git_threads_init()`. Without this,
89 * CPU cores are free to reorder cache invalidation of `_tls_init`
90 * before cache invalidation of the subsystems' newly written global
91 * state.
92 */
a15c550d
VM
93#if defined(GIT_THREADS) && defined(GIT_WIN32)
94
95static DWORD _tls_index;
6e94a1ef 96static volatile LONG _mutex = 0;
e411b74e
BS
97
98static int synchronized_threads_init()
a15c550d 99{
7ebefd22
ET
100 int error;
101
a15c550d 102 _tls_index = TlsAlloc();
1a42dd17
RB
103 if (git_mutex_init(&git__mwindow_mutex))
104 return -1;
7ebefd22
ET
105
106 /* Initialize any other subsystems that have global state */
e411b74e 107 if ((error = git_hash_global_init()) >= 0)
83634d38 108 error = git_sysdir_global_init();
7ebefd22 109
43095341 110 win32_pthread_initialize();
cdc95a0d 111
e411b74e
BS
112 return error;
113}
114
115int git_threads_init(void)
116{
cdc95a0d
PK
117 int error = 0;
118
119 /* Enter the lock */
120 while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); }
e411b74e 121
cdc95a0d 122 /* Only do work on a 0 -> 1 transition of the refcount */
3816debc 123 if (1 == git_atomic_inc(&git__n_inits))
e411b74e 124 error = synchronized_threads_init();
43095341 125
cdc95a0d
PK
126 /* Exit the lock */
127 InterlockedExchange(&_mutex, 0);
128
7ebefd22 129 return error;
a15c550d
VM
130}
131
e411b74e 132static void synchronized_threads_shutdown()
a15c550d 133{
43095341 134 /* Shut down any subsystems that have global state */
a3aa5f4d 135 git__shutdown();
a15c550d 136 TlsFree(_tls_index);
43095341 137 git_mutex_free(&git__mwindow_mutex);
e411b74e
BS
138}
139
140void git_threads_shutdown(void)
141{
cdc95a0d
PK
142 /* Enter the lock */
143 while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); }
e411b74e 144
cdc95a0d 145 /* Only do work on a 1 -> 0 transition of the refcount */
3816debc 146 if (0 == git_atomic_dec(&git__n_inits))
e411b74e 147 synchronized_threads_shutdown();
cdc95a0d
PK
148
149 /* Exit the lock */
150 InterlockedExchange(&_mutex, 0);
a15c550d
VM
151}
152
153git_global_st *git__global_state(void)
154{
155 void *ptr;
156
3816debc 157 assert(git_atomic_get(&git__n_inits) > 0);
93b5fabc 158
a15c550d
VM
159 if ((ptr = TlsGetValue(_tls_index)) != NULL)
160 return ptr;
161
2bc8fa02 162 ptr = git__malloc(sizeof(git_global_st));
a15c550d
VM
163 if (!ptr)
164 return NULL;
165
166 memset(ptr, 0x0, sizeof(git_global_st));
167 TlsSetValue(_tls_index, ptr);
168 return ptr;
169}
170
171#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
172
173static pthread_key_t _tls_key;
e411b74e
BS
174static pthread_once_t _once_init = PTHREAD_ONCE_INIT;
175int init_error = 0;
a15c550d
VM
176
177static void cb__free_status(void *st)
178{
2bc8fa02 179 git__free(st);
a15c550d
VM
180}
181
e411b74e 182static void init_once(void)
a15c550d 183{
e411b74e
BS
184 if ((init_error = git_mutex_init(&git__mwindow_mutex)) != 0)
185 return;
cf15ac8a
CMN
186 if ((init_error = git_mutex_init(&git__ssl_mutex)) != 0)
187 return;
a15c550d 188 pthread_key_create(&_tls_key, &cb__free_status);
7ebefd22 189
cf15ac8a 190
7ebefd22 191 /* Initialize any other subsystems that have global state */
e411b74e 192 if ((init_error = git_hash_global_init()) >= 0)
83634d38 193 init_error = git_sysdir_global_init();
7ebefd22 194
cf15ac8a
CMN
195 /* OpenSSL needs to be initialized from the main thread */
196 init_ssl();
197
7ebefd22 198 GIT_MEMORY_BARRIER;
e411b74e 199}
7ebefd22 200
e411b74e
BS
201int git_threads_init(void)
202{
203 pthread_once(&_once_init, init_once);
204 git_atomic_inc(&git__n_inits);
205 return init_error;
a15c550d
VM
206}
207
208void git_threads_shutdown(void)
209{
efaa342c 210 void *ptr = NULL;
e411b74e
BS
211 pthread_once_t new_once = PTHREAD_ONCE_INIT;
212
213 if (git_atomic_dec(&git__n_inits) > 0) return;
214
a3aa5f4d
RB
215 /* Shut down any subsystems that have global state */
216 git__shutdown();
217
efaa342c 218 ptr = pthread_getspecific(_tls_key);
e411b74e
BS
219 pthread_setspecific(_tls_key, NULL);
220 git__free(ptr);
53607868 221
a15c550d 222 pthread_key_delete(_tls_key);
c3320aca 223 git_mutex_free(&git__mwindow_mutex);
e411b74e 224 _once_init = new_once;
a15c550d
VM
225}
226
227git_global_st *git__global_state(void)
228{
229 void *ptr;
230
3816debc 231 assert(git_atomic_get(&git__n_inits) > 0);
93b5fabc 232
a15c550d
VM
233 if ((ptr = pthread_getspecific(_tls_key)) != NULL)
234 return ptr;
235
2bc8fa02 236 ptr = git__malloc(sizeof(git_global_st));
a15c550d
VM
237 if (!ptr)
238 return NULL;
239
240 memset(ptr, 0x0, sizeof(git_global_st));
241 pthread_setspecific(_tls_key, ptr);
242 return ptr;
243}
244
245#else
246
247static git_global_st __state;
248
7ebefd22 249int git_threads_init(void)
a15c550d 250{
8f897b6f 251 init_ssl();
3816debc 252 git_atomic_inc(&git__n_inits);
7ebefd22 253 return 0;
a15c550d
VM
254}
255
256void git_threads_shutdown(void)
257{
41954a49 258 /* Shut down any subsystems that have global state */
3816debc
RB
259 if (0 == git_atomic_dec(&git__n_inits))
260 git__shutdown();
a15c550d
VM
261}
262
263git_global_st *git__global_state(void)
264{
265 return &__state;
266}
267
268#endif /* GIT_THREADS */