From 2fa6c9ce280b037c058eed166bfc51e7c70c5d14 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Mon, 19 Aug 2002 11:13:45 +0000 Subject: [PATCH] * ./src/misc/cpu.c: libvlc now plays nice with SIGILL and restores the signal handler to its previous value after use. * ./src/libvlc.c: moved signal handling to vlc.c. --- include/vlc/vlc.h | 4 +- src/libvlc.c | 171 ++++++++++++++++++++++------------------------ src/misc/cpu.c | 59 +++++++++------- src/vlc.c | 81 ++++++++++++++++++++-- 4 files changed, 193 insertions(+), 122 deletions(-) diff --git a/include/vlc/vlc.h b/include/vlc/vlc.h index 9d4264ecc2..7ac8861bd8 100644 --- a/include/vlc/vlc.h +++ b/include/vlc/vlc.h @@ -2,7 +2,7 @@ * vlc.h: global header for vlc ***************************************************************************** * Copyright (C) 1998, 1999, 2000 VideoLAN - * $Id: vlc.h,v 1.8 2002/08/14 17:06:53 sam Exp $ + * $Id: vlc.h,v 1.9 2002/08/19 11:13:44 sam Exp $ * * 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 @@ -114,6 +114,7 @@ vlc_status_t vlc_status ( void ); vlc_error_t vlc_create ( void ); vlc_error_t vlc_init ( int, char *[] ); vlc_error_t vlc_run ( void ); +vlc_error_t vlc_die ( void ); vlc_error_t vlc_stop ( void ); vlc_error_t vlc_end ( void ); vlc_error_t vlc_destroy ( void ); @@ -129,6 +130,7 @@ vlc_status_t vlc_status_r ( vlc_t * ); vlc_t * vlc_create_r ( void ); vlc_error_t vlc_init_r ( vlc_t *, int, char *[] ); vlc_error_t vlc_run_r ( vlc_t * ); +vlc_error_t vlc_die_r ( vlc_t * ); vlc_error_t vlc_stop_r ( vlc_t * ); vlc_error_t vlc_end_r ( vlc_t * ); vlc_error_t vlc_destroy_r ( vlc_t * ); diff --git a/src/libvlc.c b/src/libvlc.c index e7672e6278..dbf15abbc4 100644 --- a/src/libvlc.c +++ b/src/libvlc.c @@ -2,7 +2,7 @@ * libvlc.c: main libvlc source ***************************************************************************** * Copyright (C) 1998-2002 VideoLAN - * $Id: libvlc.c,v 1.27 2002/08/18 13:49:20 sam Exp $ + * $Id: libvlc.c,v 1.28 2002/08/19 11:13:45 sam Exp $ * * Authors: Vincent Seguin * Samuel Hocevar @@ -37,7 +37,6 @@ #include /* sprintf() */ #include /* strerror() */ #include /* free() */ -#include /* SIGHUP, SIGINT, SIGKILL */ #include @@ -102,11 +101,6 @@ static void Usage ( vlc_t *, const char *psz_module_name ); static void ListModules ( vlc_t * ); static void Version ( void ); -#ifndef WIN32 -static void InitSignalHandler ( void ); -static void FatalSignalHandler ( int i_signal ); -#endif - #ifdef WIN32 static void ShowConsole ( void ); #endif @@ -115,12 +109,45 @@ static void ShowConsole ( void ); * vlc_create: allocate a vlc_t structure, and initialize libvlc if needed. ***************************************************************************** * This function allocates a vlc_t structure and returns NULL in case of - * failure. Also, the thread system and the signal handlers are initialized. + * failure. Also, the thread system is initialized. *****************************************************************************/ vlc_error_t vlc_create( void ) { - vlc_t * p_vlc = vlc_create_r(); - return p_vlc ? VLC_SUCCESS : VLC_EGENERIC; + vlc_t * p_vlc; + vlc_bool_t b_failed = VLC_FALSE; + + /* This gives us a rather good protection against concurrent calls, but + * an additional check will be necessary for complete thread safety. */ + if( i_vlc ) + { + return VLC_EGENERIC; + } + + p_vlc = vlc_create_r(); + + if( p_vlc == NULL ) + { + return VLC_EGENERIC; + } + + /* We have created an object, which ensures us that p_global_lock has + * been properly initialized. We can now atomically check that we are + * the only p_vlc object. */ + vlc_mutex_lock( p_vlc->p_global_lock ); + if( i_vlc != 1 ) + { + b_failed = VLC_TRUE; + } + vlc_mutex_unlock( p_vlc->p_global_lock ); + + /* There can be only one */ + if( b_failed ) + { + vlc_destroy_r( p_vlc ); + return VLC_EGENERIC; + } + + return VLC_SUCCESS; } vlc_t * vlc_create_r( void ) @@ -149,11 +176,6 @@ vlc_t * vlc_create_r( void ) vlc_mutex_init( p_vlc, &p_vlc->config_lock ); vlc_mutex_init( p_vlc, &p_vlc->structure_lock ); - /* Set signal handling policy for all threads */ -#ifndef WIN32 - InitSignalHandler( ); -#endif - /* Store our newly allocated structure in the global list */ vlc_mutex_lock( p_vlc->p_global_lock ); pp_vlc = realloc( pp_vlc, (i_vlc+1) * sizeof( vlc_t * ) ); @@ -180,7 +202,7 @@ vlc_t * vlc_create_r( void ) *****************************************************************************/ vlc_error_t vlc_init( int i_argc, char *ppsz_argv[] ) { - return vlc_init_r( ( i_vlc == 1 ) ? *pp_vlc : NULL, i_argc, ppsz_argv ); + return vlc_init_r( ( i_vlc == 1 ) ? pp_vlc[0] : NULL, i_argc, ppsz_argv ); } vlc_error_t vlc_init_r( vlc_t *p_vlc, int i_argc, char *ppsz_argv[] ) @@ -197,8 +219,6 @@ vlc_error_t vlc_init_r( vlc_t *p_vlc, int i_argc, char *ppsz_argv[] ) return VLC_ESTATUS; } - fprintf( stderr, COPYRIGHT_MESSAGE "\n" ); - /* Guess what CPU we have */ p_vlc->i_cpu = CPUCapabilities( p_vlc ); @@ -511,7 +531,7 @@ vlc_error_t vlc_init_r( vlc_t *p_vlc, int i_argc, char *ppsz_argv[] ) *****************************************************************************/ vlc_error_t vlc_run( void ) { - return vlc_run_r( ( i_vlc == 1 ) ? *pp_vlc : NULL ); + return vlc_run_r( ( i_vlc == 1 ) ? pp_vlc[0] : NULL ); } vlc_error_t vlc_run_r( vlc_t *p_vlc ) @@ -539,7 +559,7 @@ vlc_error_t vlc_run_r( vlc_t *p_vlc ) *****************************************************************************/ vlc_error_t vlc_add_intf( const char *psz_module, vlc_bool_t b_block ) { - return vlc_add_intf_r( ( i_vlc == 1 ) ? *pp_vlc : NULL, + return vlc_add_intf_r( ( i_vlc == 1 ) ? pp_vlc[0] : NULL, psz_module, b_block ); } @@ -602,7 +622,7 @@ vlc_error_t vlc_add_intf_r( vlc_t *p_vlc, const char *psz_module, *****************************************************************************/ vlc_error_t vlc_stop( void ) { - return vlc_stop_r( ( i_vlc == 1 ) ? *pp_vlc : NULL ); + return vlc_stop_r( ( i_vlc == 1 ) ? pp_vlc[0] : NULL ); } vlc_error_t vlc_stop_r( vlc_t *p_vlc ) @@ -679,7 +699,7 @@ vlc_error_t vlc_stop_r( vlc_t *p_vlc ) *****************************************************************************/ vlc_error_t vlc_end( void ) { - return vlc_end_r( ( i_vlc == 1 ) ? *pp_vlc : NULL ); + return vlc_end_r( ( i_vlc == 1 ) ? pp_vlc[0] : NULL ); } vlc_error_t vlc_end_r( vlc_t *p_vlc ) @@ -737,7 +757,7 @@ vlc_error_t vlc_end_r( vlc_t *p_vlc ) *****************************************************************************/ vlc_error_t vlc_destroy( void ) { - return vlc_destroy_r( ( i_vlc == 1 ) ? *pp_vlc : NULL ); + return vlc_destroy_r( ( i_vlc == 1 ) ? pp_vlc[0] : NULL ); } vlc_error_t vlc_destroy_r( vlc_t *p_vlc ) @@ -802,9 +822,38 @@ vlc_error_t vlc_destroy_r( vlc_t *p_vlc ) return VLC_SUCCESS; } +/***************************************************************************** + * vlc_die: ask vlc to die. + ***************************************************************************** + * This function sets p_vlc->b_die to VLC_TRUE, but does not do any other + * task. It is your duty to call vlc_end and vlc_destroy afterwards. + *****************************************************************************/ +vlc_error_t vlc_die( void ) +{ + return vlc_die_r( ( i_vlc == 1 ) ? pp_vlc[0] : NULL ); +} + +vlc_error_t vlc_die_r( vlc_t *p_vlc ) +{ + if( !p_vlc ) + { + fprintf( stderr, "error: invalid status (!EXIST)\n" ); + return VLC_ESTATUS; + } + + p_vlc->b_die = VLC_TRUE; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * vlc_status: return the current vlc status. + ***************************************************************************** + * This function returns the current value of p_vlc->i_status. + *****************************************************************************/ vlc_status_t vlc_status( void ) { - return vlc_status_r( ( i_vlc == 1 ) ? *pp_vlc : NULL ); + return vlc_status_r( ( i_vlc == 1 ) ? pp_vlc[0] : NULL ); } vlc_status_t vlc_status_r( vlc_t *p_vlc ) @@ -817,9 +866,15 @@ vlc_status_t vlc_status_r( vlc_t *p_vlc ) return p_vlc->i_status; } +/***************************************************************************** + * vlc_add_target: adds a target for playing. + ***************************************************************************** + * This function adds psz_target to the current playlist. If a playlist does + * not exist, it will create one. + *****************************************************************************/ vlc_error_t vlc_add_target( const char *psz_target, int i_mode, int i_pos ) { - return vlc_add_target_r( ( i_vlc == 1 ) ? *pp_vlc : NULL, + return vlc_add_target_r( ( i_vlc == 1 ) ? pp_vlc[0] : NULL, psz_target, i_mode, i_pos ); } @@ -1177,69 +1232,3 @@ static void ShowConsole( void ) } #endif -#ifndef WIN32 -/***************************************************************************** - * InitSignalHandler: system signal handler initialization - ***************************************************************************** - * Set the signal handlers. SIGTERM is not intercepted, because we need at - * at least a method to kill the program when all other methods failed, and - * when we don't want to use SIGKILL. - *****************************************************************************/ -static void InitSignalHandler( void ) -{ - /* Termination signals */ - signal( SIGINT, FatalSignalHandler ); - signal( SIGHUP, FatalSignalHandler ); - signal( SIGQUIT, FatalSignalHandler ); - - /* Other signals */ - signal( SIGALRM, SIG_IGN ); - signal( SIGPIPE, SIG_IGN ); -} - -/***************************************************************************** - * FatalSignalHandler: system signal handler - ***************************************************************************** - * This function is called when a fatal signal is received by the program. - * It tries to end the program in a clean way. - *****************************************************************************/ -static void FatalSignalHandler( int i_signal ) -{ - static mtime_t abort_time = 0; - static volatile vlc_bool_t b_die = VLC_FALSE; - int i_index; - - /* Once a signal has been trapped, the termination sequence will be - * armed and following signals will be ignored to avoid sending messages - * to an interface having been destroyed */ - - if( !b_die ) - { - b_die = VLC_TRUE; - abort_time = mdate(); - - fprintf( stderr, "signal %d received, terminating libvlc - do it " - "again in case your process gets stuck\n", i_signal ); - - /* Try to terminate everything - this is done by requesting the end of - * all the p_vlc structures */ - for( i_index = 0 ; i_index < i_vlc ; i_index++ ) - { - /* Acknowledge the signal received */ - pp_vlc[ i_index ]->b_die = VLC_TRUE; - } - } - else if( mdate() > abort_time + 1000000 ) - { - /* If user asks again 1 second later, die badly */ - signal( SIGINT, SIG_IGN ); - signal( SIGHUP, SIG_IGN ); - signal( SIGQUIT, SIG_IGN ); - - fprintf( stderr, "user insisted too much, dying badly\n" ); - - exit( 1 ); - } -} -#endif - diff --git a/src/misc/cpu.c b/src/misc/cpu.c index 4df79dc171..39e9331390 100644 --- a/src/misc/cpu.c +++ b/src/misc/cpu.c @@ -2,7 +2,7 @@ * cpu.c: CPU detection code ***************************************************************************** * Copyright (C) 1998-2002 VideoLAN - * $Id: cpu.c,v 1.4 2002/06/07 14:30:41 sam Exp $ + * $Id: cpu.c,v 1.5 2002/08/19 11:13:45 sam Exp $ * * Authors: Samuel Hocevar * Christophe Massiot @@ -43,7 +43,8 @@ /***************************************************************************** * Local prototypes *****************************************************************************/ -static void IllegalSignalHandler( int i_signal ); +static void SigHandler ( int ); +static u32 Capabilities ( vlc_object_t * ); /***************************************************************************** * Global variables - they're needed for signal handling @@ -55,11 +56,27 @@ static char *psz_capability; #endif /***************************************************************************** - * CPUCapabilities: list the processors MMX support and other capabilities + * CPUCapabilities: get the CPU capabilities + ***************************************************************************** + * This function is a wrapper around Capabilities(). + *****************************************************************************/ +u32 __CPUCapabilities( vlc_object_t *p_this ) +{ + u32 i_capabilities; + + vlc_mutex_lock( p_this->p_vlc->p_global_lock ); + i_capabilities = Capabilities( p_this ); + vlc_mutex_unlock( p_this->p_vlc->p_global_lock ); + + return i_capabilities; +} + +/***************************************************************************** + * Capabilities: list the processors MMX support and other capabilities ***************************************************************************** * This function is called to list extensions the CPU may have. *****************************************************************************/ -u32 __CPUCapabilities( vlc_object_t *p_this ) +static u32 Capabilities( vlc_object_t *p_this ) { volatile u32 i_capabilities = CPU_CAPABILITY_NONE; @@ -112,12 +129,12 @@ u32 __CPUCapabilities( vlc_object_t *p_this ) : "a" ( a ) \ : "cc" ); - i_capabilities |= CPU_CAPABILITY_FPU; - # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) - signal( SIGILL, IllegalSignalHandler ); + sighandler_t pf_sigill = signal( SIGILL, SigHandler ); # endif + i_capabilities |= CPU_CAPABILITY_FPU; + /* test for a 486 CPU */ asm volatile ( "pushl %%ebx\n\t" "pushfl\n\t" @@ -138,7 +155,7 @@ u32 __CPUCapabilities( vlc_object_t *p_this ) if( i_eax == i_ebx ) { # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) - signal( SIGILL, NULL ); + signal( SIGILL, pf_sigill ); # endif return i_capabilities; } @@ -151,7 +168,7 @@ u32 __CPUCapabilities( vlc_object_t *p_this ) if( !i_eax ) { # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) - signal( SIGILL, NULL ); + signal( SIGILL, pf_sigill ); # endif return i_capabilities; } @@ -169,7 +186,7 @@ u32 __CPUCapabilities( vlc_object_t *p_this ) if( ! (i_edx & 0x00800000) ) { # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) - signal( SIGILL, NULL ); + signal( SIGILL, pf_sigill ); # endif return i_capabilities; } @@ -185,13 +202,11 @@ u32 __CPUCapabilities( vlc_object_t *p_this ) psz_capability = "SSE"; i_illegal = 0; - vlc_mutex_lock( p_this->p_vlc->p_global_lock ); if( setjmp( env ) == 0 ) { /* Test a SSE instruction */ __asm__ __volatile__ ( "xorps %%xmm0,%%xmm0\n" : : ); } - vlc_mutex_unlock( p_this->p_vlc->p_global_lock ); if( i_illegal == 0 ) { @@ -206,7 +221,7 @@ u32 __CPUCapabilities( vlc_object_t *p_this ) if( i_eax < 0x80000001 ) { # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) - signal( SIGILL, NULL ); + signal( SIGILL, pf_sigill ); # endif return i_capabilities; } @@ -220,13 +235,11 @@ u32 __CPUCapabilities( vlc_object_t *p_this ) psz_capability = "3D Now!"; i_illegal = 0; - vlc_mutex_lock( p_this->p_vlc->p_global_lock ); if( setjmp( env ) == 0 ) { /* Test a 3D Now! instruction */ __asm__ __volatile__ ( "pfadd %%mm0,%%mm0\n" "femms\n" : : ); } - vlc_mutex_unlock( p_this->p_vlc->p_global_lock ); if( i_illegal == 0 ) { @@ -241,20 +254,19 @@ u32 __CPUCapabilities( vlc_object_t *p_this ) } # if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) - signal( SIGILL, NULL ); + signal( SIGILL, pf_sigill ); # endif return i_capabilities; #elif defined( __powerpc__ ) - i_capabilities |= CPU_CAPABILITY_FPU; - # ifdef CAN_COMPILE_ALTIVEC - signal( SIGILL, IllegalSignalHandler ); + sighandler_t pf_sigill = signal( SIGILL, SigHandler ); + + i_capabilities |= CPU_CAPABILITY_FPU; i_illegal = 0; - vlc_mutex_lock( p_this->p_vlc->p_global_lock ); if( setjmp( env ) == 0 ) { asm volatile ("mtspr 256, %0\n\t" @@ -262,14 +274,13 @@ u32 __CPUCapabilities( vlc_object_t *p_this ) : : "r" (-1)); } - vlc_mutex_unlock( p_this->p_vlc->p_global_lock ); if( i_illegal == 0 ) { i_capabilities |= CPU_CAPABILITY_ALTIVEC; } - signal( SIGILL, NULL ); + signal( SIGILL, pf_sigill ); # endif return i_capabilities; @@ -287,12 +298,12 @@ u32 __CPUCapabilities( vlc_object_t *p_this ) } /***************************************************************************** - * IllegalSignalHandler: system signal handler + * SigHandler: system signal handler ***************************************************************************** * This function is called when an illegal instruction signal is received by * the program. We use this function to test OS and CPU capabilities *****************************************************************************/ -static void IllegalSignalHandler( int i_signal ) +static void SigHandler( int i_signal ) { /* Acknowledge the signal received */ i_illegal = 1; diff --git a/src/vlc.c b/src/vlc.c index 5adc5fe877..4677528c63 100644 --- a/src/vlc.c +++ b/src/vlc.c @@ -2,11 +2,12 @@ * vlc.c: the vlc player ***************************************************************************** * Copyright (C) 1998-2001 VideoLAN - * $Id: vlc.c,v 1.8 2002/08/08 00:35:11 sam Exp $ + * $Id: vlc.c,v 1.9 2002/08/19 11:13:45 sam Exp $ * * Authors: Vincent Seguin * Samuel Hocevar * Gildas Bazin + * Lots of other people, see the libvlc AUTHORS file * * 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 @@ -22,19 +23,30 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************/ + #include /* SIGHUP, SIGINT, SIGKILL */ #include /* fprintf() */ #include /* putenv(), strtol(), */ +#include /* SIGHUP, SIGINT, SIGKILL */ #include +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +#ifndef WIN32 +static void SigHandler ( int i_signal ); +#endif + /***************************************************************************** * main: parse command line, start interface and spawn threads *****************************************************************************/ -int main(int i_argc, char *ppsz_argv[]) +int main( int i_argc, char *ppsz_argv[] ) { vlc_error_t err; + fprintf( stderr, COPYRIGHT_MESSAGE "\n" ); + #ifdef SYS_LINUX # ifdef DEBUG /* Activate malloc checking routines to detect heap corruptions. */ @@ -45,14 +57,28 @@ int main(int i_argc, char *ppsz_argv[]) # endif #endif - /* Create the vlc structure */ + /* Create a libvlc structure */ err = vlc_create(); if( err != VLC_SUCCESS ) { return err; } - /* Initialize vlc */ +#ifndef WIN32 + /* Set the signal handlers. SIGTERM is not intercepted, because we need at + * least one method to kill the program when all other methods failed, and + * when we don't want to use SIGKILL. + * Note that we set the signals after the vlc_create call. */ + signal( SIGINT, SigHandler ); + signal( SIGHUP, SigHandler ); + signal( SIGQUIT, SigHandler ); + + /* Other signals */ + signal( SIGALRM, SIG_IGN ); + signal( SIGPIPE, SIG_IGN ); +#endif + + /* Initialize libvlc */ err = vlc_init( i_argc, ppsz_argv ); if( err != VLC_SUCCESS ) { @@ -60,7 +86,7 @@ int main(int i_argc, char *ppsz_argv[]) return err; } - /* Run vlc, in non-blocking mode */ + /* Run libvlc, in non-blocking mode */ err = vlc_run(); /* Add background interfaces */ @@ -83,9 +109,52 @@ int main(int i_argc, char *ppsz_argv[]) /* Finish all threads */ vlc_end(); - /* Destroy the vlc structure */ + /* Destroy the libvlc structure */ vlc_destroy(); return err; } +#ifndef WIN32 +/***************************************************************************** + * SigHandler: system signal handler + ***************************************************************************** + * This function is called when a fatal signal is received by the program. + * It tries to end the program in a clean way. + *****************************************************************************/ +static void SigHandler( int i_signal ) +{ + static mtime_t abort_time = 0; + static volatile vlc_bool_t b_die = VLC_FALSE; + + /* Once a signal has been trapped, the termination sequence will be + * armed and subsequent signals will be ignored to avoid sending signals + * to a libvlc structure having been destroyed */ + + if( !b_die ) + { + b_die = VLC_TRUE; + abort_time = mdate(); + + fprintf( stderr, "signal %d received, terminating vlc - do it " + "again in case it gets stuck\n", i_signal ); + + /* Acknowledge the signal received */ + vlc_die(); + } + else if( mdate() > abort_time + 1000000 ) + { + /* If user asks again 1 second later, die badly */ + signal( SIGINT, SIG_DFL ); + signal( SIGHUP, SIG_DFL ); + signal( SIGQUIT, SIG_DFL ); + signal( SIGALRM, SIG_DFL ); + signal( SIGPIPE, SIG_DFL ); + + fprintf( stderr, "user insisted too much, dying badly\n" ); + + exit( 1 ); + } +} +#endif +