From fa9fc74f05e74375845f5af4f5a2d6678d0c4c65 Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9mi=20Denis-Courmont?= Date: Sun, 11 Feb 2018 17:20:46 +0200 Subject: [PATCH] threads: add one-time initializer vlc_once() --- include/vlc_threads.h | 38 +++++++++++++++++++++++++++++++++++++- src/android/thread.c | 6 ++++++ src/darwin/thread.c | 6 ++++++ src/libvlccore.sym | 1 + src/posix/thread.c | 6 ++++++ src/win32/thread.c | 16 ++++++++++++++++ 6 files changed, 72 insertions(+), 1 deletion(-) diff --git a/include/vlc_threads.h b/include/vlc_threads.h index 960d458bb2..37054a3ded 100644 --- a/include/vlc_threads.h +++ b/include/vlc_threads.h @@ -72,6 +72,8 @@ typedef struct #define LIBVLC_NEED_CONDVAR #define LIBVLC_NEED_SEMAPHORE #define LIBVLC_NEED_RWLOCK +typedef INIT_ONCE vlc_once_t; +#define VLC_STATIC_ONCE INIT_ONCE_STATIC_INIT typedef struct vlc_threadvar *vlc_threadvar_t; typedef struct vlc_timer *vlc_timer_t; @@ -171,7 +173,8 @@ typedef struct vlc_thread *vlc_thread_t; #define VLC_THREAD_CANCELED NULL typedef pthread_mutex_t vlc_mutex_t; #define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER - +typedef pthread_once_t vlc_once_t; +#define VLC_STATIC_ONCE PTHREAD_ONCE_INIT typedef pthread_key_t vlc_threadvar_t; typedef struct vlc_timer *vlc_timer_t; @@ -221,6 +224,8 @@ typedef pthread_cond_t vlc_cond_t; typedef semaphore_t vlc_sem_t; typedef pthread_rwlock_t vlc_rwlock_t; #define VLC_STATIC_RWLOCK PTHREAD_RWLOCK_INITIALIZER +typedef pthread_once_t vlc_once_t; +#define VLC_STATIC_ONCE PTHREAD_ONCE_INIT typedef pthread_key_t vlc_threadvar_t; typedef struct vlc_timer *vlc_timer_t; @@ -309,6 +314,19 @@ typedef pthread_rwlock_t vlc_rwlock_t; #define VLC_STATIC_RWLOCK PTHREAD_RWLOCK_INITIALIZER /** + * One-time initialization. + * + * A one-time initialization object must always be initialized assigned to + * \ref VLC_STATIC_ONCE before use. + */ +typedef pthread_once_t vlc_once_t; + +/** + * Static initializer for one-time initialization. + */ +#define VLC_STATIC_ONCE PTHREAD_ONCE_INIT + +/** * Thread-local key handle. */ typedef pthread_key_t vlc_threadvar_t; @@ -585,6 +603,24 @@ VLC_API void vlc_rwlock_wrlock(vlc_rwlock_t *); VLC_API void vlc_rwlock_unlock(vlc_rwlock_t *); /** + * Executes a function one time. + * + * The first time this function is called with a given one-time initialization + * object, it executes the provided callback. + * Any further call with the same object will be a no-op. + * + * In the corner case that the first time execution is ongoing in another + * thread, then the function will wait for completion on the other thread + * (and then synchronize memory) before it returns. + * This ensures that, no matter what, the callback has been executed exactly + * once and its side effects are visible after the function returns. + * + * \param once a one-time initialization object + * \param cb callback to execute (the first time) + */ +VLC_API void vlc_once(vlc_once_t *restrict once, void (*cb)(void)); + +/** * Allocates a thread-specific variable. * * @param key where to store the thread-specific variable handle diff --git a/src/android/thread.c b/src/android/thread.c index 3f8062753e..46e1c27892 100644 --- a/src/android/thread.c +++ b/src/android/thread.c @@ -141,6 +141,12 @@ void vlc_mutex_unlock (vlc_mutex_t *p_mutex) VLC_THREAD_ASSERT ("unlocking mutex"); } +void vlc_once(vlc_once_t *once, void (*cb)(void)) +{ + int val = pthread_once(once, cb); + VLC_THREAD_ASSERT("initializing once"); +} + struct vlc_thread { pthread_t thread; diff --git a/src/darwin/thread.c b/src/darwin/thread.c index b4991fa4c9..22660c0ee8 100644 --- a/src/darwin/thread.c +++ b/src/darwin/thread.c @@ -369,6 +369,12 @@ void vlc_rwlock_unlock (vlc_rwlock_t *lock) VLC_THREAD_ASSERT ("releasing R/W lock"); } +void vlc_once(vlc_once_t *once, void (*cb)(void)) +{ + int val = pthread_once(once, cb); + VLC_THREAD_ASSERT("initializing once"); +} + int vlc_threadvar_create (vlc_threadvar_t *key, void (*destr) (void *)) { return pthread_key_create (key, destr); diff --git a/src/libvlccore.sym b/src/libvlccore.sym index a15ba0d923..e6f3abff34 100644 --- a/src/libvlccore.sym +++ b/src/libvlccore.sym @@ -643,6 +643,7 @@ vlc_object_find_name vlc_object_hold vlc_object_release vlc_object_get_name +vlc_once vlc_rand_bytes vlc_drand48 vlc_lrand48 diff --git a/src/posix/thread.c b/src/posix/thread.c index df7ce867b2..352b37d871 100644 --- a/src/posix/thread.c +++ b/src/posix/thread.c @@ -367,6 +367,12 @@ void vlc_rwlock_unlock (vlc_rwlock_t *lock) VLC_THREAD_ASSERT ("releasing R/W lock"); } +void vlc_once(vlc_once_t *once, void (*cb)(void)) +{ + int val = pthread_once(once, cb); + VLC_THREAD_ASSERT("initializing once"); +} + int vlc_threadvar_create (vlc_threadvar_t *key, void (*destr) (void *)) { return pthread_key_create (key, destr); diff --git a/src/win32/thread.c b/src/win32/thread.c index 9a20af04fa..b40f64cd52 100644 --- a/src/win32/thread.c +++ b/src/win32/thread.c @@ -196,6 +196,22 @@ void vlc_sem_wait (vlc_sem_t *sem) } #endif +/*** One-time initialization ***/ +static BOOL CALLBACK vlc_once_callback(INIT_ONCE *once, void *parm, void **ctx) +{ + void (*cb)(void) = parm; + + cb(); + (void) once; + (void) ctx; + return TRUE; +} + +void vlc_once(vlc_once_t *once, void (*cb)(void)) +{ + InitOnceExecuteOnce(once, vlc_once_callback, cb, NULL); +} + /*** Thread-specific variables (TLS) ***/ struct vlc_threadvar { -- 2.11.4.GIT