[vlc-commits] [Git][videolan/vlc][master] 3 commits: atomic: move atomic wait/notify to atomic header

Hugo Beauzée-Luyssen (@chouquette) gitlab at videolan.org
Thu Oct 7 16:27:12 UTC 2021



Hugo Beauzée-Luyssen pushed to branch master at VideoLAN / VLC


Commits:
5d88ae10 by Rémi Denis-Courmont at 2021-10-07T16:07:34+00:00
atomic: move atomic wait/notify to atomic header

These functions are functionally at the intersection of threading and
atomic operations. But then again, atomic operations in general are
intrinsically dependent on threading.

On the practical side, <vlc_atomic.h> is not an implicit header in
<vlc_common.h>, unlike <vlc_threads.h>. So this change actually lessens
the namespace "pollution".

- - - - -
6f72508b by Rémi Denis-Courmont at 2021-10-07T16:07:34+00:00
atomic: expose the wait and notify functions

They are mostly the same as the C++20, and ever more so C2X drafts.
The differences are:
* The set of supported atom types is more constrained in LibVLC.
* LibVLC supports timed-waits.

- - - - -
83143016 by Rémi Denis-Courmont at 2021-10-07T16:07:34+00:00
media: use atomic variable for worker count

- - - - -


12 changed files:

- include/vlc_atomic.h
- include/vlc_threads.h
- lib/media.c
- lib/media_internal.h
- src/android/thread.c
- src/freebsd/thread.c
- src/libvlccore.sym
- src/linux/thread.c
- src/misc/threads.c
- src/os2/thread.c
- src/posix/wait.c
- src/win32/thread.c


Changes:

=====================================
include/vlc_atomic.h
=====================================
@@ -73,4 +73,62 @@ static inline uintptr_t vlc_atomic_rc_get(const vlc_atomic_rc_t* rc)
     return atomic_load_explicit(&rc->refs, memory_order_relaxed);
 }
 
+/**
+ * Waits on an address.
+ *
+ * Puts the calling thread to sleep if a specific unsigned 32-bits value is
+ * stored at a specified address. The thread will sleep until it is woken up by
+ * a call to vlc_atomic_notify_one() or vlc_atomic_notify_all() in another
+ * thread, or spuriously.
+ *
+ * If the value does not match, do nothing and return immediately.
+ *
+ * \param addr address to check for
+ * \param val value to match at the address
+ */
+VLC_API void vlc_atomic_wait(void *addr, unsigned val);
+
+/**
+ * Waits on an address with a time-out.
+ *
+ * This function operates as vlc_atomic_wait() but provides an additional
+ * time-out. If the deadline is reached, the thread resumes and the function
+ * returns.
+ *
+ * \param addr address to check for
+ * \param val value to match at the address
+ * \param deadline deadline to wait until
+ *
+ * \retval 0 the function was woken up before the time-out
+ * \retval ETIMEDOUT the deadline was reached
+ */
+VLC_API
+int vlc_atomic_timedwait(void *addr, unsigned val, vlc_tick_t deadline);
+
+int vlc_atomic_timedwait_daytime(void *addr, unsigned val, time_t deadline);
+
+/**
+ * Wakes up one thread on an address.
+ *
+ * Wakes up (at least) one of the thread sleeping on the specified address.
+ * The address must be equal to the first parameter given by at least one
+ * thread sleeping within the vlc_atomic_wait() or vlc_atomic_timedwait()
+ * functions. If no threads are found, this function does nothing.
+ *
+ * \param addr address identifying which threads may be woken up
+ */
+VLC_API void vlc_atomic_notify_one(void *addr);
+
+/**
+ * Wakes up all thread on an address.
+ *
+ * Wakes up all threads sleeping on the specified address (if any).
+ * Any thread sleeping within a call to vlc_atomic_wait() or
+ * vlc_atomic_timedwait() with the specified address as first call parameter
+ * will be woken up.
+ *
+ * \param addr address identifying which threads to wake up
+ */
+VLC_API void vlc_atomic_notify_all(void *addr);
+
 #endif


=====================================
include/vlc_threads.h
=====================================
@@ -652,63 +652,6 @@ VLC_API void *vlc_threadvar_get(vlc_threadvar_t);
 
 /** @} */
 
-/**
- * Waits on an address.
- *
- * Puts the calling thread to sleep if a specific unsigned 32-bits value is
- * stored at a specified address. The thread will sleep until it is woken up by
- * a call to vlc_atomic_notify_one() or vlc_atomic_notify_all() in another
- * thread, or spuriously.
- *
- * If the value does not match, do nothing and return immediately.
- *
- * \param addr address to check for
- * \param val value to match at the address
- */
-void vlc_atomic_wait(void *addr, unsigned val);
-
-/**
- * Waits on an address with a time-out.
- *
- * This function operates as vlc_atomic_wait() but provides an additional
- * time-out. If the deadline is reached, the thread resumes and the function
- * returns.
- *
- * \param addr address to check for
- * \param val value to match at the address
- * \param deadline deadline to wait until
- *
- * \retval 0 the function was woken up before the time-out
- * \retval ETIMEDOUT the deadline was reached
- */
-int vlc_atomic_timedwait(void *addr, unsigned val, vlc_tick_t deadline);
-
-int vlc_atomic_timedwait_daytime(void *addr, unsigned val, time_t deadline);
-
-/**
- * Wakes up one thread on an address.
- *
- * Wakes up (at least) one of the thread sleeping on the specified address.
- * The address must be equal to the first parameter given by at least one
- * thread sleeping within the vlc_atomic_wait() or vlc_atomic_timedwait()
- * functions. If no threads are found, this function does nothing.
- *
- * \param addr address identifying which threads may be woken up
- */
-void vlc_atomic_notify_one(void *addr);
-
-/**
- * Wakes up all thread on an address.
- *
- * Wakes up all threads sleeping on the specified address (if any).
- * Any thread sleeping within a call to vlc_atomic_wait() or
- * vlc_atomic_timedwait() with the specified address as first call parameter
- * will be woken up.
- *
- * \param addr address identifying which threads to wake up
- */
-void vlc_atomic_notify_all(void *addr);
-
 /**
  * Creates and starts a new thread.
  *


=====================================
lib/media.c
=====================================
@@ -26,6 +26,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <limits.h>
 
 #include <vlc/libvlc.h>
 #include <vlc/libvlc_picture.h>
@@ -433,11 +434,9 @@ static void input_item_preparse_ended(input_item_t *item,
     }
     send_parsed_changed( p_md, new_status );
 
-    vlc_mutex_lock(&p_md->parsed_lock);
-    assert(p_md->worker_count > 0);
-    p_md->worker_count--;
-    vlc_cond_signal(&p_md->idle_cond);
-    vlc_mutex_unlock(&p_md->parsed_lock);
+    if (atomic_fetch_sub_explicit(&p_md->worker_count, 1,
+                                  memory_order_release) == 1)
+        vlc_atomic_notify_one(&p_md->worker_count);
 }
 
 /**
@@ -512,9 +511,7 @@ libvlc_media_t * libvlc_media_new_from_input_item(
     vlc_cond_init(&p_md->parsed_cond);
     vlc_mutex_init(&p_md->parsed_lock);
     vlc_mutex_init(&p_md->subitems_lock);
-
-    vlc_cond_init(&p_md->idle_cond);
-    p_md->worker_count = 0;
+    atomic_init(&p_md->worker_count, 0);
 
     p_md->state = libvlc_NothingSpecial;
 
@@ -649,6 +646,8 @@ void libvlc_media_add_option_flag( libvlc_media_t * p_md,
 // Delete a media descriptor object
 void libvlc_media_release( libvlc_media_t *p_md )
 {
+    unsigned int ref;
+
     if (!p_md)
         return;
 
@@ -661,10 +660,9 @@ void libvlc_media_release( libvlc_media_t *p_md )
     libvlc_MetadataCancel( p_md->p_libvlc_instance->p_libvlc_int, p_md );
 
     /* Wait for all async tasks to stop. */
-    vlc_mutex_lock( &p_md->parsed_lock );
-    while( p_md->worker_count > 0 )
-        vlc_cond_wait( &p_md->idle_cond, &p_md->parsed_lock );
-    vlc_mutex_unlock( &p_md->parsed_lock );
+    while ((ref = atomic_load_explicit(&p_md->worker_count,
+                                       memory_order_acquire)) > 0)
+        vlc_atomic_wait(&p_md->worker_count, ref);
 
     if( p_md->p_subitems )
         libvlc_media_list_release( p_md->p_subitems );
@@ -866,6 +864,17 @@ static int media_parse(libvlc_media_t *media, bool b_async,
         input_item_t *item = media->p_input_item;
         input_item_meta_request_option_t parse_scope = META_REQUEST_OPTION_SCOPE_LOCAL;
         int ret;
+        unsigned int ref = atomic_load_explicit(&media->worker_count,
+                                                memory_order_relaxed);
+        do
+        {
+            if (unlikely(ref == UINT_MAX))
+                return -EOVERFLOW;
+        }
+        while (!atomic_compare_exchange_weak_explicit(&media->worker_count,
+                                                      &ref, ref + 1,
+                                                      memory_order_relaxed,
+                                                      memory_order_relaxed));
 
         if (parse_flag & libvlc_media_parse_network)
             parse_scope |= META_REQUEST_OPTION_SCOPE_NETWORK;
@@ -876,22 +885,13 @@ static int media_parse(libvlc_media_t *media, bool b_async,
         if (parse_flag & libvlc_media_do_interact)
             parse_scope |= META_REQUEST_OPTION_DO_INTERACT;
 
-        /* Note: we cannot keep parsed_lock when calling libvlc_MetadataRequest
-         * because it might also be used to submit the state synchronously
-         * which would result in recursive lock. */
-        vlc_mutex_lock(&media->parsed_lock);
-        media->worker_count++;
-        vlc_mutex_unlock(&media->parsed_lock);
-
         ret = libvlc_MetadataRequest(libvlc, item, parse_scope,
                                      &input_preparser_callbacks, media,
                                      timeout, media);
         if (ret != VLC_SUCCESS)
         {
-            vlc_mutex_lock(&media->parsed_lock);
-            assert(media->worker_count > 0);
-            media->worker_count--;
-            vlc_mutex_unlock(&media->parsed_lock);
+            atomic_fetch_sub_explicit(&media->worker_count, 1,
+                                      memory_order_relaxed);
             return ret;
         }
     }


=====================================
lib/media_internal.h
=====================================
@@ -51,8 +51,7 @@ struct libvlc_media_t
     /* Idle protection to prevent the media from being released during
      * preparsing. The preparse will be cancelled but the release will
      * be blocking until no async code is using the media anymore. */
-    vlc_cond_t idle_cond;
-    size_t worker_count;
+    atomic_uint worker_count;
 
     libvlc_media_parsed_status_t parsed_status;
     bool is_parsed;


=====================================
src/android/thread.c
=====================================
@@ -43,6 +43,8 @@
 #include <pthread.h>
 #include <sched.h>
 
+#include <vlc_atomic.h>
+
 /* debug */
 
 #ifndef NDEBUG


=====================================
src/freebsd/thread.c
=====================================
@@ -32,6 +32,7 @@
 #include <sys/umtx.h>
 
 #include <vlc_common.h>
+#include <vlc_atomic.h>
 
 unsigned long vlc_thread_id(void)
 {


=====================================
src/libvlccore.sym
=====================================
@@ -501,6 +501,10 @@ vlc_clone
 VLC_CompileBy
 VLC_CompileHost
 VLC_Compiler
+vlc_atomic_wait
+vlc_atomic_timedwait
+vlc_atomic_notify_one
+vlc_atomic_notify_all
 vlc_cond_broadcast
 vlc_cond_init
 vlc_cond_signal


=====================================
src/linux/thread.c
=====================================
@@ -38,6 +38,7 @@
 #endif
 
 #include <vlc_common.h>
+#include <vlc_atomic.h>
 
 unsigned long vlc_thread_id(void)
 {


=====================================
src/misc/threads.c
=====================================
@@ -28,6 +28,7 @@
 #include <stdatomic.h>
 
 #include <vlc_common.h>
+#include <vlc_atomic.h>
 #include "libvlc.h"
 
 /* <stdatomic.h> types cannot be used in the C++ view of <vlc_threads.h> */


=====================================
src/os2/thread.c
=====================================
@@ -54,6 +54,8 @@
 
 #include <sys/stat.h>
 
+#include <vlc_atomic.h>
+
 /* Static mutex and condition variable */
 static vlc_mutex_t super_mutex;
 static vlc_cond_t  super_variable;


=====================================
src/posix/wait.c
=====================================
@@ -32,6 +32,8 @@
 #include <sys/types.h>
 #include <pthread.h>
 
+#include <vlc_atomic.h>
+
 static clockid_t vlc_clock_id = CLOCK_REALTIME;
 
 #define WAIT_BUCKET_INIT \


=====================================
src/win32/thread.c
=====================================
@@ -43,6 +43,7 @@
 #ifndef VLC_WINSTORE_APP
 #include <mmsystem.h>
 #endif
+#include <vlc_atomic.h>
 
 /*** Static mutex and condition variable ***/
 static CRITICAL_SECTION super_mutex;



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/55c929bd00bab041f6d69cdee1eb8774a15ce3b4...831430160678f2928ffb78d0bdd4ec4e1274eef3

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/55c929bd00bab041f6d69cdee1eb8774a15ce3b4...831430160678f2928ffb78d0bdd4ec4e1274eef3
You're receiving this email because of your account on code.videolan.org.




More information about the vlc-commits mailing list