From 6197b056e6f9bd026012db6f1512bbd981e27442 Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9mi=20Denis-Courmont?= Date: Sun, 30 May 2010 20:17:27 +0300 Subject: [PATCH] libvlc_Quit: support using a callback This is more flexible than the current libvlc_InternalWait() which requires a thread that does nothing for the whole lifetime of VLC. --- src/Makefile.am | 1 + src/control/libvlc_internal.h | 1 + src/interface/interface.c | 2 - src/libvlc.c | 36 +---------- src/libvlc.h | 17 ++++++ src/libvlccore.sym | 1 + src/misc/exit.c | 110 ++++++++++++++++++++++++++++++++++ 7 files changed, 132 insertions(+), 36 deletions(-) create mode 100644 src/misc/exit.c diff --git a/src/Makefile.am b/src/Makefile.am index 5ce3214c85..8a235067e9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -428,6 +428,7 @@ SOURCES_libvlc_common = \ misc/cpu.c \ misc/action.c \ misc/epg.c \ + misc/exit.c \ config/configuration.h \ config/core.c \ config/chain.c \ diff --git a/src/control/libvlc_internal.h b/src/control/libvlc_internal.h index 7ab347d7ae..c079f8dba9 100644 --- a/src/control/libvlc_internal.h +++ b/src/control/libvlc_internal.h @@ -50,6 +50,7 @@ VLC_EXPORT (void, libvlc_InternalDestroy, ( libvlc_int_t * ) ); VLC_EXPORT (int, libvlc_InternalAddIntf, ( libvlc_int_t *, const char * ) ); VLC_EXPORT (void, libvlc_InternalWait, ( libvlc_int_t * ) ); +VLC_EXPORT (void, libvlc_SetExitHandler, ( libvlc_int_t *, void (*) (void *), void * ) ); typedef void (*libvlc_vlm_release_func_t)( libvlc_instance_t * ) ; diff --git a/src/interface/interface.c b/src/interface/interface.c index ba9240b0c8..9268391525 100644 --- a/src/interface/interface.c +++ b/src/interface/interface.c @@ -182,8 +182,6 @@ void intf_DestroyAll( libvlc_int_t *p_libvlc ) { intf_thread_t *p_first; - assert( !vlc_object_alive( p_libvlc ) ); - vlc_mutex_lock( &lock ); p_first = libvlc_priv( p_libvlc )->p_intf; #ifndef NDEBUG diff --git a/src/libvlc.c b/src/libvlc.c index 3d78cde3bb..9affe8cf37 100644 --- a/src/libvlc.c +++ b/src/libvlc.c @@ -273,6 +273,7 @@ libvlc_int_t * libvlc_InternalCreate( void ) /* Initialize mutexes */ vlc_mutex_init( &priv->timer_lock ); + vlc_ExitInit( &priv->exit ); return p_libvlc; error: @@ -1073,6 +1074,7 @@ void libvlc_InternalDestroy( libvlc_int_t *p_libvlc ) msg_Destroy (priv->msg_bank); /* Destroy mutexes */ + vlc_ExitDestroy( &priv->exit ); vlc_mutex_destroy( &priv->timer_lock ); #ifndef NDEBUG /* Hack to dump leaked objects tree */ @@ -1121,40 +1123,6 @@ int libvlc_InternalAddIntf( libvlc_int_t *p_libvlc, char const *psz_module ) return ret; } -#ifndef WIN32 -static vlc_mutex_t exit_lock = VLC_STATIC_MUTEX; -static vlc_cond_t exiting = VLC_STATIC_COND; -#else -extern vlc_mutex_t super_mutex; -extern vlc_cond_t super_variable; -# define exit_lock super_mutex -# define exiting super_variable -#endif - -/** - * Waits until the LibVLC instance gets an exit signal. Normally, this happens - * when the user "exits" an interface plugin. - */ -void libvlc_InternalWait( libvlc_int_t *p_libvlc ) -{ - vlc_mutex_lock( &exit_lock ); - while( vlc_object_alive( p_libvlc ) ) - vlc_cond_wait( &exiting, &exit_lock ); - vlc_mutex_unlock( &exit_lock ); -} - -/** - * Posts an exit signal to LibVLC instance. This will normally initiate the - * cleanup and destroy process. It should only be called on behalf of the user. - */ -void libvlc_Quit( libvlc_int_t *p_libvlc ) -{ - vlc_mutex_lock( &exit_lock ); - vlc_object_kill( p_libvlc ); - vlc_cond_broadcast( &exiting ); - vlc_mutex_unlock( &exit_lock ); -} - #if defined( ENABLE_NLS ) && (defined (__APPLE__) || defined (WIN32)) && \ ( defined( HAVE_GETTEXT ) || defined( HAVE_INCLUDED_GETTEXT ) ) /***************************************************************************** diff --git a/src/libvlc.h b/src/libvlc.h index a9fd3d17eb..873b73cd9d 100644 --- a/src/libvlc.h +++ b/src/libvlc.h @@ -93,6 +93,20 @@ const char* msg_StackMsg ( void ); */ char *vlc_fix_readdir (const char *); +/* + * LibVLC exit event handling + */ +typedef struct vlc_exit +{ + vlc_mutex_t lock; + void (*handler) (void *); + void *opaque; + bool killed; +} vlc_exit_t; + +void vlc_ExitInit( vlc_exit_t * ); +void vlc_ExitDestroy( vlc_exit_t * ); + /* * LibVLC objects stuff */ @@ -210,6 +224,9 @@ typedef struct libvlc_priv_t /* Objects tree */ vlc_mutex_t structure_lock; + + /* Exit callback */ + vlc_exit_t exit; } libvlc_priv_t; static inline libvlc_priv_t *libvlc_priv (libvlc_int_t *libvlc) diff --git a/src/libvlccore.sym b/src/libvlccore.sym index 6767a6b6c0..d8cd222309 100644 --- a/src/libvlccore.sym +++ b/src/libvlccore.sym @@ -234,6 +234,7 @@ libvlc_InternalDestroy libvlc_InternalInit libvlc_InternalWait libvlc_Quit +libvlc_SetExitHandler LocaleFree make_URI make_path diff --git a/src/misc/exit.c b/src/misc/exit.c new file mode 100644 index 0000000000..65c380973a --- /dev/null +++ b/src/misc/exit.c @@ -0,0 +1,110 @@ +/***************************************************************************** + * quit.c: LibVLC termination event + ***************************************************************************** + * Copyright (C) 2009-2010 the VideoLAN team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 +#include +#include "libvlc.h" +#include "control/libvlc_internal.h" + +void vlc_ExitInit( vlc_exit_t *exit ) +{ + vlc_mutex_init( &exit->lock ); + exit->handler = NULL; + exit->opaque = NULL; + exit->killed = false; +} + +void vlc_ExitDestroy( vlc_exit_t *exit ) +{ + vlc_mutex_destroy( &exit->lock ); +} + + +/** + * Registers a callback for the LibVLC exit event. + * + * @note This function conflicts with libvlc_InternalWait(). + * Use either or none of them, but not both. + */ +void libvlc_SetExitHandler( libvlc_int_t *p_libvlc, void (*handler) (void *), + void *opaque ) +{ + vlc_exit_t *exit = &libvlc_priv( p_libvlc )->exit; + + vlc_mutex_lock( &exit->lock ); + if( exit->killed ) /* already exited! (race condition) */ + handler( opaque ); + exit->handler = handler; + exit->opaque = opaque; + vlc_mutex_unlock( &exit->lock ); +} + +/** + * Posts an exit signal to LibVLC instance. This only emits a notification to + * the main thread. It might take a while before the actual cleanup occurs. + * This function should only be called on behalf of the user. + */ +void libvlc_Quit( libvlc_int_t *p_libvlc ) +{ + vlc_exit_t *exit = &libvlc_priv( p_libvlc )->exit; + + vlc_mutex_lock( &exit->lock ); + if( !exit->killed ) + { + msg_Dbg( p_libvlc, "exiting" ); + exit->killed = true; + if( exit->handler != NULL ) + exit->handler( exit->opaque ); + } + vlc_mutex_unlock( &exit->lock ); +} + + +static void exit_wakeup( void *data ) +{ + vlc_cond_signal( data ); +} + +/** + * Waits until the LibVLC instance gets an exit signal. + * This normally occurs when the user "exits" an interface plugin. But it can + * also be triggered by the special vlc://quit item, the update checker, or + * the playlist engine. + */ +void libvlc_InternalWait( libvlc_int_t *p_libvlc ) +{ + vlc_exit_t *exit = &libvlc_priv( p_libvlc )->exit; + vlc_cond_t wait; + + vlc_cond_init( &wait ); + + vlc_mutex_lock( &exit->lock ); + exit->handler = exit_wakeup; + exit->opaque = &wait; + while( !exit->killed ) + vlc_cond_wait( &wait, &exit->lock ); + vlc_mutex_unlock( &exit->lock ); + + vlc_cond_destroy( &wait ); +} -- 2.39.2