* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
#include "vlc.h"
#include "libs.h"
#include "extension.h"
#include "assert.h"
+#include <vlc_common.h>
#include <vlc_input.h>
#include <vlc_events.h>
+#include <vlc_dialog.h>
/* Functions to register */
static const luaL_Reg p_reg[] =
NULL
};
+#define WATCH_TIMER_PERIOD (10 * CLOCK_FREQ) ///< 10s period for the timer
+
static int ScanExtensions( extensions_manager_t *p_this );
static int ScanLuaCallback( vlc_object_t *p_this, const char *psz_script,
void *dummy );
static int TriggerMenu( extension_t *p_ext, int id );
static int TriggerExtension( extensions_manager_t *p_mgr,
extension_t *p_ext );
+static void WatchTimerCallback( void* );
-int vlclua_extension_deactivate( lua_State *L );
+static int vlclua_extension_deactivate( lua_State *L );
+static int vlclua_extension_keep_alive( lua_State *L );
/* Interactions */
static int vlclua_extension_dialog_callback( vlc_object_t *p_this,
vlc_mutex_destroy( &p_ext->p_sys->running_lock );
vlc_mutex_destroy( &p_ext->p_sys->command_lock );
vlc_cond_destroy( &p_ext->p_sys->wait );
+ vlc_timer_destroy( p_ext->p_sys->timer );
free( p_ext->p_sys );
free( p_ext );
}
p_ext->p_sys->p_mgr = p_mgr;
+ /* Watch timer */
+ if( vlc_timer_create( &p_ext->p_sys->timer, WatchTimerCallback, p_ext ) )
+ {
+ free( p_ext->psz_name );
+ free( p_ext->p_sys );
+ free( p_ext );
+ return 0;
+ }
+
/* Mutexes and conditions */
vlc_mutex_init( &p_ext->p_sys->command_lock );
vlc_mutex_init( &p_ext->p_sys->running_lock );
lua_getglobal( L, "vlc" );
lua_pushcfunction( L, vlclua_extension_deactivate );
lua_setfield( L, -2, "deactivate" );
+ lua_pushcfunction( L, vlclua_extension_keep_alive );
+ lua_setfield( L, -2, "keep_alive" );
/* Setup the module search path */
if( vlclua_add_modules_path( p_mgr, L, p_ext->psz_name ) )
* (see extension_thread.c)
**/
int lua_ExecuteFunctionVa( extensions_manager_t *p_mgr, extension_t *p_ext,
- const char *psz_function, va_list args )
+ const char *psz_function, va_list args )
{
- int i_ret = VLC_EGENERIC;
+ int i_ret = VLC_SUCCESS;
int i_args = 0;
assert( p_mgr != NULL );
assert( p_ext != NULL );
}
i_args ++;
}
+
+ // Create watch timer
+ vlc_mutex_lock( &p_ext->p_sys->command_lock );
+ vlc_timer_schedule( p_ext->p_sys->timer, false, WATCH_TIMER_PERIOD, 0 );
+ vlc_mutex_unlock( &p_ext->p_sys->command_lock );
+
+ // Start actual call to Lua
if( lua_pcall( L, i_args, 1, 0 ) )
{
msg_Warn( p_mgr, "Error while running script %s, "
"function %s(): %s", p_ext->psz_name, psz_function,
lua_tostring( L, lua_gettop( L ) ) );
- goto exit;
+ i_ret = VLC_EGENERIC;
}
- i_ret = lua_DialogFlush( L );
+ // Reset watch timer and timestamp
+ vlc_mutex_lock( &p_ext->p_sys->command_lock );
+ if( p_ext->p_sys->progress )
+ {
+ dialog_ProgressDestroy( p_ext->p_sys->progress );
+ p_ext->p_sys->progress = NULL;
+ }
+ vlc_timer_schedule( p_ext->p_sys->timer, false, 0, 0 );
+ vlc_mutex_unlock( &p_ext->p_sys->command_lock );
+
+ i_ret |= lua_DialogFlush( L );
+
exit:
return i_ret;
int lua_ExtensionTriggerMenu( extensions_manager_t *p_mgr,
extension_t *p_ext, int id )
{
- int i_ret = VLC_EGENERIC;
+ int i_ret = VLC_SUCCESS;
lua_State *L = GetLuaState( p_mgr, p_ext );
if( !L )
/* Pass id as unique argument to the function */
lua_pushinteger( L, id );
+ // Create watch timer
+ vlc_mutex_lock( &p_ext->p_sys->command_lock );
+ vlc_timer_schedule( p_ext->p_sys->timer, false, WATCH_TIMER_PERIOD, 0 );
+ vlc_mutex_unlock( &p_ext->p_sys->command_lock );
+
if( lua_pcall( L, 1, 1, 0 ) != 0 )
{
msg_Warn( p_mgr, "Error while running script %s, "
"function trigger_menu(): %s", p_ext->psz_name,
lua_tostring( L, lua_gettop( L ) ) );
- return VLC_EGENERIC;
+ i_ret = VLC_EGENERIC;
+ }
+
+ // Reset watch timer and timestamp
+ vlc_mutex_lock( &p_ext->p_sys->command_lock );
+ if( p_ext->p_sys->progress )
+ {
+ dialog_ProgressDestroy( p_ext->p_sys->progress );
+ p_ext->p_sys->progress = NULL;
}
+ vlc_timer_schedule( p_ext->p_sys->timer, false, 0, 0 );
+ vlc_mutex_unlock( &p_ext->p_sys->command_lock );
- i_ret = lua_DialogFlush( L );
+ i_ret |= lua_DialogFlush( L );
if( i_ret < VLC_SUCCESS )
{
msg_Dbg( p_mgr, "Something went wrong in %s (%s:%d)",
__func__, __FILE__, __LINE__ );
}
+
return i_ret;
}
return ( i_ret == VLC_SUCCESS ) ? 1 : 0;
}
+/** Keep an extension alive. This resets the watch timer to 0
+ * @param L lua_State
+ * @note This is the "vlc.keep_alive()" function
+ **/
+int vlclua_extension_keep_alive( lua_State *L )
+{
+ extension_t *p_ext = vlclua_extension_get( L );
+
+ vlc_mutex_lock( &p_ext->p_sys->command_lock );
+ if( p_ext->p_sys->progress )
+ {
+ dialog_ProgressDestroy( p_ext->p_sys->progress );
+ p_ext->p_sys->progress = NULL;
+ }
+ vlc_timer_schedule( p_ext->p_sys->timer, false, WATCH_TIMER_PERIOD, 0 );
+ vlc_mutex_unlock( &p_ext->p_sys->command_lock );
+
+ return 1;
+}
+
/** Callback for the variable "dialog-event"
* @param p_this Current object owner of the extension and the dialog
* @param psz_var "dialog-event"
PushCommandUnique( p_ext, CMD_UPDATE_META );
}
-/* Lock this extension. Can fail. */
+/** Lock this extension. Can fail. */
bool LockExtension( extension_t *p_ext )
{
+ vlc_mutex_lock( &p_ext->p_sys->command_lock );
if( p_ext->p_sys->b_exiting )
+ {
+ vlc_mutex_unlock( &p_ext->p_sys->command_lock );
return false;
+ }
vlc_mutex_lock( &p_ext->p_sys->running_lock );
if( p_ext->p_sys->b_exiting )
{
vlc_mutex_unlock( &p_ext->p_sys->running_lock );
+ vlc_mutex_unlock( &p_ext->p_sys->command_lock );
return false;
}
+ vlc_mutex_unlock( &p_ext->p_sys->command_lock );
return true;
}
+/** Unlock this extension. */
void UnlockExtension( extension_t *p_ext )
{
vlc_mutex_unlock( &p_ext->p_sys->running_lock );
}
+
+/** Watch timer callback
+ * The timer expired, Lua may be stuck, ask the user what to do now
+ **/
+static void WatchTimerCallback( void *data )
+{
+ extension_t *p_ext = data;
+ extensions_manager_t *p_mgr = p_ext->p_sys->p_mgr;
+
+ char *message;
+ if( asprintf( &message, _( "Extension '%s' does not respond.\n"
+ "Do you want to kill it now? " ),
+ p_ext->psz_title ) == -1 )
+ {
+ return;
+ }
+
+ vlc_mutex_lock( &p_ext->p_sys->command_lock );
+
+ // Do we have a pending Deactivate command?
+ if( ( p_ext->p_sys->command &&
+ p_ext->p_sys->command->i_command == CMD_DEACTIVATE )
+ || ( p_ext->p_sys->command->next
+ && p_ext->p_sys->command->next->i_command == CMD_DEACTIVATE) )
+ {
+ if( p_ext->p_sys->progress )
+ {
+ dialog_ProgressDestroy( p_ext->p_sys->progress );
+ p_ext->p_sys->progress = NULL;
+ }
+ vlc_mutex_unlock( &p_ext->p_sys->command_lock );
+ KillExtension( p_mgr, p_ext );
+ return;
+ }
+
+ if( !p_ext->p_sys->progress )
+ {
+ p_ext->p_sys->progress =
+ dialog_ProgressCreate( p_mgr, _( "Extension not responding!" ),
+ message,
+ _( "Yes" ) );
+ vlc_timer_schedule( p_ext->p_sys->timer, false, 100000, 0 );
+ }
+ else
+ {
+ if( dialog_ProgressCancelled( p_ext->p_sys->progress ) )
+ {
+ dialog_ProgressDestroy( p_ext->p_sys->progress );
+ p_ext->p_sys->progress = NULL;
+ vlc_mutex_unlock( &p_ext->p_sys->command_lock );
+ KillExtension( p_mgr, p_ext );
+ return;
+ }
+ vlc_timer_schedule( p_ext->p_sys->timer, false, 100000, 0 );
+ }
+ vlc_mutex_unlock( &p_ext->p_sys->command_lock );
+}
return VLC_EGENERIC;
}
+ if( p_ext->p_sys->progress )
+ {
+ // Extension is stuck, kill it now
+ dialog_ProgressDestroy( p_ext->p_sys->progress );
+ p_ext->p_sys->progress = NULL;
+ vlc_mutex_unlock( &p_ext->p_sys->command_lock );
+ KillExtension( p_mgr, p_ext );
+ return VLC_SUCCESS;
+ }
+
/* Free the list of commands */
if( p_ext->p_sys->command )
FreeCommands( p_ext->p_sys->command->next );
return (i_idx >= 0) ? VLC_SUCCESS : VLC_EGENERIC;
}
+void KillExtension( extensions_manager_t *p_mgr, extension_t *p_ext )
+{
+ /* Cancel thread if it seems stuck for a while */
+ msg_Dbg( p_mgr, "Killing extension now" );
+ vlc_cancel( p_ext->p_sys->thread );
+ lua_ExtensionDeactivate( p_mgr, p_ext );
+ p_ext->p_sys->b_exiting = true;
+ RemoveActivated( p_mgr, p_ext );
+}
+
/** Push a UI command */
int __PushCommand( extension_t *p_ext, bool b_unique, command_type_e i_command,
va_list args )
extension_t *p_ext = data;
extensions_manager_t *p_mgr = p_ext->p_sys->p_mgr;
+ int cancel = vlc_savecancel();
vlc_mutex_lock( &p_ext->p_sys->command_lock );
while( !p_ext->p_sys->b_exiting )
/* Pop command in front */
struct command_t *cmd = p_ext->p_sys->command;
vlc_mutex_unlock( &p_ext->p_sys->command_lock );
+ vlc_restorecancel( cancel );
/* Run command */
if( cmd )
{
if( LockExtension( p_ext ) )
{
+ mutex_cleanup_push( &p_ext->p_sys->running_lock );
switch( cmd->i_command )
{
case CMD_ACTIVATE:
break;
}
}
+ vlc_cleanup_pop();
UnlockExtension( p_ext );
}
}
+ cancel = vlc_savecancel();
vlc_mutex_lock( &p_ext->p_sys->command_lock );
if( p_ext->p_sys->command )
{
vlc_mutex_unlock( &p_ext->p_sys->command_lock );
msg_Dbg( p_mgr, "Extension thread end: '%s'", p_ext->psz_title );
+ vlc_restorecancel( cancel );
// Note: At this point, the extension should be deactivated
return NULL;