[vlc-commits] threads: add one-time initializer vlc_once()

Rémi Denis-Courmont git at videolan.org
Sun Feb 11 16:29:38 CET 2018


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sun Feb 11 17:20:46 2018 +0200| [71d2d7c5a2adcf3cd41118eeba2ad40ee901304f] | committer: Rémi Denis-Courmont

threads: add one-time initializer vlc_once()

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=71d2d7c5a2adcf3cd41118eeba2ad40ee901304f
---

 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..f2c6eb3766 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_INITIALIZER
 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_INITIALIZER
 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_INITIALIZER
+
+/**
  * 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
 {



More information about the vlc-commits mailing list