libvlc_Quit: support using a callback
authorRémi Denis-Courmont <remi@remlab.net>
Sun, 30 May 2010 17:17:27 +0000 (20:17 +0300)
committerRémi Denis-Courmont <remi@remlab.net>
Sun, 30 May 2010 17:52:23 +0000 (20:52 +0300)
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
src/control/libvlc_internal.h
src/interface/interface.c
src/libvlc.c
src/libvlc.h
src/libvlccore.sym
src/misc/exit.c [new file with mode: 0644]

index 5ce3214..8a23506 100644 (file)
@@ -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 \
index 7ab347d..c079f8d 100644 (file)
@@ -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 * ) ;
 
index ba9240b..9268391 100644 (file)
@@ -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
index 3d78cde..9affe8c 100644 (file)
@@ -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 ) )
 /*****************************************************************************
index a9fd3d1..873b73c 100644 (file)
@@ -94,6 +94,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)
index 6767a6b..d8cd222 100644 (file)
@@ -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 (file)
index 0000000..65c3809
--- /dev/null
@@ -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 <vlc_common.h>
+#include <vlc_interface.h>
+#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 );
+}