Commit cffcf64f authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

Cleanup interaction-capable interface registration

 * Make registration thread-safe, and independent on vlc_list_find().
 * Fix use-after-free race condition when destroying the interface
   (interaction will be lost instead).
parent 2e4212b2
...@@ -67,9 +67,6 @@ struct intf_thread_t ...@@ -67,9 +67,6 @@ struct intf_thread_t
void ( *pf_show_dialog ) ( intf_thread_t *, int, int, void ( *pf_show_dialog ) ( intf_thread_t *, int, int,
intf_dialog_args_t * ); intf_dialog_args_t * );
/** Interaction stuff */
bool b_interaction;
vlc_mutex_t change_lock; vlc_mutex_t change_lock;
}; };
...@@ -108,6 +105,9 @@ VLC_EXPORT( void, intf_StopThread, ( intf_thread_t * ) ); ...@@ -108,6 +105,9 @@ VLC_EXPORT( void, intf_StopThread, ( intf_thread_t * ) );
#define intf_Eject(a,b) __intf_Eject(VLC_OBJECT(a),b) #define intf_Eject(a,b) __intf_Eject(VLC_OBJECT(a),b)
VLC_EXPORT( int, __intf_Eject, ( vlc_object_t *, const char * ) ); VLC_EXPORT( int, __intf_Eject, ( vlc_object_t *, const char * ) );
VLC_EXPORT( int, interaction_Register, ( intf_thread_t * ) );
VLC_EXPORT( int, interaction_Unregister, ( intf_thread_t * ) );
/*@}*/ /*@}*/
/***************************************************************************** /*****************************************************************************
......
...@@ -409,7 +409,7 @@ static VLCMain *_o_sharedMainInstance = nil; ...@@ -409,7 +409,7 @@ static VLCMain *_o_sharedMainInstance = nil;
var_Create( p_intf, "interaction", VLC_VAR_ADDRESS ); var_Create( p_intf, "interaction", VLC_VAR_ADDRESS );
var_AddCallback( p_intf, "interaction", InteractCallback, self ); var_AddCallback( p_intf, "interaction", InteractCallback, self );
p_intf->b_interaction = true; interaction_Register( p_intf );
/* update the playmode stuff */ /* update the playmode stuff */
p_intf->p_sys->b_playmode_update = true; p_intf->p_sys->b_playmode_update = true;
...@@ -685,7 +685,7 @@ static VLCMain *_o_sharedMainInstance = nil; ...@@ -685,7 +685,7 @@ static VLCMain *_o_sharedMainInstance = nil;
[o_extended savePrefs]; [o_extended savePrefs];
} }
p_intf->b_interaction = false; interaction_Unregister( p_intf );
var_DelCallback( p_intf, "interaction", InteractCallback, self ); var_DelCallback( p_intf, "interaction", InteractCallback, self );
/* remove global observer watching for vout device changes correctly */ /* remove global observer watching for vout device changes correctly */
......
...@@ -186,7 +186,7 @@ MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf ) ...@@ -186,7 +186,7 @@ MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
************/ ************/
var_Create( p_intf, "interaction", VLC_VAR_ADDRESS ); var_Create( p_intf, "interaction", VLC_VAR_ADDRESS );
var_AddCallback( p_intf, "interaction", InteractCallback, this ); var_AddCallback( p_intf, "interaction", InteractCallback, this );
p_intf->b_interaction = true; interaction_Register( p_intf );
var_AddCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf ); var_AddCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf );
...@@ -267,7 +267,7 @@ MainInterface::~MainInterface() ...@@ -267,7 +267,7 @@ MainInterface::~MainInterface()
/* Unregister callback for the intf-popupmenu variable */ /* Unregister callback for the intf-popupmenu variable */
var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf ); var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
p_intf->b_interaction = false; interaction_Unregister( p_intf );
var_DelCallback( p_intf, "interaction", InteractCallback, this ); var_DelCallback( p_intf, "interaction", InteractCallback, this );
p_intf->p_sys->p_mi = NULL; p_intf->p_sys->p_mi = NULL;
......
...@@ -164,7 +164,7 @@ VlcProc::VlcProc( intf_thread_t *pIntf ): SkinObject( pIntf ), ...@@ -164,7 +164,7 @@ VlcProc::VlcProc( intf_thread_t *pIntf ): SkinObject( pIntf ),
// Called when we have an interaction dialog to display // Called when we have an interaction dialog to display
var_Create( pIntf, "interaction", VLC_VAR_ADDRESS ); var_Create( pIntf, "interaction", VLC_VAR_ADDRESS );
var_AddCallback( pIntf, "interaction", onInteraction, this ); var_AddCallback( pIntf, "interaction", onInteraction, this );
pIntf->b_interaction = true; interaction_Register( pIntf );
getIntf()->p_sys->p_input = NULL; getIntf()->p_sys->p_input = NULL;
} }
...@@ -179,6 +179,8 @@ VlcProc::~VlcProc() ...@@ -179,6 +179,8 @@ VlcProc::~VlcProc()
vlc_object_release( getIntf()->p_sys->p_input ); vlc_object_release( getIntf()->p_sys->p_input );
} }
interaction_Unregister( getIntf() );
var_DelCallback( getIntf()->p_sys->p_playlist, "intf-change", var_DelCallback( getIntf()->p_sys->p_playlist, "intf-change",
onIntfChange, this ); onIntfChange, this );
var_DelCallback( getIntf()->p_sys->p_playlist, "item-append", var_DelCallback( getIntf()->p_sys->p_playlist, "item-append",
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
* Local prototypes * Local prototypes
*****************************************************************************/ *****************************************************************************/
static interaction_t * InteractionGet( vlc_object_t * ); static interaction_t * InteractionGet( vlc_object_t * );
static void InteractionSearchInterface( interaction_t * ); static intf_thread_t * SearchInterface( interaction_t * );
static void* InteractionLoop( vlc_object_t * ); static void* InteractionLoop( vlc_object_t * );
static void InteractionManage( interaction_t * ); static void InteractionManage( interaction_t * );
...@@ -401,6 +401,39 @@ void interaction_Destroy( interaction_t *p_interaction ) ...@@ -401,6 +401,39 @@ void interaction_Destroy( interaction_t *p_interaction )
vlc_object_release( p_interaction ); vlc_object_release( p_interaction );
} }
static vlc_mutex_t intf_lock = VLC_STATIC_MUTEX;
int interaction_Register( intf_thread_t *intf )
{
libvlc_priv_t *priv = libvlc_priv( intf->p_libvlc );
int ret = VLC_EGENERIC;
vlc_mutex_lock( &intf_lock );
if( priv->p_interaction_intf == NULL )
{ /* Since the interface is responsible for unregistering itself before
* it terminates, an object reference is not needed. */
priv->p_interaction_intf = intf;
ret = VLC_SUCCESS;
}
vlc_mutex_unlock( &intf_lock );
return ret;
}
int interaction_Unregister( intf_thread_t *intf )
{
libvlc_priv_t *priv = libvlc_priv( intf->p_libvlc );
int ret = VLC_EGENERIC;
vlc_mutex_lock( &intf_lock );
if( priv->p_interaction_intf == intf )
{
priv->p_interaction_intf = NULL;
ret = VLC_SUCCESS;
}
vlc_mutex_unlock( &intf_lock );
return ret;
}
/********************************************************************** /**********************************************************************
* The following functions are local * The following functions are local
**********************************************************************/ **********************************************************************/
...@@ -415,32 +448,19 @@ static interaction_t * InteractionGet( vlc_object_t *p_this ) ...@@ -415,32 +448,19 @@ static interaction_t * InteractionGet( vlc_object_t *p_this )
} }
/* Look for an interface suitable for interaction */ /* Look for an interface suitable for interaction, and hold it. */
static void InteractionSearchInterface( interaction_t *p_interaction ) static intf_thread_t *SearchInterface( interaction_t *p_interaction )
{ {
vlc_list_t *p_list; libvlc_priv_t *priv = libvlc_priv( p_interaction->p_libvlc );
int i_index; intf_thread_t *intf;
p_interaction->p_intf = NULL; vlc_mutex_lock( &intf_lock );
intf = priv->p_interaction_intf;
p_list = vlc_list_find( p_interaction, VLC_OBJECT_INTF, FIND_ANYWHERE ); if( intf != NULL )
if( !p_list ) vlc_object_hold( intf );
{ vlc_mutex_unlock( &intf_lock );
msg_Err( p_interaction, "unable to create module list" );
return;
}
for( i_index = 0; i_index < p_list->i_count; i_index ++ ) return intf;
{
intf_thread_t *p_intf = (intf_thread_t *)
p_list->p_values[i_index].p_object;
if( p_intf->b_interaction )
{
p_interaction->p_intf = p_intf;
break;
}
}
vlc_list_release ( p_list );
} }
/* Find an interaction dialog by its id */ /* Find an interaction dialog by its id */
...@@ -595,7 +615,7 @@ static void InteractionManage( interaction_t *p_interaction ) ...@@ -595,7 +615,7 @@ static void InteractionManage( interaction_t *p_interaction )
/* Nothing to do */ /* Nothing to do */
if( p_interaction->i_dialogs == 0 ) return; if( p_interaction->i_dialogs == 0 ) return;
InteractionSearchInterface( p_interaction ); p_interaction->p_intf = SearchInterface( p_interaction );
if( !p_interaction->p_intf ) if( !p_interaction->p_intf )
{ {
/* We mark all dialogs as answered with their "default" answer */ /* We mark all dialogs as answered with their "default" answer */
...@@ -611,8 +631,6 @@ static void InteractionManage( interaction_t *p_interaction ) ...@@ -611,8 +631,6 @@ static void InteractionManage( interaction_t *p_interaction )
p_dialog->i_status = HIDING_DIALOG; p_dialog->i_status = HIDING_DIALOG;
} }
} }
else
vlc_object_hold( p_interaction->p_intf );
for( i_index = 0 ; i_index < p_interaction->i_dialogs; i_index ++ ) for( i_index = 0 ; i_index < p_interaction->i_dialogs; i_index ++ )
{ {
......
...@@ -89,7 +89,6 @@ intf_thread_t* __intf_Create( vlc_object_t *p_this, const char *psz_module ) ...@@ -89,7 +89,6 @@ intf_thread_t* __intf_Create( vlc_object_t *p_this, const char *psz_module )
p_intf = vlc_object_create( p_this, VLC_OBJECT_INTF ); p_intf = vlc_object_create( p_this, VLC_OBJECT_INTF );
if( !p_intf ) if( !p_intf )
return NULL; return NULL;
p_intf->b_interaction = false;
#if defined( __APPLE__ ) || defined( WIN32 ) #if defined( __APPLE__ ) || defined( WIN32 )
p_intf->b_should_run_on_first_thread = false; p_intf->b_should_run_on_first_thread = false;
#endif #endif
......
...@@ -226,6 +226,7 @@ typedef struct libvlc_priv_t ...@@ -226,6 +226,7 @@ typedef struct libvlc_priv_t
playlist_t *p_playlist; //< the playlist singleton playlist_t *p_playlist; //< the playlist singleton
vlm_t *p_vlm; ///< the VLM singleton (or NULL) vlm_t *p_vlm; ///< the VLM singleton (or NULL)
interaction_t *p_interaction; ///< interface interaction object interaction_t *p_interaction; ///< interface interaction object
intf_thread_t *p_interaction_intf; ///< XXX interface for interaction
httpd_t *p_httpd; ///< HTTP daemon (src/network/httpd.c) httpd_t *p_httpd; ///< HTTP daemon (src/network/httpd.c)
#ifdef ENABLE_SOUT #ifdef ENABLE_SOUT
sap_handler_t *p_sap; ///< SAP SDP advertiser sap_handler_t *p_sap; ///< SAP SDP advertiser
......
...@@ -188,6 +188,8 @@ __input_Read ...@@ -188,6 +188,8 @@ __input_Read
input_SplitMRL input_SplitMRL
input_StopThread input_StopThread
input_vaControl input_vaControl
interaction_Register
interaction_Unregister
__intf_Create __intf_Create
__intf_Eject __intf_Eject
__intf_Progress __intf_Progress
......
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