Commit eeb67833 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

Rework signal handling so that it is async-safe

and that signals never disturb our innocent blocking system call callers
(such as network I/O)
parent eb14a72b
...@@ -35,6 +35,9 @@ ...@@ -35,6 +35,9 @@
#ifdef HAVE_TIME_H #ifdef HAVE_TIME_H
# include <time.h> /* time() */ # include <time.h> /* time() */
#endif #endif
#ifdef HAVE_PTHREAD_H
# include <pthread.h>
#endif
#include <vlc/vlc.h> #include <vlc/vlc.h>
...@@ -48,7 +51,7 @@ extern void __wgetmainargs(int *argc, wchar_t ***wargv, wchar_t ***wenviron, ...@@ -48,7 +51,7 @@ extern void __wgetmainargs(int *argc, wchar_t ***wargv, wchar_t ***wenviron,
* Local prototypes. * Local prototypes.
*****************************************************************************/ *****************************************************************************/
#if !defined(WIN32) && !defined(UNDER_CE) #if !defined(WIN32) && !defined(UNDER_CE)
static void SigHandler ( int i_signal ); static void *SigHandler ( void *set );
#endif #endif
/***************************************************************************** /*****************************************************************************
...@@ -91,17 +94,30 @@ int main( int i_argc, char *ppsz_argv[] ) ...@@ -91,17 +94,30 @@ int main( int i_argc, char *ppsz_argv[] )
} }
#if !defined(WIN32) && !defined(UNDER_CE) #if !defined(WIN32) && !defined(UNDER_CE)
/* Set the signal handlers. SIGTERM is not intercepted, because we need at /* Synchronously intercepted signals. Thy request a clean shutdown,
* least one method to kill the program when all other methods failed, and * and force an unclean shutdown if they are triggered again 2+ seconds
* when we don't want to use SIGKILL. * later. We have to handle SIGTERM cleanly because of daemon mode.
* Note that we set the signals after the vlc_create call. */ * Note that we set the signals after the vlc_create call. */
signal( SIGINT, SigHandler ); static const int sigs[] = { SIGINT, SIGHUP, SIGQUIT, SIGTERM };
signal( SIGHUP, SigHandler ); /* Ignored signals */
signal( SIGQUIT, SigHandler ); static const int ignored[] = { SIGALRM, SIGPIPE };
sigset_t set;
pthread_t sigth;
sigemptyset (&set);
for (unsigned i = 0; i < sizeof (sigs) / sizeof (sigs[0]); i++)
sigaddset (&set, sigs[i]);
for (unsigned i = 0; i < sizeof (ignored) / sizeof (ignored[0]); i++)
sigaddset (&set, ignored[i]);
/* Block all these signals */
pthread_sigmask (SIG_BLOCK, &set, NULL);
/* Other signals */ for (unsigned i = 0; i < sizeof (ignored) / sizeof (ignored[0]); i++)
signal( SIGALRM, SIG_IGN ); sigdelset (&set, ignored[i]);
signal( SIGPIPE, SIG_IGN );
pthread_create (&sigth, NULL, SigHandler, &set);
#endif #endif
#ifdef WIN32 #ifdef WIN32
...@@ -155,6 +171,11 @@ int main( int i_argc, char *ppsz_argv[] ) ...@@ -155,6 +171,11 @@ int main( int i_argc, char *ppsz_argv[] )
i_ret = VLC_AddIntf( 0, NULL, VLC_TRUE, VLC_TRUE ); i_ret = VLC_AddIntf( 0, NULL, VLC_TRUE, VLC_TRUE );
#if !defined(WIN32) && !defined(UNDER_CE)
pthread_cancel (sigth);
pthread_join (sigth, NULL);
#endif
/* Finish the threads */ /* Finish the threads */
VLC_CleanUp( 0 ); VLC_CleanUp( 0 );
...@@ -168,42 +189,46 @@ int main( int i_argc, char *ppsz_argv[] ) ...@@ -168,42 +189,46 @@ int main( int i_argc, char *ppsz_argv[] )
/***************************************************************************** /*****************************************************************************
* SigHandler: system signal handler * SigHandler: system signal handler
***************************************************************************** *****************************************************************************
* This function is called when a fatal signal is received by the program. * This thread receives all handled signals synchronously.
* It tries to end the program in a clean way. * It tries to end the program in a clean way.
*****************************************************************************/ *****************************************************************************/
static void SigHandler( int i_signal ) static void *SigHandler( void *data )
{ {
static time_t abort_time = 0; const sigset_t *set = (sigset_t *)data;
static volatile vlc_bool_t b_die = VLC_FALSE; time_t abort_time = 0;
vlc_bool_t b_die = VLC_FALSE;
/* Once a signal has been trapped, the termination sequence will be for (;;)
* 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; int i_signal, state;
abort_time = time( NULL ); (void)sigwait (set, &i_signal);
fprintf( stderr, "signal %d received, terminating vlc - do it " /* Once a signal has been trapped, the termination sequence will be
"again in case it gets stuck\n", i_signal ); * armed and subsequent signals will be ignored to avoid sending
* signals to a libvlc structure having been destroyed */
/* Acknowledge the signal received */ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state);
VLC_Die( 0 ); if( !b_die )
} {
else if( time( NULL ) > abort_time + 2 ) b_die = VLC_TRUE;
{ abort_time = time( NULL );
/* If user asks again 1 or 2 seconds 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" ); fprintf( stderr, "signal %d received, terminating vlc - do it "
"again in case it gets stuck\n", i_signal );
abort(); /* Acknowledge the signal received */
VLC_Die( 0 );
}
else if( time( NULL ) > abort_time + 2 )
{
/* If user asks again 1 or 2 seconds later, die badly */
pthread_sigmask (SIG_UNBLOCK, set, NULL);
fprintf( stderr, "user insisted too much, dying badly\n" );
abort();
}
pthread_setcancelstate (state, NULL);
} }
/* Never reached */
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment