mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-22 22:20:02 +00:00
global: synchronize initialization and shutdown with pthreads
When trying to initialize and tear down global data structures from different threads at once with `git_libgit2_init` and `git_libgit2_shutdown`, we race around initializing data. While we use `pthread_once` to assert that we only initilize data a single time, we actually reset the `pthread_once_t` on the last call to `git_libgit2_shutdown`. As resetting this variable is not synchronized with other threads trying to access it, this is actually racy when one thread tries to do a complete shutdown of libgit2 while another thread tries to initialize it. Fix the issue by creating a mutex which synchronizes `init_once` and the library shutdown.
This commit is contained in:
parent
41ad9ebfad
commit
59c6c2860a
20
src/global.c
20
src/global.c
@ -247,6 +247,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
|
|||||||
#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
|
#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
|
||||||
|
|
||||||
static pthread_key_t _tls_key;
|
static pthread_key_t _tls_key;
|
||||||
|
static pthread_mutex_t _init_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static pthread_once_t _once_init = PTHREAD_ONCE_INIT;
|
static pthread_once_t _once_init = PTHREAD_ONCE_INIT;
|
||||||
int init_error = 0;
|
int init_error = 0;
|
||||||
|
|
||||||
@ -268,12 +269,19 @@ static void init_once(void)
|
|||||||
|
|
||||||
int git_libgit2_init(void)
|
int git_libgit2_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret, err;
|
||||||
|
|
||||||
ret = git_atomic_inc(&git__n_inits);
|
ret = git_atomic_inc(&git__n_inits);
|
||||||
pthread_once(&_once_init, init_once);
|
|
||||||
|
|
||||||
return init_error ? init_error : ret;
|
if ((err = pthread_mutex_lock(&_init_mutex)) != 0)
|
||||||
|
return err;
|
||||||
|
err = pthread_once(&_once_init, init_once);
|
||||||
|
err |= pthread_mutex_unlock(&_init_mutex);
|
||||||
|
|
||||||
|
if (err || init_error)
|
||||||
|
return err | init_error;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_libgit2_shutdown(void)
|
int git_libgit2_shutdown(void)
|
||||||
@ -285,6 +293,9 @@ int git_libgit2_shutdown(void)
|
|||||||
if ((ret = git_atomic_dec(&git__n_inits)) != 0)
|
if ((ret = git_atomic_dec(&git__n_inits)) != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
if ((ret = pthread_mutex_lock(&_init_mutex)) != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* Shut down any subsystems that have global state */
|
/* Shut down any subsystems that have global state */
|
||||||
shutdown_common();
|
shutdown_common();
|
||||||
|
|
||||||
@ -298,6 +309,9 @@ int git_libgit2_shutdown(void)
|
|||||||
git_mutex_free(&git__mwindow_mutex);
|
git_mutex_free(&git__mwindow_mutex);
|
||||||
_once_init = new_once;
|
_once_init = new_once;
|
||||||
|
|
||||||
|
if ((ret = pthread_mutex_unlock(&_init_mutex)) != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user