[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