default:
msg_Err( p_playlist, "unknown playlist query" );
return VLC_EBADVAR;
- break;
}
vlc_object_signal_unlocked( p_playlist );
int playlist_PreparseEnqueue( playlist_t *p_playlist,
input_item_t *p_item )
{
- vlc_object_lock( p_playlist->p->p_preparse );
- if( !vlc_object_alive( p_playlist->p->p_preparse ) )
- {
- vlc_object_unlock( p_playlist->p->p_preparse );
- return VLC_EGENERIC;
- }
+ playlist_preparse_t *p_preparse = &p_playlist->p->preparse;
+
vlc_gc_incref( p_item );
- INSERT_ELEM( p_playlist->p->p_preparse->pp_waiting,
- p_playlist->p->p_preparse->i_waiting,
- p_playlist->p->p_preparse->i_waiting,
- p_item );
- vlc_object_signal_unlocked( p_playlist->p->p_preparse );
- vlc_object_unlock( p_playlist->p->p_preparse );
+
+ vlc_mutex_lock( &p_preparse->lock );
+ INSERT_ELEM( p_preparse->pp_waiting, p_preparse->i_waiting,
+ p_preparse->i_waiting, p_item );
+ vlc_cond_signal( &p_preparse->wait );
+ vlc_mutex_unlock( &p_preparse->lock );
return VLC_SUCCESS;
}
-/** Enqueue a playlist item or a node for peparsing.
- * This function should be entered without playlist and preparser locks */
+/** Enqueue a playlist item or a node for preparsing.
+ * This function shall be called without playlist and preparser locks */
int playlist_PreparseEnqueueItem( playlist_t *p_playlist,
playlist_item_t *p_item )
{
+ playlist_preparse_t *p_preparse = &p_playlist->p->preparse;
+
vlc_object_lock( p_playlist );
- vlc_object_lock( p_playlist->p->p_preparse );
- if( !vlc_object_alive( p_playlist->p->p_preparse ) )
- {
- vlc_object_unlock( p_playlist->p->p_preparse );
- vlc_object_unlock( p_playlist );
- return VLC_EGENERIC;
- }
+ vlc_mutex_lock( &p_preparse->lock );
PreparseEnqueueItemSub( p_playlist, p_item );
- vlc_object_unlock( p_playlist->p->p_preparse );
+ vlc_mutex_unlock( &p_preparse->lock );
vlc_object_unlock( p_playlist );
return VLC_SUCCESS;
}
static void PreparseEnqueueItemSub( playlist_t *p_playlist,
playlist_item_t *p_item )
{
- int i;
+ playlist_preparse_t *p_preparse = &p_playlist->p->preparse;
+
if( p_item->i_children == -1 )
{
+ /* Leaf item */
vlc_gc_incref( p_item->p_input );
- INSERT_ELEM( p_playlist->p->p_preparse->pp_waiting,
- p_playlist->p->p_preparse->i_waiting,
- p_playlist->p->p_preparse->i_waiting,
+ INSERT_ELEM( p_preparse->pp_waiting,
+ p_preparse->i_waiting,
+ p_preparse->i_waiting,
p_item->p_input );
}
else
{
- for( i = 0; i < p_item->i_children; i++)
+ /* Non-leaf item: recurse */
+ for( int i = 0; i < p_item->i_children; i++)
{
PreparseEnqueueItemSub( p_playlist, p_item->pp_children[i] );
}
# include "config.h"
#endif
+#include <stddef.h>
#include <assert.h>
#include <vlc_common.h>
#include <vlc_sout.h>
VariablesInit( p_playlist );
/* Initialise data structures */
+ p_playlist->p->p_playlist = p_playlist;
p_playlist->i_last_playlist_id = 0;
p_playlist->p_input = NULL;
static void playlist_Destructor( vlc_object_t * p_this )
{
playlist_t * p_playlist = (playlist_t *)p_this;
+ playlist_preparse_t *p_preparse = &p_playlist->p->preparse;
- if( p_playlist->p->p_preparse )
+ /* Destroy the item preparser */
+ if (p_preparse->up)
{
- vlc_object_release( p_playlist->p->p_preparse );
+ vlc_cancel (p_preparse->thread);
+ vlc_join (p_preparse->thread, NULL);
}
+ while (p_preparse->i_waiting > 0)
+ { /* Any left-over unparsed item? */
+ vlc_gc_decref (p_preparse->pp_waiting[0]);
+ REMOVE_ELEM (p_preparse->pp_waiting, p_preparse->i_waiting, 0);
+ }
+ vlc_cond_destroy (&p_preparse->wait);
+ vlc_mutex_destroy (&p_preparse->lock);
+ /* Destroy the item meta-infos fetcher */
if( p_playlist->p->p_fetcher )
{
vlc_object_release( p_playlist->p->p_fetcher );
playlist_ServicesDiscoveryKillAll( p_playlist );
playlist_MLDump( p_playlist );
- vlc_object_kill( p_playlist->p->p_preparse );
- vlc_thread_join( p_playlist->p->p_preparse );
vlc_object_kill( p_playlist->p->p_fetcher );
vlc_thread_join( p_playlist->p->p_fetcher );
}
/**
- * Preparse loop
+ * Preparse queue loop
*
- * Main loop for preparser queue
- * \param p_obj items to preparse
- * \return nothing
+ * @param p_obj preparse structure
+ * @return never
*/
-void playlist_PreparseLoop( playlist_preparse_t *p_obj )
+void *playlist_PreparseLoop( void *data )
{
- playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
- input_item_t *p_current;
+ playlist_preparse_t *p_preparse = data;
+ playlist_t *p_playlist = ((playlist_private_t *)(((char *)p_preparse)
+ - offsetof(playlist_private_t, preparse)))->p_playlist;
int i_activity;
- vlc_object_lock( p_obj );
-
- while( vlc_object_alive( p_obj ) )
+ for( ;; )
{
- if( p_obj->i_waiting == 0 )
- {
- vlc_object_wait( p_obj );
- continue;
- }
+ input_item_t *p_current;
- p_current = p_obj->pp_waiting[0];
- REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 );
- vlc_object_unlock( p_obj );
+ vlc_mutex_lock( &p_preparse->lock );
+ mutex_cleanup_push( &p_preparse->lock );
+
+ while( p_preparse->i_waiting == 0 )
+ vlc_cond_wait( &p_preparse->wait, &p_preparse->lock );
+
+ p_current = p_preparse->pp_waiting[0];
+ REMOVE_ELEM( p_preparse->pp_waiting, p_preparse->i_waiting, 0 );
+ vlc_cleanup_run( );
- PL_LOCK;
if( p_current )
{
+ int canc = vlc_savecancel ();
+ PL_LOCK;
if( p_current->i_type == ITEM_TYPE_FILE )
{
stats_TimerStart( p_playlist, "Preparse run",
}
free( psz_name );
free( psz_arturl );
- PL_UNLOCK;
+ PL_UNLOCK;
+ vlc_restorecancel( canc );
}
- else
- PL_UNLOCK;
- vlc_object_lock( p_obj );
i_activity = var_GetInteger( p_playlist, "activity" );
if( i_activity < 0 ) i_activity = 0;
- vlc_object_unlock( p_obj );
/* Sleep at least 1ms */
msleep( (i_activity+1) * 1000 );
- vlc_object_lock( p_obj );
}
- while( p_obj->i_waiting > 0 )
- {
- vlc_gc_decref( p_obj->pp_waiting[0] );
- REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 );
- }
-
- vlc_object_unlock( p_obj );
+ assert( 0 );
+ return NULL;
}
/**
/*****************************************************************************
- * playlist_internal.h : Functions for use by the playlist
+ * playlist_internal.h : Playlist internals
*****************************************************************************
- * Copyright (C) 1999-2004 the VideoLAN team
+ * Copyright (C) 1999-2008 the VideoLAN team
* $Id$
*
* Authors: Samuel Hocevar <sam@zoy.org>
typedef struct playlist_preparse_t
{
- VLC_COMMON_MEMBERS
+ vlc_thread_t thread;
vlc_mutex_t lock;
- int i_waiting;
+ vlc_cond_t wait;
input_item_t **pp_waiting;
+ int i_waiting;
+ bool up;
} playlist_preparse_t;
typedef struct playlist_fetcher_t
struct playlist_private_t
{
- playlist_preparse_t *p_preparse; /**< Preparser object */
+ playlist_t *p_playlist; /**< Public data */
+ playlist_preparse_t preparse; /**< Preparser data */
playlist_fetcher_t *p_fetcher; /**< Meta and art fetcher object */
sout_instance_t *p_sout; /**< Kept sout instance */
};
/* Engine */
void playlist_MainLoop( playlist_t * );
void playlist_LastLoop( playlist_t * );
-void playlist_PreparseLoop( playlist_preparse_t * );
+void *playlist_PreparseLoop( void * );
void playlist_FetcherLoop( playlist_fetcher_t * );
void ResetCurrentlyPlaying( playlist_t *, bool, playlist_item_t * );
* Local prototypes
*****************************************************************************/
static void* RunControlThread ( vlc_object_t * );
-static void* RunPreparse ( vlc_object_t * );
static void* RunFetcher ( vlc_object_t * );
-static void PreparseDestructor ( vlc_object_t * );
static void FetcherDestructor ( vlc_object_t * );
/*****************************************************************************
if( !p_playlist ) return;
// Preparse
- static const char ppname[] = "preparser";
- p_playlist->p->p_preparse =
- vlc_custom_create( p_playlist, sizeof( playlist_preparse_t ),
- VLC_OBJECT_GENERIC, ppname );
- if( !p_playlist->p->p_preparse )
- {
- msg_Err( p_playlist, "unable to create preparser" );
- vlc_object_release( p_playlist );
- return;
- }
- p_playlist->p->p_preparse->i_waiting = 0;
- p_playlist->p->p_preparse->pp_waiting = NULL;
-
- vlc_object_set_destructor( p_playlist->p->p_preparse, PreparseDestructor );
-
- vlc_object_attach( p_playlist->p->p_preparse, p_playlist );
- if( vlc_thread_create( p_playlist->p->p_preparse, "preparser",
- RunPreparse, VLC_THREAD_PRIORITY_LOW, false ) )
+ playlist_preparse_t *p_preparse = &p_playlist->p->preparse;
+ vlc_mutex_init (&p_preparse->lock);
+ vlc_cond_init (&p_preparse->wait);
+ p_preparse->i_waiting = 0;
+ p_preparse->pp_waiting = NULL;
+
+ if( vlc_clone( &p_preparse->thread, playlist_PreparseLoop, p_preparse,
+ VLC_THREAD_PRIORITY_LOW ) )
{
msg_Err( p_playlist, "cannot spawn preparse thread" );
- vlc_object_release( p_playlist->p->p_preparse );
+ p_preparse->up = false;
return;
}
+ p_preparse->up = true;
// Secondary Preparse
static const char fname[] = "fetcher";
return NULL;
}
-/*****************************************************************************
- * Preparse-specific functions
- *****************************************************************************/
-static void* RunPreparse ( vlc_object_t *p_this )
-{
- playlist_preparse_t *p_obj = (playlist_preparse_t*)p_this;
- int canc;
-
- canc = vlc_savecancel ();
- playlist_PreparseLoop( p_obj );
- vlc_restorecancel (canc);
- return NULL;
-}
-
static void* RunFetcher( vlc_object_t *p_this )
{
playlist_fetcher_t *p_obj = (playlist_fetcher_t *)p_this;
return NULL;
}
-static void PreparseDestructor( vlc_object_t * p_this )
-{
- playlist_preparse_t * p_preparse = (playlist_preparse_t *)p_this;
- free( p_preparse->pp_waiting );
- msg_Dbg( p_this, "Destroyed" );
-}
-
static void FetcherDestructor( vlc_object_t * p_this )
{
playlist_fetcher_t * p_fetcher = (playlist_fetcher_t *)p_this;