[vlc-devel] [PATCH 1/3] threads: generic one-time initializer

RĂ©mi Denis-Courmont remi at remlab.net
Thu Apr 2 16:28:36 CEST 2020


---
 include/vlc_threads.h | 20 ++++++++++++++++++++
 src/misc/threads.c    | 40 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 60 insertions(+)

diff --git a/include/vlc_threads.h b/include/vlc_threads.h
index 131e319622..b04a3305c1 100644
--- a/include/vlc_threads.h
+++ b/include/vlc_threads.h
@@ -633,6 +633,25 @@ VLC_API void vlc_rwlock_unlock(vlc_rwlock_t *);
 
 /** @} */
 
+#ifndef __cplusplus
+#if 0
+/**
+ * One-time initialization.
+ *
+ * A one-time initialization object must always be initialized assigned to
+ * \ref VLC_STATIC_ONCE before use.
+ */
+typedef struct
+{
+    atomic_uint value;
+} vlc_once_t;
+
+/**
+ * Static initializer for one-time initialization.
+ */
+#define VLC_STATIC_ONCE { ATOMIC_VAR_INIT(0) }
+#endif
+
 /**
  * Executes a function one time.
  *
@@ -650,6 +669,7 @@ VLC_API void vlc_rwlock_unlock(vlc_rwlock_t *);
  * \param cb callback to execute (the first time)
  */
 VLC_API void vlc_once(vlc_once_t *restrict once, void (*cb)(void));
+#endif
 
 /**
  * \defgroup threadvar Thread-specific variables
diff --git a/src/misc/threads.c b/src/misc/threads.c
index b1eb9888f2..11c46fa730 100644
--- a/src/misc/threads.c
+++ b/src/misc/threads.c
@@ -533,3 +533,43 @@ int vlc_sem_timedwait(vlc_sem_t *sem, vlc_tick_t deadline)
 
     return 0;
 }
+
+#if 0
+enum { VLC_ONCE_UNDONE, VLC_ONCE_DOING, VLC_ONCE_CONTEND, VLC_ONCE_DONE };
+
+void vlc_once(vlc_once_t *restrict once, void (*cb)(void))
+{
+    unsigned int value = VLC_ONCE_UNDONE;
+
+    if (atomic_compare_exchange_strong_explicit(&once->value, &value,
+                                                VLC_ONCE_DOING,
+                                                memory_order_acquire,
+                                                memory_order_acquire)) {
+        /* First time: run the callback */
+        cb();
+
+        if (atomic_exchange_explicit(&once->value, VLC_ONCE_DONE,
+                                     memory_order_release) == VLC_ONCE_CONTEND)
+            /* Notify waiters if any */
+            vlc_atomic_notify_all(&once->value);
+
+        return;
+    }
+
+    assert(value >= VLC_ONCE_DOING);
+
+    if (unlikely(value == VLC_ONCE_DOING)
+     && atomic_compare_exchange_strong_explicit(&once->value, &value,
+                                                VLC_ONCE_CONTEND,
+                                                memory_order_acquire,
+                                                memory_order_acquire))
+        value = VLC_ONCE_CONTEND;
+
+    assert(value >= VLC_ONCE_CONTEND);
+
+    while (unlikely(value != VLC_ONCE_DONE)) {
+        vlc_atomic_wait(&once->value, VLC_ONCE_CONTEND);
+        value = atomic_load_explicit(&once->value, memory_order_acquire);
+    }
+}
+#endif
-- 
2.26.0



More information about the vlc-devel mailing list