[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