Commit 80684e78 authored by Laurent Aimar's avatar Laurent Aimar

Fixed a race condition with input creation and events.

input_CreateThread* have been splitted in two functions:
 - input_Create
 - input_Start
to allow attaching to input events and creating settings/variables
before starting the input thread.

For consistency, input_StopThread has been renamed input_Stop.

Initial report from Hugo Beauzee-Luyssen.
parent a135b02f
...@@ -248,14 +248,16 @@ static inline void vlc_input_attachment_Delete( input_attachment_t *a ) ...@@ -248,14 +248,16 @@ static inline void vlc_input_attachment_Delete( input_attachment_t *a )
#define INPUT_UPDATE_META 0x0040 #define INPUT_UPDATE_META 0x0040
#define INPUT_UPDATE_SIGNAL 0x0080 #define INPUT_UPDATE_SIGNAL 0x0080
/** Get the input item for an input thread /**
* FIXME see src/input/item.c but is is unsafe unless * This defines private core storage for an input.
* you hold p_input
*/ */
VLC_EXPORT(input_item_t*, input_GetItem, (input_thread_t*));
typedef struct input_thread_private_t input_thread_private_t; typedef struct input_thread_private_t input_thread_private_t;
/**
* This defines an opaque input resource handler.
*/
typedef struct input_resource_t input_resource_t;
/** /**
* Main structure representing an input thread. This structure is mostly * Main structure representing an input thread. This structure is mostly
* private. The only public fields are READ-ONLY. You must use the helpers * private. The only public fields are READ-ONLY. You must use the helpers
...@@ -431,32 +433,9 @@ typedef enum input_event_type_e ...@@ -431,32 +433,9 @@ typedef enum input_event_type_e
} input_event_type_e; } input_event_type_e;
/** @}*/
/*****************************************************************************
* Prototypes
*****************************************************************************/
/** /**
* It will create a new input thread. * Input queries
*
* You must call input_StopThread() on it and then vlc_object_release().
*/ */
#define input_CreateThread(a,b) __input_CreateThread(VLC_OBJECT(a),b)
VLC_EXPORT( input_thread_t *, __input_CreateThread, ( vlc_object_t *, input_item_t * ) );
/**
* It will ask a input_thread_t to stop.
*
* b_abort must be true when a user stop is requested and not because you have
* detected an error or an eof. It will be used to properly send the
* INPUT_EVENT_ABORT event.
*/
VLC_EXPORT( void, input_StopThread, ( input_thread_t *, bool b_abort ) );
#define input_Read(a,b,c) __input_Read(VLC_OBJECT(a),b, c)
VLC_EXPORT( int, __input_Read, ( vlc_object_t *, input_item_t *, bool ) );
enum input_query_e enum input_query_e
{ {
/* input variable "position" */ /* input variable "position" */
...@@ -526,9 +505,37 @@ enum input_query_e ...@@ -526,9 +505,37 @@ enum input_query_e
INPUT_GET_VOUTS, /* arg1=vout_thread_t ***, int * res=can fail */ INPUT_GET_VOUTS, /* arg1=vout_thread_t ***, int * res=can fail */
}; };
/** @}*/
/*****************************************************************************
* Prototypes
*****************************************************************************/
#define input_Create(a,b,c,d) __input_Create(VLC_OBJECT(a),b,c,d)
VLC_EXPORT( input_thread_t *, __input_Create, ( vlc_object_t *p_parent, input_item_t *, const char *psz_log, input_resource_t * ) );
#define input_CreateAndStart(a,b,c) __input_CreateAndStart(VLC_OBJECT(a),b,c)
VLC_EXPORT( input_thread_t *, __input_CreateAndStart, ( vlc_object_t *p_parent, input_item_t *, const char *psz_log ) );
VLC_EXPORT( int, input_Start, ( input_thread_t * ) );
VLC_EXPORT( void, input_Stop, ( input_thread_t *, bool b_abort ) );
#define input_Read(a,b,c) __input_Read(VLC_OBJECT(a),b, c)
VLC_EXPORT( int, __input_Read, ( vlc_object_t *, input_item_t *, bool ) );
VLC_EXPORT( int, input_vaControl,( input_thread_t *, int i_query, va_list ) ); VLC_EXPORT( int, input_vaControl,( input_thread_t *, int i_query, va_list ) );
VLC_EXPORT( int, input_Control, ( input_thread_t *, int i_query, ... ) ); VLC_EXPORT( int, input_Control, ( input_thread_t *, int i_query, ... ) );
/**
* Get the input item for an input thread
*
* You have to keep a reference to the input or to the input_item_t until
* you do not need it anymore.
*/
VLC_EXPORT( input_item_t*, input_GetItem, ( input_thread_t * ) );
/** /**
* It will return the current state of the input. * It will return the current state of the input.
* Provided for convenience. * Provided for convenience.
...@@ -567,7 +574,7 @@ static inline vout_thread_t *input_GetVout( input_thread_t *p_input ) ...@@ -567,7 +574,7 @@ static inline vout_thread_t *input_GetVout( input_thread_t *p_input )
vlc_object_release( (vlc_object_t *)(pp_vout[i]) ); vlc_object_release( (vlc_object_t *)(pp_vout[i]) );
p_vout = (i_vout >= 1) ? pp_vout[0] : NULL; p_vout = (i_vout >= 1) ? pp_vout[0] : NULL;
free (pp_vout); free( pp_vout );
return p_vout; return p_vout;
} }
......
...@@ -159,13 +159,16 @@ static void Close( vlc_object_t *p_this ) ...@@ -159,13 +159,16 @@ static void Close( vlc_object_t *p_this )
for( i = 0; i < p_sys->i_input; i++ ) for( i = 0; i < p_sys->i_input; i++ )
{ {
if( p_sd->p_sys->pp_input[i] ) input_thread_t *p_input = p_sd->p_sys->pp_input[i];
{ if( !p_input )
input_StopThread( p_sd->p_sys->pp_input[i], true ); continue;
vlc_object_release( p_sd->p_sys->pp_input[i] );
input_Stop( p_input, true );
vlc_thread_join( p_input );
vlc_object_release( p_input );
p_sd->p_sys->pp_input[i] = NULL; p_sd->p_sys->pp_input[i] = NULL;
} }
}
free( p_sd->p_sys->pp_input ); free( p_sd->p_sys->pp_input );
for( i = 0; i < p_sys->i_urls; i++ ) free( p_sys->ppsz_urls[i] ); for( i = 0; i < p_sys->i_urls; i++ ) free( p_sys->ppsz_urls[i] );
free( p_sys->ppsz_urls ); free( p_sys->ppsz_urls );
...@@ -197,11 +200,14 @@ static void *Run( void *data ) ...@@ -197,11 +200,14 @@ static void *Run( void *data )
for( int i = 0; i < p_sd->p_sys->i_input; i++ ) for( int i = 0; i < p_sd->p_sys->i_input; i++ )
{ {
if( p_sd->p_sys->pp_input[i]->b_eof input_thread_t *p_input = p_sd->p_sys->pp_input[i];
|| p_sd->p_sys->pp_input[i]->b_error )
if( p_input->b_eof || p_input->b_error )
{ {
input_StopThread( p_sd->p_sys->pp_input[i], false ); input_Stop( p_input, false );
vlc_object_release( p_sd->p_sys->pp_input[i] ); vlc_thread_join( p_input );
vlc_object_release( p_input );
p_sd->p_sys->pp_input[i] = NULL; p_sd->p_sys->pp_input[i] = NULL;
REMOVE_ELEM( p_sys->pp_input, p_sys->i_input, i ); REMOVE_ELEM( p_sys->pp_input, p_sys->i_input, i );
i--; i--;
...@@ -253,7 +259,7 @@ static void ParseUrls( services_discovery_t *p_sd, char *psz_urls ) ...@@ -253,7 +259,7 @@ static void ParseUrls( services_discovery_t *p_sd, char *psz_urls )
services_discovery_AddItem( p_sd, p_input, NULL /* no cat */ ); services_discovery_AddItem( p_sd, p_input, NULL /* no cat */ );
vlc_gc_decref( p_input ); vlc_gc_decref( p_input );
INSERT_ELEM( p_sys->pp_input, p_sys->i_input, p_sys->i_input, INSERT_ELEM( p_sys->pp_input, p_sys->i_input, p_sys->i_input,
input_CreateThread( p_sd, p_input ) ); input_CreateAndStart( p_sd, p_input, NULL ) );
} }
if( psz_tok ) psz_urls = psz_tok+1; if( psz_tok ) psz_urls = psz_tok+1;
else return; else return;
......
...@@ -89,7 +89,7 @@ static void release_input_thread( libvlc_media_player_t *p_mi, bool b_input_abor ...@@ -89,7 +89,7 @@ static void release_input_thread( libvlc_media_player_t *p_mi, bool b_input_abor
input_event_changed, p_mi ); input_event_changed, p_mi );
/* We owned this one */ /* We owned this one */
input_StopThread( p_input_thread, b_input_abort ); input_Stop( p_input_thread, b_input_abort );
vlc_thread_join( p_input_thread ); vlc_thread_join( p_input_thread );
var_Destroy( p_input_thread, "drawable-hwnd" ); var_Destroy( p_input_thread, "drawable-hwnd" );
...@@ -606,8 +606,8 @@ void libvlc_media_player_play( libvlc_media_player_t *p_mi, ...@@ -606,8 +606,8 @@ void libvlc_media_player_play( libvlc_media_player_t *p_mi,
return; return;
} }
p_mi->p_input_thread = input_CreateThread( p_mi->p_input_thread = input_Create( p_mi->p_libvlc_instance->p_libvlc_int,
p_mi->p_libvlc_instance->p_libvlc_int, p_mi->p_md->p_input_item ); p_mi->p_md->p_input_item, NULL, NULL );
if( !p_mi->p_input_thread ) if( !p_mi->p_input_thread )
{ {
...@@ -643,6 +643,12 @@ void libvlc_media_player_play( libvlc_media_player_t *p_mi, ...@@ -643,6 +643,12 @@ void libvlc_media_player_play( libvlc_media_player_t *p_mi,
var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi ); var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi ); var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
if( input_Start( p_input_thread ) )
{
vlc_object_release( p_input_thread );
p_mi->p_input_thread = NULL;
}
vlc_mutex_unlock( &p_mi->object_lock ); vlc_mutex_unlock( &p_mi->object_lock );
} }
...@@ -717,7 +723,7 @@ void libvlc_media_player_stop( libvlc_media_player_t *p_mi, ...@@ -717,7 +723,7 @@ void libvlc_media_player_stop( libvlc_media_player_t *p_mi,
if( !p_input_thread ) if( !p_input_thread )
return; return;
input_StopThread( p_input_thread, true ); input_Stop( p_input_thread, true );
vlc_object_release( p_input_thread ); vlc_object_release( p_input_thread );
p_mi->p_input_thread = NULL; p_mi->p_input_thread = NULL;
} }
......
This diff is collapsed.
...@@ -46,11 +46,6 @@ int input_Preparse( vlc_object_t *, input_item_t * ); ...@@ -46,11 +46,6 @@ int input_Preparse( vlc_object_t *, input_item_t * );
* FIXME it should NOT be defined here or not coded in misc/stats.c */ * FIXME it should NOT be defined here or not coded in misc/stats.c */
input_stats_t *stats_NewInputStats( input_thread_t *p_input ); input_stats_t *stats_NewInputStats( input_thread_t *p_input );
/**
* This defines an opaque input resource handler.
*/
typedef struct input_resource_t input_resource_t;
/** /**
* This function releases an input_resource_t and all associated resources. * This function releases an input_resource_t and all associated resources.
*/ */
...@@ -74,8 +69,6 @@ void input_resource_TerminateVout( input_resource_t *p_resource ); ...@@ -74,8 +69,6 @@ void input_resource_TerminateVout( input_resource_t *p_resource );
bool input_resource_HasVout( input_resource_t *p_resource ); bool input_resource_HasVout( input_resource_t *p_resource );
/* input.c */ /* input.c */
#define input_CreateThreadExtended(a,b,c,d) __input_CreateThreadExtended(VLC_OBJECT(a),b,c,d)
input_thread_t *__input_CreateThreadExtended ( vlc_object_t *, input_item_t *, const char *, input_resource_t * );
/** /**
* This function detaches resources from a dead input. * This function detaches resources from a dead input.
......
...@@ -531,12 +531,12 @@ static int vlm_OnMediaUpdate( vlm_t *p_vlm, vlm_media_sys_t *p_media ) ...@@ -531,12 +531,12 @@ static int vlm_OnMediaUpdate( vlm_t *p_vlm, vlm_media_sys_t *p_media )
if( asprintf( &psz_header, _("Media: %s"), p_cfg->psz_name ) == -1 ) if( asprintf( &psz_header, _("Media: %s"), p_cfg->psz_name ) == -1 )
psz_header = NULL; psz_header = NULL;
if( (p_input = input_CreateThreadExtended( p_vlm->p_libvlc, p_media->vod.p_item, psz_header, NULL ) ) ) if( (p_input = input_CreateAndStart( p_vlm->p_libvlc, p_media->vod.p_item, psz_header ) ) )
{ {
while( !p_input->b_eof && !p_input->b_error ) while( !p_input->b_eof && !p_input->b_error )
msleep( 100000 ); msleep( 100000 );
input_StopThread( p_input, false ); input_Stop( p_input, false );
vlc_thread_join( p_input ); vlc_thread_join( p_input );
vlc_object_release( p_input ); vlc_object_release( p_input );
} }
...@@ -778,7 +778,7 @@ static void vlm_MediaInstanceDelete( vlm_t *p_vlm, int64_t id, vlm_media_instanc ...@@ -778,7 +778,7 @@ static void vlm_MediaInstanceDelete( vlm_t *p_vlm, int64_t id, vlm_media_instanc
{ {
input_resource_t *p_resource; input_resource_t *p_resource;
input_StopThread( p_input, true ); input_Stop( p_input, true );
vlc_thread_join( p_input ); vlc_thread_join( p_input );
p_resource = input_DetachResource( p_input ); p_resource = input_DetachResource( p_input );
...@@ -861,7 +861,7 @@ static int vlm_ControlMediaInstanceStart( vlm_t *p_vlm, int64_t id, const char * ...@@ -861,7 +861,7 @@ static int vlm_ControlMediaInstanceStart( vlm_t *p_vlm, int64_t id, const char *
return VLC_SUCCESS; return VLC_SUCCESS;
} }
input_StopThread( p_input, !p_input->b_eof && !p_input->b_error ); input_Stop( p_input, !p_input->b_eof && !p_input->b_error );
vlc_thread_join( p_input ); vlc_thread_join( p_input );
p_instance->p_input_resource = input_DetachResource( p_input ); p_instance->p_input_resource = input_DetachResource( p_input );
...@@ -881,8 +881,13 @@ static int vlm_ControlMediaInstanceStart( vlm_t *p_vlm, int64_t id, const char * ...@@ -881,8 +881,13 @@ static int vlm_ControlMediaInstanceStart( vlm_t *p_vlm, int64_t id, const char *
if( asprintf( &psz_log, _("Media: %s"), p_media->cfg.psz_name ) != -1 ) if( asprintf( &psz_log, _("Media: %s"), p_media->cfg.psz_name ) != -1 )
{ {
p_instance->p_input = input_CreateThreadExtended( p_vlm->p_libvlc, p_instance->p_item, p_instance->p_input = input_Create( p_vlm->p_libvlc, p_instance->p_item,
psz_log, p_instance->p_input_resource ); psz_log, p_instance->p_input_resource );
if( p_instance->p_input && input_Start( p_instance->p_input ) )
{
vlc_object_release( p_instance->p_input );
p_instance->p_input = NULL;
}
p_instance->p_input_resource = NULL; p_instance->p_input_resource = NULL;
if( !p_instance->p_input ) if( !p_instance->p_input )
......
...@@ -169,8 +169,9 @@ image_Mime2Fourcc ...@@ -169,8 +169,9 @@ image_Mime2Fourcc
image_Type2Fourcc image_Type2Fourcc
InitMD5 InitMD5
input_Control input_Control
__input_Create
__input_CreateAndStart
input_CreateFilename input_CreateFilename
__input_CreateThread
input_DecoderDecode input_DecoderDecode
input_DecoderDelete input_DecoderDelete
input_DecoderNew input_DecoderNew
...@@ -199,7 +200,8 @@ input_item_SetURI ...@@ -199,7 +200,8 @@ input_item_SetURI
input_MetaTypeToLocalizedString input_MetaTypeToLocalizedString
__input_Read __input_Read
input_SplitMRL input_SplitMRL
input_StopThread input_Start
input_Stop
input_vaControl input_vaControl
__intf_Create __intf_Create
__intf_Eject __intf_Eject
......
...@@ -823,7 +823,7 @@ static void GoAndPreparse( playlist_t *p_playlist, int i_mode, ...@@ -823,7 +823,7 @@ static void GoAndPreparse( playlist_t *p_playlist, int i_mode,
pl_priv(p_playlist)->request.i_skip = 0; pl_priv(p_playlist)->request.i_skip = 0;
pl_priv(p_playlist)->request.p_item = p_toplay; pl_priv(p_playlist)->request.p_item = p_toplay;
if( pl_priv(p_playlist)->p_input ) if( pl_priv(p_playlist)->p_input )
input_StopThread( pl_priv(p_playlist)->p_input, true ); input_Stop( pl_priv(p_playlist)->p_input, true );
pl_priv(p_playlist)->request.i_status = PLAYLIST_RUNNING; pl_priv(p_playlist)->request.i_status = PLAYLIST_RUNNING;
vlc_cond_signal( &pl_priv(p_playlist)->signal ); vlc_cond_signal( &pl_priv(p_playlist)->signal );
} }
......
...@@ -251,14 +251,17 @@ static int PlayItem( playlist_t *p_playlist, playlist_item_t *p_item ) ...@@ -251,14 +251,17 @@ static int PlayItem( playlist_t *p_playlist, playlist_item_t *p_item )
assert( p_sys->p_input == NULL ); assert( p_sys->p_input == NULL );
input_thread_t *p_input_thread = input_thread_t *p_input_thread = input_Create( p_playlist, p_input, NULL, p_sys->p_input_resource );
input_CreateThreadExtended( p_playlist, p_input, NULL, p_sys->p_input_resource );
if( p_input_thread ) if( p_input_thread )
{ {
p_sys->p_input = p_input_thread; p_sys->p_input = p_input_thread;
var_AddCallback( p_input_thread, "intf-event", InputEvent, p_playlist ); var_AddCallback( p_input_thread, "intf-event", InputEvent, p_playlist );
if( input_Start( p_sys->p_input ) )
{
vlc_object_release( p_input_thread );
p_sys->p_input = p_input_thread = NULL;
}
} }
p_sys->p_input_resource = NULL; p_sys->p_input_resource = NULL;
...@@ -473,7 +476,7 @@ static int LoopInput( playlist_t *p_playlist ) ...@@ -473,7 +476,7 @@ static int LoopInput( playlist_t *p_playlist )
if( ( p_sys->request.b_request || !vlc_object_alive( p_playlist ) ) && !p_input->b_die ) if( ( p_sys->request.b_request || !vlc_object_alive( p_playlist ) ) && !p_input->b_die )
{ {
PL_DEBUG( "incoming request - stopping current input" ); PL_DEBUG( "incoming request - stopping current input" );
input_StopThread( p_input, true ); input_Stop( p_input, true );
} }
/* This input is dead. Remove it ! */ /* This input is dead. Remove it ! */
...@@ -514,7 +517,7 @@ static int LoopInput( playlist_t *p_playlist ) ...@@ -514,7 +517,7 @@ static int LoopInput( playlist_t *p_playlist )
else if( p_input->b_error || p_input->b_eof ) else if( p_input->b_error || p_input->b_eof )
{ {
PL_DEBUG( "finished input" ); PL_DEBUG( "finished input" );
input_StopThread( p_input, false ); input_Stop( p_input, false );
} }
return VLC_SUCCESS; return VLC_SUCCESS;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment