[vlc-commits] [Git][videolan/vlc][master] 2 commits: threads: add vlc_once_begin() and vlc_once_complete()
Hugo Beauzée-Luyssen (@chouquette)
gitlab at videolan.org
Wed Feb 23 10:10:16 UTC 2022
Hugo Beauzée-Luyssen pushed to branch master at VideoLAN / VLC
Commits:
c86e6039 by Rémi Denis-Courmont at 2022-02-23T09:23:55+00:00
threads: add vlc_once_begin() and vlc_once_complete()
This supports one-time initialisation without callback, which is
somewhat more flexible and provides better type safety.
- - - - -
8b4fec24 by Rémi Denis-Courmont at 2022-02-23T09:23:55+00:00
threads: rewrite and inline vlc_once()
This rewrites vlc_once() as a trivial wrapper for vlc_once_begin() and
vlc_once_complete().
- - - - -
3 changed files:
- include/vlc_threads.h
- src/libvlccore.sym
- src/misc/threads.c
Changes:
=====================================
include/vlc_threads.h
=====================================
@@ -528,6 +528,55 @@ typedef struct
*/
#define VLC_STATIC_ONCE { ATOMIC_VAR_INIT(0) }
+/**
+ * Begins a one-time initialization.
+ *
+ * This function checks if a one-time initialization has completed:
+ * - If this is the first time the function is called for the given one-time
+ * initialization object, it marks the beginning of the initialization and
+ * returns true. vlc_once_complete() must be called to mark the completion
+ * of the initialisation.
+ * - Otherwise, it waits until the initialization completes and returns false.
+ * - In particular, if the initialization has already completed, the function
+ * returns false immediately without actually waiting.
+ *
+ * The specified one-time initialization object must have been initialized
+ * with @ref VLC_STATIC_ONCE, which is a constant expression suitable as a
+ * static initializer.
+ *
+ * \warning If this function is called twice without an intervening call to
+ * vlc_once_complete(), a dead lock will occur.
+ *
+ * \param once one-time initialisation object
+ * \retval false on the first call (for the given object)
+ * \retval true on subsequent calls (for the given object)
+ */
+VLC_API bool vlc_once_begin(vlc_once_t *restrict once);
+
+static inline bool vlc_once_begin_inline(vlc_once_t *restrict once)
+{
+ /* Fast path: check if already initialized */
+ if (unlikely(atomic_load_explicit(&once->value, memory_order_acquire) < 3))
+ return vlc_once_begin(once);
+ return true;
+}
+#define vlc_once_begin(once) vlc_once_begin_inline(once)
+
+/**
+ * Completes a one-time initialization.
+ *
+ * This function marks the end of an ongoing one-time initialization.
+ * If any thread is waiting for the completion of that initialization, its
+ * execution will be resumed.
+ *
+ * \warning The behavior is undefined if the one-time initialization object
+ * is uninitialized, if one-time initialization has not started, or
+ * if one-time initialization has already completed.
+ *
+ * \param once one-time initialisation object
+ */
+VLC_API void vlc_once_complete(vlc_once_t *restrict once);
+
/**
* Executes a function one time.
*
@@ -545,17 +594,14 @@ typedef struct
* \param cb callback to execute (the first time)
* \param opaque data pointer for the callback
*/
-VLC_API void vlc_once(vlc_once_t *restrict once, void (*cb)(void *),
- void *opaque);
-
-static inline void vlc_once_inline(vlc_once_t *restrict once,
- void (*cb)(void *), void *opaque)
+static inline void vlc_once(vlc_once_t *restrict once, void (*cb)(void *),
+ void *opaque)
{
- /* Fast path: check if already initialized */
- if (unlikely(atomic_load_explicit(&once->value, memory_order_acquire) < 3))
- vlc_once(once, cb, opaque);
+ if (unlikely(!vlc_once_begin(once))) {
+ cb(opaque);
+ vlc_once_complete(once);
+ }
}
-#define vlc_once(once, cb, opaque) vlc_once_inline(once, cb, opaque)
#endif
/**
=====================================
src/libvlccore.sym
=====================================
@@ -660,7 +660,8 @@ vlc_object_parent
vlc_object_get_tracer
vlc_object_Log
vlc_object_vaLog
-vlc_once
+vlc_once_begin
+vlc_once_complete
vlc_rand_bytes
vlc_drand48
vlc_lrand48
=====================================
src/misc/threads.c
=====================================
@@ -398,24 +398,15 @@ enum { VLC_ONCE_UNDONE, VLC_ONCE_DOING, VLC_ONCE_CONTEND, VLC_ONCE_DONE };
static_assert (VLC_ONCE_DONE == 3, "Check vlc_once in header file");
-void (vlc_once)(vlc_once_t *restrict once, void (*cb)(void *), void *opaque)
+bool (vlc_once_begin)(vlc_once_t *restrict once)
{
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(opaque);
-
- 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;
- }
+ memory_order_acquire))
+ return false;
assert(value >= VLC_ONCE_DOING);
@@ -432,4 +423,20 @@ void (vlc_once)(vlc_once_t *restrict once, void (*cb)(void *), void *opaque)
vlc_atomic_wait(&once->value, VLC_ONCE_CONTEND);
value = atomic_load_explicit(&once->value, memory_order_acquire);
}
+
+ return true;
+}
+
+void vlc_once_complete(vlc_once_t *restrict once)
+{
+ switch (atomic_exchange_explicit(&once->value, VLC_ONCE_DONE,
+ memory_order_release)) {
+ case VLC_ONCE_DOING: /* No waiters, nothing (else) to do */
+ break;
+ case VLC_ONCE_CONTEND: /* Notify waiters */
+ vlc_atomic_notify_all(&once->value);
+ break;
+ default:
+ vlc_assert_unreachable();
+ }
}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/dc26eb5389b55e688ce1a647a76a8c995cd3ee84...8b4fec2456c81f29931f898806d84b3db1a9c9e3
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/dc26eb5389b55e688ce1a647a76a8c995cd3ee84...8b4fec2456c81f29931f898806d84b3db1a9c9e3
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list