[vlc-devel] [PATCH 1/7] playlist/background_worker: introduce background-worker utility
Filip Roséen
filip at atch.se
Wed Mar 22 17:58:41 CET 2017
The primary reason for this helper utility is to allow for the
preparser and {meta,art}-fetcher to share a common backbone as they
both deal with a queue of entities that are to be processed one-by-one
in the background.
By using struct background_worker in the preparser and fetcher we will
prevent code duplication, while also allowing for easier maintenence in
the future (such as allowing for concurrently running tasks within a
single queue).
---
src/Makefile.am | 2 +
src/playlist/misc/background_worker.c | 192 ++++++++++++++++++++++++++++++++++
src/playlist/misc/background_worker.h | 62 +++++++++++
3 files changed, 256 insertions(+)
create mode 100644 src/playlist/misc/background_worker.c
create mode 100644 src/playlist/misc/background_worker.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 1e0e70fa86..2aa8891026 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -220,6 +220,8 @@ libvlccore_la_SOURCES = \
playlist/fetcher.h \
playlist/sort.c \
playlist/loadsave.c \
+ playlist/misc/background_worker.c \
+ playlist/misc/background_worker.h \
playlist/preparser.c \
playlist/preparser.h \
playlist/tree.c \
diff --git a/src/playlist/misc/background_worker.c b/src/playlist/misc/background_worker.c
new file mode 100644
index 0000000000..0c6041e6ef
--- /dev/null
+++ b/src/playlist/misc/background_worker.c
@@ -0,0 +1,192 @@
+/*****************************************************************************
+ * 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 <vlc_common.h>
+#include <vlc_threads.h>
+#include <vlc_arrays.h>
+
+#include "libvlc.h"
+#include "background_worker.h"
+
+static void* Thread( void* data )
+{
+ struct background_worker* worker = data;
+ struct background_worker_private* priv = &worker->p;
+
+ vlc_mutex_lock( &priv->lock );
+ for( ;; )
+ {
+ vlc_cond_broadcast( &priv->wait );
+
+ if( priv->current.handle == NULL )
+ {
+ if( vlc_array_count( &priv->queue ) == 0 )
+ break;
+
+ struct background_worker_item* item =
+ vlc_array_item_at_index( &priv->queue, 0 );
+
+ void* handle;
+ if( !worker->pf_start( priv->owner, item->entity, &handle ) )
+ {
+ priv->current.item = item;
+ priv->current.handle = handle;
+ priv->current.deadline = item->timeout > VLC_TS_INVALID
+ ? mdate() + item->timeout : INT64_MAX;
+ }
+
+ vlc_array_remove( &priv->queue, 0 );
+ continue;
+ }
+
+ for( ;; )
+ {
+ bool const b_timeout = priv->current.deadline < mdate();
+
+ vlc_mutex_unlock( &priv->lock );
+
+ if( b_timeout ||
+ worker->pf_probe( priv->owner, priv->current.handle ) )
+ {
+ worker->pf_stop( priv->owner, priv->current.handle );
+ worker->pf_release( priv->current.item->entity );
+
+ vlc_mutex_lock( &priv->lock );
+ break;
+ }
+
+ vlc_mutex_lock( &priv->lock );
+ vlc_cond_timedwait( &priv->wait, &priv->lock,
+ priv->current.deadline );
+ }
+
+ priv->current.item = NULL;
+ priv->current.handle = NULL;
+ }
+
+ priv->active = false;
+ vlc_mutex_unlock( &priv->lock );
+ return NULL;
+}
+
+static void BackgroundWorkerCancel( struct background_worker* worker, void* id)
+{
+ struct background_worker_private* priv = &worker->p;
+
+ vlc_mutex_lock( &priv->lock );
+ for( size_t i = 0; i < vlc_array_count( &priv->queue ); )
+ {
+ struct background_worker_item* item =
+ vlc_array_item_at_index( &priv->queue, i );
+
+ if( id == NULL || item->id == id )
+ {
+ vlc_array_remove( &priv->queue, i );
+ worker->pf_release( item->entity );
+ free( item );
+ continue;
+ }
+
+ ++i;
+ }
+
+ if( ( id && priv->current.item && priv->current.item->id == id ) ||
+ ( id == NULL && priv->active ) )
+ {
+ priv->current.deadline = VLC_TS_0;
+ vlc_cond_broadcast( &priv->wait );
+
+ while( ( id && priv->current.item && priv->current.item->id == id ) ||
+ ( id == NULL && priv->active ) )
+ {
+ vlc_cond_wait( &priv->wait, &priv->lock );
+ }
+ }
+ vlc_mutex_unlock( &priv->lock );
+}
+
+void background_worker_Init( struct background_worker* worker, void* owner,
+ int timeout )
+{
+ worker->p.default_timeout = timeout > 0 ? timeout*1000 : VLC_TS_INVALID;
+ worker->p.current.handle = NULL;
+ worker->p.current.item = NULL;
+ worker->p.active = false;
+ worker->p.owner = owner;
+
+ vlc_array_init( &worker->p.queue );
+ vlc_mutex_init( &worker->p.lock );
+ vlc_cond_init( &worker->p.wait );
+}
+
+int background_worker_Push( struct background_worker* worker, void* entity,
+ void* id, int timeout )
+{
+ struct background_worker_item* item = malloc( sizeof( *item ) );
+ struct background_worker_private* priv = &worker->p;
+
+ if( unlikely( !item ) )
+ return VLC_EGENERIC;
+
+ item->id = id;
+ item->entity = entity;
+ item->timeout = timeout > 0 ? timeout*1000 : worker->p.default_timeout;
+
+ vlc_mutex_lock( &worker->p.lock );
+ vlc_array_append( &worker->p.queue, item );
+
+ if( !worker->p.active &&
+ vlc_clone_detach( NULL, Thread, worker, VLC_THREAD_PRIORITY_LOW ) )
+ {
+ vlc_mutex_unlock( &priv->lock );
+ return VLC_EGENERIC;
+ }
+
+ worker->p.active = true;
+ worker->pf_hold( item->entity );
+ vlc_mutex_unlock( &priv->lock );
+
+ return VLC_SUCCESS;
+}
+
+void background_worker_Cancel( struct background_worker* worker, void* id )
+{
+ BackgroundWorkerCancel( worker, id );
+}
+
+void background_worker_Signal( struct background_worker* worker )
+{
+ struct background_worker_private* priv = &worker->p;
+
+ vlc_mutex_lock( &priv->lock );
+ vlc_cond_broadcast( &priv->wait );
+ vlc_mutex_unlock( &priv->lock );
+}
+
+void background_worker_Clean( struct background_worker* worker )
+{
+ BackgroundWorkerCancel( worker, NULL );
+
+ vlc_array_clear( &worker->p.queue );
+ vlc_cond_destroy( &worker->p.wait );
+ vlc_mutex_destroy( &worker->p.lock );
+}
diff --git a/src/playlist/misc/background_worker.h b/src/playlist/misc/background_worker.h
new file mode 100644
index 0000000000..3d78d63468
--- /dev/null
+++ b/src/playlist/misc/background_worker.h
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ * 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_item {
+ void* id;
+ void* entity;
+ int timeout;
+};
+
+struct background_worker_private {
+ void* owner;
+ int default_timeout;
+
+ vlc_mutex_t lock;
+ vlc_cond_t wait;
+
+ struct {
+ void* handle;
+ mtime_t deadline;
+ struct background_worker_item* item;
+ } current;
+
+ bool active;
+ vlc_array_t queue;
+};
+
+struct background_worker {
+ void( *pf_release )( void* );
+ void( *pf_hold )( void* );
+
+ int( *pf_start )( void* owner, void* item, void** out );
+ int( *pf_probe )( void* owner, void* handle );
+ void( *pf_stop )( void* owner, void* handle );
+
+ struct background_worker_private p;
+};
+
+void background_worker_Init( struct background_worker* worker, void* owner, int timeout );
+void background_worker_Cancel( struct background_worker* worker, void* id );
+void background_worker_Signal( struct background_worker* worker );
+void background_worker_Clean( struct background_worker* worker );
+int background_worker_Push( struct background_worker* worker, void* entity, void* id, int timeout );
+
+#endif
--
2.12.0
More information about the vlc-devel
mailing list