Skip to content

Commit 5fe5557

Browse files
authored
Merge pull request libgit2#3974 from libgit2/pks/synchronize-shutdown
global: synchronize initialization and shutdown with pthreads
2 parents 6e2fab9 + 1c33ecc commit 5fe5557

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

src/global.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
247247
#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
248248

249249
static pthread_key_t _tls_key;
250+
static pthread_mutex_t _init_mutex = PTHREAD_MUTEX_INITIALIZER;
250251
static pthread_once_t _once_init = PTHREAD_ONCE_INIT;
251252
int init_error = 0;
252253

@@ -268,12 +269,19 @@ static void init_once(void)
268269

269270
int git_libgit2_init(void)
270271
{
271-
int ret;
272+
int ret, err;
272273

273274
ret = git_atomic_inc(&git__n_inits);
274-
pthread_once(&_once_init, init_once);
275275

276-
return init_error ? init_error : ret;
276+
if ((err = pthread_mutex_lock(&_init_mutex)) != 0)
277+
return err;
278+
err = pthread_once(&_once_init, init_once);
279+
err |= pthread_mutex_unlock(&_init_mutex);
280+
281+
if (err || init_error)
282+
return err | init_error;
283+
284+
return ret;
277285
}
278286

279287
int git_libgit2_shutdown(void)
@@ -285,6 +293,9 @@ int git_libgit2_shutdown(void)
285293
if ((ret = git_atomic_dec(&git__n_inits)) != 0)
286294
return ret;
287295

296+
if ((ret = pthread_mutex_lock(&_init_mutex)) != 0)
297+
return ret;
298+
288299
/* Shut down any subsystems that have global state */
289300
shutdown_common();
290301

@@ -298,6 +309,9 @@ int git_libgit2_shutdown(void)
298309
git_mutex_free(&git__mwindow_mutex);
299310
_once_init = new_once;
300311

312+
if ((ret = pthread_mutex_unlock(&_init_mutex)) != 0)
313+
return ret;
314+
301315
return 0;
302316
}
303317

@@ -327,7 +341,7 @@ int git_libgit2_init(void)
327341
{
328342
int ret;
329343

330-
/* Only init SSL the first time */
344+
/* Only init subsystems the first time */
331345
if ((ret = git_atomic_inc(&git__n_inits)) != 1)
332346
return ret;
333347

@@ -345,6 +359,7 @@ int git_libgit2_shutdown(void)
345359
if ((ret = git_atomic_dec(&git__n_inits)) == 0) {
346360
shutdown_common();
347361
git__global_state_cleanup(&__state);
362+
memset(&__state, 0, sizeof(__state));
348363
}
349364

350365
return ret;

tests/core/init.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,43 @@ void test_core_init__returns_count(void)
1212
cl_assert_equal_i(1, git_libgit2_shutdown());
1313
}
1414

15+
void test_core_init__reinit_succeeds(void)
16+
{
17+
cl_assert_equal_i(0, git_libgit2_shutdown());
18+
cl_assert_equal_i(1, git_libgit2_init());
19+
cl_sandbox_set_search_path_defaults();
20+
}
21+
22+
#ifdef GIT_THREADS
23+
static void *reinit(void *unused)
24+
{
25+
unsigned i;
26+
27+
for (i = 0; i < 20; i++) {
28+
cl_assert(git_libgit2_init() > 0);
29+
cl_assert(git_libgit2_shutdown() >= 0);
30+
}
31+
32+
return unused;
33+
}
34+
#endif
35+
36+
void test_core_init__concurrent_init_succeeds(void)
37+
{
38+
#ifdef GIT_THREADS
39+
git_thread threads[10];
40+
unsigned i;
41+
42+
cl_assert_equal_i(0, git_libgit2_shutdown());
43+
44+
for (i = 0; i < ARRAY_SIZE(threads); i++)
45+
git_thread_create(&threads[i], reinit, NULL);
46+
for (i = 0; i < ARRAY_SIZE(threads); i++)
47+
git_thread_join(&threads[i], NULL);
48+
49+
cl_assert_equal_i(1, git_libgit2_init());
50+
cl_sandbox_set_search_path_defaults();
51+
#else
52+
cl_skip();
53+
#endif
54+
}

0 commit comments

Comments
 (0)