[vlc-commits] threads: generic one-time initializer

Rémi Denis-Courmont git at videolan.org
Thu Apr 2 18:14:34 CEST 2020


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Mon Feb 24 21:31:37 2020 +0200| [07f65e3381414ebbf83f92c0602b30d411dbc56b] | committer: Rémi Denis-Courmont

threads: generic one-time initializer

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

 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



More information about the vlc-commits mailing list