[vlc-devel] [PATCH 6/6] misc: remove background_worker

Romain Vimont rom1v at videolabs.io
Mon Sep 7 17:40:11 CEST 2020


A new "minimal" executor API has been introduced to replace it.
---
 src/Makefile.am              |   2 -
 src/misc/background_worker.c | 363 -----------------------------------
 src/misc/background_worker.h | 203 --------------------
 3 files changed, 568 deletions(-)
 delete mode 100644 src/misc/background_worker.c
 delete mode 100644 src/misc/background_worker.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 5336fd7ac0..4fbc2528fc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -350,8 +350,6 @@ libvlccore_la_SOURCES = \
 	text/iso_lang.c \
 	text/iso-639_def.h \
 	misc/actions.c \
-	misc/background_worker.c \
-	misc/background_worker.h \
 	misc/executor.c \
 	misc/md5.c \
 	misc/probe.c \
diff --git a/src/misc/background_worker.c b/src/misc/background_worker.c
deleted file mode 100644
index 05e28d813c..0000000000
--- a/src/misc/background_worker.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/*****************************************************************************
- * Copyright (C) 2017 VLC authors and VideoLAN
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <assert.h>
-#include <vlc_common.h>
-#include <vlc_list.h>
-#include <vlc_threads.h>
-
-#include "libvlc.h"
-#include "background_worker.h"
-
-struct task {
-    struct vlc_list node;
-    void* id; /**< id associated with entity */
-    void* entity; /**< the entity to process */
-    vlc_tick_t timeout; /**< timeout duration in vlc_tick_t */
-};
-
-struct background_worker;
-
-struct background_thread {
-    struct background_worker *owner;
-    vlc_cond_t probe_cancel_wait; /**< wait for probe request or cancelation */
-    bool probe; /**< true if a probe is requested */
-    bool cancel; /**< true if a cancel is requested */
-    struct task *task; /**< current task */
-    struct vlc_list node;
-};
-
-struct background_worker {
-    void* owner;
-    struct background_worker_config conf;
-
-    vlc_mutex_t lock;
-
-    int uncompleted; /**< number of tasks requested but not completed */
-    int nthreads; /**< number of threads in the threads list */
-    struct vlc_list threads; /**< list of active background_thread instances */
-
-    struct vlc_list queue; /**< queue of tasks */
-    vlc_cond_t queue_wait; /**< wait for the queue to be non-empty */
-
-    vlc_cond_t nothreads_wait; /**< wait for nthreads == 0 */
-    bool closing; /**< true if background worker deletion is requested */
-};
-
-static struct task *task_Create(struct background_worker *worker, void *id,
-                                void *entity, int timeout)
-{
-    struct task *task = malloc(sizeof(*task));
-    if (unlikely(!task))
-        return NULL;
-
-    task->id = id;
-    task->entity = entity;
-    task->timeout = timeout < 0 ? worker->conf.default_timeout : VLC_TICK_FROM_MS(timeout);
-    worker->conf.pf_hold(task->entity);
-    return task;
-}
-
-static void task_Destroy(struct background_worker *worker, struct task *task)
-{
-    worker->conf.pf_release(task->entity);
-    free(task);
-}
-
-static struct task *QueueTake(struct background_worker *worker, int timeout_ms)
-{
-    vlc_mutex_assert(&worker->lock);
-
-    vlc_tick_t deadline = vlc_tick_now() + VLC_TICK_FROM_MS(timeout_ms);
-    bool timeout = false;
-    while (!timeout && !worker->closing && vlc_list_is_empty(&worker->queue))
-        timeout = vlc_cond_timedwait(&worker->queue_wait,
-                                     &worker->lock, deadline) != 0;
-
-    if (worker->closing || timeout)
-        return NULL;
-
-    struct task *task = vlc_list_first_entry_or_null(&worker->queue,
-                                                     struct task, node);
-    assert(task);
-    vlc_list_remove(&task->node);
-
-    return task;
-}
-
-static void QueuePush(struct background_worker *worker, struct task *task)
-{
-    vlc_mutex_assert(&worker->lock);
-    vlc_list_append(&task->node, &worker->queue);
-    vlc_cond_signal(&worker->queue_wait);
-}
-
-static void QueueRemoveAll(struct background_worker *worker, void *id)
-{
-    vlc_mutex_assert(&worker->lock);
-    struct task *task;
-    vlc_list_foreach(task, &worker->queue, node)
-    {
-        if (!id || task->id == id)
-        {
-            vlc_list_remove(&task->node);
-            task_Destroy(worker, task);
-        }
-    }
-}
-
-static struct background_thread *
-background_thread_Create(struct background_worker *owner)
-{
-    struct background_thread *thread = malloc(sizeof(*thread));
-    if (!thread)
-        return NULL;
-
-    vlc_cond_init(&thread->probe_cancel_wait);
-    thread->probe = false;
-    thread->cancel = false;
-    thread->task = NULL;
-    thread->owner = owner;
-    return thread;
-}
-
-static void background_thread_Destroy(struct background_thread *thread)
-{
-    free(thread);
-}
-
-static struct background_worker *background_worker_Create(void *owner,
-                                         struct background_worker_config *conf)
-{
-    struct background_worker* worker = malloc(sizeof(*worker));
-    if (unlikely(!worker))
-        return NULL;
-
-    worker->conf = *conf;
-    worker->owner = owner;
-
-    vlc_mutex_init(&worker->lock);
-    worker->uncompleted = 0;
-    worker->nthreads = 0;
-    vlc_list_init(&worker->threads);
-    vlc_list_init(&worker->queue);
-    vlc_cond_init(&worker->queue_wait);
-    vlc_cond_init(&worker->nothreads_wait);
-    worker->closing = false;
-    return worker;
-}
-
-static void background_worker_Destroy(struct background_worker *worker)
-{
-    free(worker);
-}
-
-static void TerminateTask(struct background_thread *thread, struct task *task)
-{
-    struct background_worker *worker = thread->owner;
-
-    vlc_mutex_lock(&worker->lock);
-    thread->task = NULL;
-    worker->uncompleted--;
-    assert(worker->uncompleted >= 0);
-    vlc_mutex_unlock(&worker->lock);
-
-    task_Destroy(worker, task);
-}
-
-static void RemoveThread(struct background_thread *thread)
-{
-    struct background_worker *worker = thread->owner;
-
-    vlc_mutex_lock(&worker->lock);
-
-    vlc_list_remove(&thread->node);
-    worker->nthreads--;
-    assert(worker->nthreads >= 0);
-    if (!worker->nthreads)
-        vlc_cond_signal(&worker->nothreads_wait);
-
-    vlc_mutex_unlock(&worker->lock);
-
-    background_thread_Destroy(thread);
-}
-
-static void* Thread( void* data )
-{
-    struct background_thread *thread = data;
-    struct background_worker *worker = thread->owner;
-
-    for (;;)
-    {
-        vlc_mutex_lock(&worker->lock);
-        struct task *task = QueueTake(worker, 5000);
-        if (!task)
-        {
-            vlc_mutex_unlock(&worker->lock);
-            /* terminate this thread */
-            break;
-        }
-
-        thread->task = task;
-        thread->cancel = false;
-        thread->probe = false;
-        vlc_tick_t deadline;
-        if (task->timeout > 0)
-            deadline = vlc_tick_now() + task->timeout;
-        else
-            deadline = INT64_MAX; /* no deadline */
-        vlc_mutex_unlock(&worker->lock);
-
-        void *handle;
-        if (worker->conf.pf_start(worker->owner, task->entity, &handle))
-        {
-            TerminateTask(thread, task);
-            continue;
-        }
-
-        for (;;)
-        {
-            vlc_mutex_lock(&worker->lock);
-            bool timeout = false;
-            while (!timeout && !thread->probe && !thread->cancel)
-                /* any non-zero return value means timeout */
-                timeout = vlc_cond_timedwait(&thread->probe_cancel_wait,
-                                             &worker->lock, deadline) != 0;
-
-            bool cancel = thread->cancel;
-            thread->cancel = false;
-            thread->probe = false;
-            vlc_mutex_unlock(&worker->lock);
-
-            if (timeout || cancel
-                    || worker->conf.pf_probe(worker->owner, handle))
-            {
-                worker->conf.pf_stop(worker->owner, handle);
-                TerminateTask(thread, task);
-                break;
-            }
-        }
-    }
-
-    RemoveThread(thread);
-
-    return NULL;
-}
-
-static bool SpawnThread(struct background_worker *worker)
-{
-    vlc_mutex_assert(&worker->lock);
-
-    struct background_thread *thread = background_thread_Create(worker);
-    if (!thread)
-        return false;
-
-    if (vlc_clone_detach(NULL, Thread, thread, VLC_THREAD_PRIORITY_LOW))
-    {
-        free(thread);
-        return false;
-    }
-    worker->nthreads++;
-    vlc_list_append(&thread->node, &worker->threads);
-
-    return true;
-}
-
-struct background_worker* background_worker_New( void* owner,
-    struct background_worker_config* conf )
-{
-    return background_worker_Create(owner, conf);
-}
-
-int background_worker_Push( struct background_worker* worker, void* entity,
-                        void* id, int timeout )
-{
-    struct task *task = task_Create(worker, id, entity, timeout);
-    if (unlikely(!task))
-        return VLC_ENOMEM;
-
-    vlc_mutex_lock(&worker->lock);
-    QueuePush(worker, task);
-    if (++worker->uncompleted > worker->nthreads
-            && worker->nthreads < worker->conf.max_threads)
-        SpawnThread(worker);
-    vlc_mutex_unlock(&worker->lock);
-
-    return VLC_SUCCESS;
-}
-
-static void BackgroundWorkerCancelLocked(struct background_worker *worker,
-                                         void *id)
-{
-    vlc_mutex_assert(&worker->lock);
-
-    QueueRemoveAll(worker, id);
-
-    struct background_thread *thread;
-    vlc_list_foreach(thread, &worker->threads, node)
-    {
-        if (!id || (thread->task && thread->task->id == id && !thread->cancel))
-        {
-            thread->cancel = true;
-            vlc_cond_signal(&thread->probe_cancel_wait);
-        }
-    }
-}
-
-void background_worker_Cancel( struct background_worker* worker, void* id )
-{
-    vlc_mutex_lock(&worker->lock);
-    BackgroundWorkerCancelLocked(worker, id);
-    vlc_mutex_unlock(&worker->lock);
-}
-
-void background_worker_RequestProbe( struct background_worker* worker )
-{
-    vlc_mutex_lock(&worker->lock);
-
-    struct background_thread *thread;
-    vlc_list_foreach(thread, &worker->threads, node)
-    {
-        thread->probe = true;
-        vlc_cond_signal(&thread->probe_cancel_wait);
-    }
-
-    vlc_mutex_unlock(&worker->lock);
-}
-
-void background_worker_Delete( struct background_worker* worker )
-{
-    vlc_mutex_lock(&worker->lock);
-
-    worker->closing = true;
-    BackgroundWorkerCancelLocked(worker, NULL);
-    /* closing is now true, this will wake up any QueueTake() */
-    vlc_cond_broadcast(&worker->queue_wait);
-
-    while (worker->nthreads)
-        vlc_cond_wait(&worker->nothreads_wait, &worker->lock);
-
-    vlc_mutex_unlock(&worker->lock);
-
-    /* no threads use the worker anymore, we can destroy it */
-    background_worker_Destroy(worker);
-}
diff --git a/src/misc/background_worker.h b/src/misc/background_worker.h
deleted file mode 100644
index abe65159ff..0000000000
--- a/src/misc/background_worker.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*****************************************************************************
- * Copyright (C) 2017 VLC authors and VideoLAN
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-#ifndef BACKGROUND_WORKER_H__
-#define BACKGROUND_WORKER_H__
-
-struct background_worker_config {
-    /**
-     * Default timeout for completing a task
-     *
-     * If less-than 0 a task can run indefinitely without being killed, whereas
-     * a positive value denotes the maximum number of milliseconds a task can
-     * run before \ref pf_stop is called to kill it.
-     **/
-    vlc_tick_t default_timeout;
-
-    /**
-     * Maximum number of threads used to execute tasks.
-     */
-    int max_threads;
-
-    /**
-     * Release an entity
-     *
-     * This callback will be called in order to decrement the ref-count of a
-     * entity within the background-worker. It will happen either when \ref
-     * pf_stop has finished executing, or if the entity is removed from the
-     * queue (through \ref background_worker_Cancel)
-     *
-     * \warning As each task might be executed in parallel by different threads,
-     *          this callback must be thread-safe.
-     *
-     * \param entity the entity to release
-     **/
-    void( *pf_release )( void* entity );
-
-    /**
-     * Hold a queued item
-     *
-     * This callback will be called in order to increment the ref-count of an
-     * entity. It will happen when the entity is pushed into the queue of
-     * pending tasks as part of \ref background_worker_Push.
-     *
-     * \warning As each task might be executed in parallel by different threads,
-     *          this callback must be thread-safe.
-     *
-     * \param entity the entity to hold
-     **/
-    void( *pf_hold )( void* entity );
-
-    /**
-     * Start a new task
-     *
-     * This callback is called in order to construct a new background task. In
-     * order for the background-worker to be able to continue processing
-     * incoming requests, \ref pf_start is meant to start a task (such as a
-     * thread), and then store the associated handle in `*out`.
-     *
-     * The value of `*out` will then be the value of the argument named `handle`
-     * in terms of \ref pf_probe and \ref pf_stop.
-     *
-     * \warning As each task might be executed in parallel by different threads,
-     *          this callback must be thread-safe.
-     *
-     * \param owner the owner of the background-worker
-     * \param entity the entity for which a task is to be created
-     * \param out [out] `*out` shall, on success, refer to the handle associated
-     *                   with the running task.
-     * \return VLC_SUCCESS if a task was created, an error-code on failure.
-     **/
-    int( *pf_start )( void* owner, void* entity, void** out );
-
-    /**
-     * Probe a running task
-     *
-     * This callback is called in order to see whether or not a running task has
-     * finished or not. It can be called anytime between a successful call to
-     * \ref pf_start, and the corresponding call to \ref pf_stop.
-     *
-     * \warning As each task might be executed in parallel by different threads,
-     *          this callback must be thread-safe.
-     *
-     * \param owner the owner of the background-worker
-     * \param handle the handle associated with the running task
-     * \return 0 if the task is still running, any other value if finished.
-     **/
-    int( *pf_probe )( void* owner, void* handle );
-
-    /**
-     * Stop a running task
-     *
-     * This callback is called in order to stop a running task. If \ref pf_start
-     * has created a non-detached thread, \ref pf_stop is where you would
-     * interrupt and then join it.
-     *
-     * \warning This function is called either after \ref pf_probe has stated
-     *          that the task has finished, or if the timeout (if any) for the
-     *          task has been reached.
-     *
-     * \warning As each task might be executed in parallel by different threads,
-     *          this callback must be thread-safe.
-     *
-     * \param owner the owner of the background-worker
-     * \parma handle the handle associated with the task to be stopped
-     **/
-    void( *pf_stop )( void* owner, void* handle );
-};
-
-/**
- * Create a background-worker
- *
- * This function creates a new background-worker using the passed configuration.
- *
- * \warning all members of `config` shall have been set by the caller.
- * \warning the returned resource must be destroyed using \ref
- *          background_worker_Delete on success.
- *
- * \param owner the owner of the background-worker
- * \param config the background-worker's configuration
- * \return a pointer-to the created background-worker on success,
- *         `NULL` on failure.
- **/
-struct background_worker* background_worker_New( void* owner,
-    struct background_worker_config* config );
-
-/**
- * Request the background-worker to probe the current task
- *
- * This function is used to signal the background-worker that it should do
- * another probe to see whether the current task is still alive.
- *
- * \warning Note that the function will not wait for the probing to finish, it
- *          will simply ask the background worker to recheck it as soon as
- *          possible.
- *
- * \param worker the background-worker
- **/
-void background_worker_RequestProbe( struct background_worker* worker );
-
-/**
- * Push an entity into the background-worker
- *
- * This function is used to push an entity into the queue of pending work. The
- * entities will be processed in the order in which they are received (in terms
- * of the order of invocations in a single-threaded environment).
- *
- * \param worker the background-worker
- * \param entity the entity which is to be queued
- * \param id a value suitable for identifying the entity, or `NULL`
- * \param timeout the timeout of the entity in milliseconds, `0` denotes no
- *                timeout, a negative value will use the default timeout
- *                associated with the background-worker.
- * \return VLC_SUCCESS if the entity was successfully queued, an error-code on
- *         failure.
- **/
-int background_worker_Push( struct background_worker* worker, void* entity,
-    void* id, int timeout );
-
-/**
- * Remove entities from the background-worker
- *
- * This function is used to remove processing of a certain entity given its
- * associated id, or to remove all queued (including currently running)
- * entities.
- *
- * \warning if the `id` passed refers to an entity that is currently being
- *          processed, the call will block until the task has been terminated.
- *
- * \param worker the background-worker
- * \param id NULL if every entity shall be removed, and the currently running
- *        task (if any) shall be cancelled.
- **/
-void background_worker_Cancel( struct background_worker* worker, void* id );
-
-/**
- * Delete a background-worker
- *
- * This function will destroy a background-worker created through \ref
- * background_worker_New. It will effectively stop the currently running task,
- * if any, and empty the queue of pending entities.
- *
- * \warning If there is a currently running task, the function will block until
- *          it has been stopped.
- *
- * \param worker the background-worker
- **/
-void background_worker_Delete( struct background_worker* worker );
-#endif
-- 
2.28.0



More information about the vlc-devel mailing list