Skip to content

Commit 6f41498

Browse files
robUx4tguillem
authored andcommitted
upnp: avoid locking each libupnp callback exclusively
UpnpDownloadXmlDoc() can take a while, during that time all other callbacks are blocking while they could handle simple events quickly (logging) or do another UpnpDownloadXmlDoc() in parallel. We only need to lock the MediaServerList in the callbacks when we need it. And not use it if it's already destroyed. Signed-off-by: Thomas Guillem <[email protected]>
1 parent 17ca1cb commit 6f41498

File tree

2 files changed

+55
-11
lines changed

2 files changed

+55
-11
lines changed

modules/services_discovery/upnp.cpp

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -627,10 +627,8 @@ void MediaServerList::removeServer( const std::string& udn )
627627
/*
628628
* Handles servers listing UPnP events
629629
*/
630-
int MediaServerList::Callback( Upnp_EventType event_type, void* p_event, MediaServerList* self )
630+
int MediaServerList::Callback( Upnp_EventType event_type, void* p_event )
631631
{
632-
services_discovery_t* p_sd = self->m_sd;
633-
634632
switch( event_type )
635633
{
636634
case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
@@ -642,14 +640,24 @@ int MediaServerList::Callback( Upnp_EventType event_type, void* p_event, MediaSe
642640

643641
int i_res;
644642
i_res = UpnpDownloadXmlDoc( p_discovery->Location, &p_description_doc );
643+
644+
MediaServerList *self = UpnpInstanceWrapper::lockMediaServerList();
645+
if ( !self )
646+
{
647+
UpnpInstanceWrapper::unlockMediaServerList();
648+
return UPNP_E_CANCELED;
649+
}
650+
645651
if ( i_res != UPNP_E_SUCCESS )
646652
{
647-
msg_Warn( p_sd, "Could not download device description! "
653+
msg_Warn( self->m_sd, "Could not download device description! "
648654
"Fetching data from %s failed: %s",
649655
p_discovery->Location, UpnpGetErrorMessage( i_res ) );
656+
UpnpInstanceWrapper::unlockMediaServerList();
650657
return i_res;
651658
}
652659
self->parseNewServer( p_description_doc, p_discovery->Location );
660+
UpnpInstanceWrapper::unlockMediaServerList();
653661
ixmlDocument_free( p_description_doc );
654662
}
655663
break;
@@ -658,16 +666,29 @@ int MediaServerList::Callback( Upnp_EventType event_type, void* p_event, MediaSe
658666
{
659667
struct Upnp_Discovery* p_discovery = ( struct Upnp_Discovery* )p_event;
660668

661-
self->removeServer( p_discovery->DeviceId );
669+
MediaServerList *self = UpnpInstanceWrapper::lockMediaServerList();
670+
if ( self )
671+
self->removeServer( p_discovery->DeviceId );
672+
UpnpInstanceWrapper::unlockMediaServerList();
662673
}
663674
break;
664675

665676
case UPNP_EVENT_SUBSCRIBE_COMPLETE:
666-
msg_Warn( p_sd, "subscription complete" );
677+
{
678+
MediaServerList *self = UpnpInstanceWrapper::lockMediaServerList();
679+
if ( self )
680+
msg_Warn( self->m_sd, "subscription complete" );
681+
UpnpInstanceWrapper::unlockMediaServerList();
682+
}
667683
break;
668684

669685
case UPNP_DISCOVERY_SEARCH_TIMEOUT:
670-
msg_Warn( p_sd, "search timeout" );
686+
{
687+
MediaServerList *self = UpnpInstanceWrapper::lockMediaServerList();
688+
if ( self )
689+
msg_Warn( self->m_sd, "search timeout" );
690+
UpnpInstanceWrapper::unlockMediaServerList();
691+
}
671692
break;
672693

673694
case UPNP_EVENT_RECEIVED:
@@ -677,7 +698,12 @@ int MediaServerList::Callback( Upnp_EventType event_type, void* p_event, MediaSe
677698
break;
678699

679700
default:
680-
msg_Err( p_sd, "Unhandled event, please report ( type=%d )", event_type );
701+
{
702+
MediaServerList *self = UpnpInstanceWrapper::lockMediaServerList();
703+
if ( self )
704+
msg_Err( self->m_sd, "Unhandled event, please report ( type=%d )", event_type );
705+
UpnpInstanceWrapper::unlockMediaServerList();
706+
}
681707
break;
682708
}
683709

@@ -1322,9 +1348,25 @@ UpnpClient_Handle UpnpInstanceWrapper::handle() const
13221348
int UpnpInstanceWrapper::Callback(Upnp_EventType event_type, void *p_event, void *p_user_data)
13231349
{
13241350
VLC_UNUSED(p_user_data);
1325-
vlc_mutex_locker lock( &s_lock );
1351+
vlc_mutex_lock( &s_lock );
13261352
if ( !UpnpInstanceWrapper::p_server_list )
1353+
{
1354+
vlc_mutex_unlock( &s_lock );
1355+
/* no MediaServerList available (anymore), do nothing */
13271356
return 0;
1328-
SD::MediaServerList::Callback( event_type, p_event, UpnpInstanceWrapper::p_server_list );
1357+
}
1358+
vlc_mutex_unlock( &s_lock );
1359+
SD::MediaServerList::Callback( event_type, p_event );
13291360
return 0;
13301361
}
1362+
1363+
SD::MediaServerList *UpnpInstanceWrapper::lockMediaServerList()
1364+
{
1365+
vlc_mutex_lock( &s_lock ); /* do not allow deleting the p_server_list while using it */
1366+
return UpnpInstanceWrapper::p_server_list;
1367+
}
1368+
1369+
void UpnpInstanceWrapper::unlockMediaServerList()
1370+
{
1371+
vlc_mutex_unlock( &s_lock );
1372+
}

modules/services_discovery/upnp.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ class UpnpInstanceWrapper
6161
static UpnpInstanceWrapper* get(vlc_object_t* p_obj, services_discovery_t *p_sd);
6262
void release(bool isSd);
6363
UpnpClient_Handle handle() const;
64+
static SD::MediaServerList *lockMediaServerList();
65+
static void unlockMediaServerList();
6466

6567
private:
6668
static int Callback( Upnp_EventType event_type, void* p_event, void* p_user_data );
@@ -103,7 +105,7 @@ class MediaServerList
103105
bool addServer(MediaServerDesc *desc );
104106
void removeServer(const std::string &udn );
105107
MediaServerDesc* getServer( const std::string& udn );
106-
static int Callback( Upnp_EventType event_type, void* p_event, MediaServerList* self );
108+
static int Callback( Upnp_EventType event_type, void* p_event );
107109

108110
private:
109111
void parseNewServer( IXML_Document* doc, const std::string& location );

0 commit comments

Comments
 (0)