[vlc-devel] [PATCH v5 7/9] video_output: handle the termination of the vout thread outside of control.c

Steve Lhomme robux4 at ycbcr.xyz
Fri Dec 18 10:21:30 UTC 2020


To terminate the thread ASAP we need to set the terminate flag (from whatever
thread) and wake up the loop if it was waiting for anything.

The control_Pop still waits for the is_held to be false, meaning other threads
doing things on the vout to be done. This was done when the vout thread loop
was just receiving VOUT_CONTROL_TERMINATE to signify the end of the thread.

As the termination may happen during ThreadDisplayPicture we also check if we
have to terminate the thread when it is done.
---
 src/video_output/control.c      | 19 ++-----------------
 src/video_output/control.h      |  4 +---
 src/video_output/video_output.c | 18 +++++++++++++-----
 3 files changed, 16 insertions(+), 25 deletions(-)

diff --git a/src/video_output/control.c b/src/video_output/control.c
index 56f105f4bbd..c5b14887ecb 100644
--- a/src/video_output/control.c
+++ b/src/video_output/control.c
@@ -39,7 +39,6 @@ void vout_control_Init(vout_control_t *ctrl)
     ctrl->is_held = false;
     ctrl->is_waiting = false;
     ctrl->can_sleep = true;
-    ctrl->is_terminated = false;
     ARRAY_INIT(ctrl->cmd);
 }
 
@@ -65,14 +64,6 @@ void vout_control_Wake(vout_control_t *ctrl)
     vlc_mutex_unlock(&ctrl->lock);
 }
 
-void vout_control_PushTerminate(vout_control_t *ctrl)
-{
-    vlc_mutex_lock(&ctrl->lock);
-    ctrl->is_terminated = true;
-    vlc_cond_signal(&ctrl->wait_request);
-    vlc_mutex_unlock(&ctrl->lock);
-}
-
 void vout_control_Hold(vout_control_t *ctrl)
 {
     vlc_mutex_lock(&ctrl->lock);
@@ -91,13 +82,12 @@ void vout_control_Release(vout_control_t *ctrl)
     vlc_mutex_unlock(&ctrl->lock);
 }
 
-int vout_control_Pop(vout_control_t *ctrl, vlc_mouse_t *mouse,
-                     bool *is_terminated, vlc_tick_t deadline)
+int vout_control_Pop(vout_control_t *ctrl, vlc_mouse_t *mouse, vlc_tick_t deadline)
 {
     bool has_cmd = false;
     vlc_mutex_lock(&ctrl->lock);
 
-    if (ctrl->cmd.i_size <= 0 && !ctrl->is_terminated) {
+    if (ctrl->cmd.i_size <= 0) {
         /* Spurious wakeups are perfectly fine */
         if (deadline != VLC_TICK_INVALID && ctrl->can_sleep) {
             ctrl->is_waiting = true;
@@ -110,9 +100,6 @@ int vout_control_Pop(vout_control_t *ctrl, vlc_mouse_t *mouse,
     while (ctrl->is_held)
         vlc_cond_wait(&ctrl->wait_available, &ctrl->lock);
 
-    if (ctrl->is_terminated)
-        goto done;
-
     if (ctrl->cmd.i_size > 0) {
         has_cmd = true;
         *mouse = ARRAY_VAL(ctrl->cmd, 0);
@@ -120,8 +107,6 @@ int vout_control_Pop(vout_control_t *ctrl, vlc_mouse_t *mouse,
     } else {
         ctrl->can_sleep = true;
     }
-done:
-    *is_terminated = ctrl->is_terminated;
     vlc_mutex_unlock(&ctrl->lock);
 
     return has_cmd ? VLC_SUCCESS : VLC_EGENERIC;
diff --git a/src/video_output/control.h b/src/video_output/control.h
index ce2c480879c..35e8aad6528 100644
--- a/src/video_output/control.h
+++ b/src/video_output/control.h
@@ -35,7 +35,6 @@ typedef struct {
     bool can_sleep;
     bool is_waiting;
     bool is_held;
-    bool is_terminated;
     DECL_ARRAY(vlc_mouse_t) cmd;
 } vout_control_t;
 
@@ -45,12 +44,11 @@ void vout_control_Clean(vout_control_t *);
 
 /* controls outside of the vout thread */
 void vout_control_PushMouse(vout_control_t *, const vlc_mouse_t *);
-void vout_control_PushTerminate(vout_control_t *);
 void vout_control_Wake(vout_control_t *);
 void vout_control_Hold(vout_control_t *);
 void vout_control_Release(vout_control_t *);
 
 /* control inside of the vout thread */
-int vout_control_Pop(vout_control_t *, vlc_mouse_t *, bool *, vlc_tick_t deadline);
+int vout_control_Pop(vout_control_t *, vlc_mouse_t *, vlc_tick_t deadline);
 
 #endif
diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c
index ed6b2c18491..350a3e76c6e 100644
--- a/src/video_output/video_output.c
+++ b/src/video_output/video_output.c
@@ -118,6 +118,7 @@ typedef struct vout_thread_sys_t
 
     /* Thread & synchronization */
     vout_control_t  control;
+    atomic_bool     control_is_terminated; // shutdown the vout thread
     vlc_thread_t    thread;
 
     struct {
@@ -1898,18 +1899,21 @@ static void *Thread(void *object)
             deadline = VLC_TICK_INVALID;
         }
 
-        bool terminated = false;
         vlc_mouse_t video_mouse;
-        while (vout_control_Pop(&sys->control, &video_mouse, &terminated,
-                                deadline) == VLC_SUCCESS && !terminated) {
+        while (vout_control_Pop(&sys->control, &video_mouse, deadline) == VLC_SUCCESS) {
+            if (atomic_load(&sys->control_is_terminated))
+                break;
             ThreadProcessMouseState(vout, &video_mouse);
         }
 
-        if (terminated)
+        if (atomic_load(&sys->control_is_terminated))
             break;
 
         wait = ThreadDisplayPicture(vout, &deadline) != VLC_SUCCESS;
 
+        if (atomic_load(&sys->control_is_terminated))
+            break;
+
         const bool picture_interlaced = sys->displayed.is_interlaced;
 
         vout_SetInterlacingState(&vout->obj, &sys->private, picture_interlaced);
@@ -1970,7 +1974,9 @@ void vout_StopDisplay(vout_thread_t *vout)
 {
     vout_thread_sys_t *sys = VOUT_THREAD_TO_SYS(vout);
 
-    vout_control_PushTerminate(&sys->control);
+    atomic_store(&sys->control_is_terminated, true);
+    // wake up so it goes back to the loop that will detect the terminated state
+    vout_control_Wake(&sys->control);
     vlc_join(sys->thread, NULL);
 
     vout_ReleaseDisplay(sys);
@@ -2115,6 +2121,7 @@ vout_thread_t *vout_Create(vlc_object_t *object)
                spu_Create(vout, vout) : NULL;
 
     vout_control_Init(&sys->control);
+    atomic_init(&sys->control_is_terminated, false);
 
     sys->title.show     = var_InheritBool(vout, "video-title-show");
     sys->title.timeout  = var_InheritInteger(vout, "video-title-timeout");
@@ -2303,6 +2310,7 @@ int vout_Request(const vout_configuration_t *cfg, vlc_video_context *vctx, input
         vout_DisableWindow(vout);
         return -1;
     }
+    atomic_store(&sys->control_is_terminated, false);
     if (vlc_clone(&sys->thread, Thread, vout, VLC_THREAD_PRIORITY_OUTPUT)) {
         vout_ReleaseDisplay(vout);
         vout_DisableWindow(vout);
-- 
2.29.2



More information about the vlc-devel mailing list