Changeset eeb6783303988aea7e6a19bc21249749c6b4f8ba

Show
Ignore:
Timestamp:
13/02/07 21:48:52 (2 years ago)
Author:
Rémi Denis-Courmont <rem@videolan.org>
git-committer:
Rémi Denis-Courmont <rem@videolan.org> 1171399732 +0000
git-parent:

[eb14a72b31b8a5687adaac1cc4f5e1467f78c7ef]

git-author:
Rémi Denis-Courmont <rem@videolan.org> 1171399732 +0000
Message:

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)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • src/vlc.c

    r1c3bc89 reeb6783  
    3636#   include <time.h>                                               /* time() */ 
    3737#endif 
     38#ifdef HAVE_PTHREAD_H 
     39#   include <pthread.h> 
     40#endif 
    3841 
    3942#include <vlc/vlc.h> 
     
    4952 *****************************************************************************/ 
    5053#if !defined(WIN32) && !defined(UNDER_CE) 
    51 static void SigHandler  ( int i_signal ); 
     54static void *SigHandler  ( void *set ); 
    5255#endif 
    5356 
     
    9295 
    9396#if !defined(WIN32) && !defined(UNDER_CE) 
    94     /* Set the signal handlers. SIGTERM is not intercepted, because we need at 
    95      * least one method to kill the program when all other methods failed, and 
    96      * when we don't want to use SIGKILL
     97    /* Synchronously intercepted signals. Thy request a clean shutdown, 
     98     * and force an unclean shutdown if they are triggered again 2+ seconds 
     99     * later. We have to handle SIGTERM cleanly because of daemon mode
    97100     * Note that we set the signals after the vlc_create call. */ 
    98     signal( SIGINT,  SigHandler ); 
    99     signal( SIGHUP,  SigHandler ); 
    100     signal( SIGQUIT, SigHandler ); 
    101  
    102     /* Other signals */ 
    103     signal( SIGALRM, SIG_IGN ); 
    104     signal( SIGPIPE, SIG_IGN ); 
     101    static const int sigs[] = { SIGINT, SIGHUP, SIGQUIT, SIGTERM }; 
     102    /* Ignored signals */ 
     103    static const int ignored[] = { SIGALRM, SIGPIPE }; 
     104 
     105    sigset_t set; 
     106    pthread_t sigth; 
     107 
     108    sigemptyset (&set); 
     109    for (unsigned i = 0; i < sizeof (sigs) / sizeof (sigs[0]); i++) 
     110        sigaddset (&set, sigs[i]); 
     111    for (unsigned i = 0; i < sizeof (ignored) / sizeof (ignored[0]); i++) 
     112        sigaddset (&set, ignored[i]); 
     113 
     114    /* Block all these signals */ 
     115    pthread_sigmask (SIG_BLOCK, &set, NULL); 
     116 
     117    for (unsigned i = 0; i < sizeof (ignored) / sizeof (ignored[0]); i++) 
     118        sigdelset (&set, ignored[i]); 
     119 
     120    pthread_create (&sigth, NULL, SigHandler, &set); 
    105121#endif 
    106122 
     
    156172    i_ret = VLC_AddIntf( 0, NULL, VLC_TRUE, VLC_TRUE ); 
    157173 
     174#if !defined(WIN32) && !defined(UNDER_CE) 
     175    pthread_cancel (sigth); 
     176    pthread_join (sigth, NULL); 
     177#endif 
     178 
    158179    /* Finish the threads */ 
    159180    VLC_CleanUp( 0 ); 
     
    169190 * SigHandler: system signal handler 
    170191 ***************************************************************************** 
    171  * This function is called when a fatal signal is received by the program
     192 * This thread receives all handled signals synchronously
    172193 * It tries to end the program in a clean way. 
    173194 *****************************************************************************/ 
    174 static void SigHandler( int i_signal
     195static void *SigHandler( void *data
    175196{ 
    176     static time_t abort_time = 0; 
    177     static volatile vlc_bool_t b_die = VLC_FALSE; 
    178  
    179     /* Once a signal has been trapped, the termination sequence will be 
    180      * armed and subsequent signals will be ignored to avoid sending signals 
    181      * to a libvlc structure having been destroyed */ 
    182  
    183     if( !b_die ) 
    184     { 
    185         b_die = VLC_TRUE; 
    186         abort_time = time( NULL ); 
    187  
    188         fprintf( stderr, "signal %d received, terminating vlc - do it " 
    189                          "again in case it gets stuck\n", i_signal ); 
    190  
    191         /* Acknowledge the signal received */ 
    192         VLC_Die( 0 ); 
    193     } 
    194     else if( time( NULL ) > abort_time + 2 ) 
    195     { 
    196         /* If user asks again 1 or 2 seconds later, die badly */ 
    197         signal( SIGINT,  SIG_DFL ); 
    198         signal( SIGHUP,  SIG_DFL ); 
    199         signal( SIGQUIT, SIG_DFL ); 
    200         signal( SIGALRM, SIG_DFL ); 
    201         signal( SIGPIPE, SIG_DFL ); 
    202  
    203         fprintf( stderr, "user insisted too much, dying badly\n" ); 
    204  
    205         abort(); 
    206     } 
     197    const sigset_t *set = (sigset_t *)data; 
     198    time_t abort_time = 0; 
     199    vlc_bool_t b_die = VLC_FALSE; 
     200 
     201    for (;;) 
     202    { 
     203        int i_signal, state; 
     204        (void)sigwait (set, &i_signal); 
     205 
     206        /* Once a signal has been trapped, the termination sequence will be 
     207         * armed and subsequent signals will be ignored to avoid sending 
     208         * signals to a libvlc structure having been destroyed */ 
     209 
     210        pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state); 
     211        if( !b_die ) 
     212        { 
     213            b_die = VLC_TRUE; 
     214            abort_time = time( NULL ); 
     215 
     216            fprintf( stderr, "signal %d received, terminating vlc - do it " 
     217                            "again in case it gets stuck\n", i_signal ); 
     218 
     219            /* Acknowledge the signal received */ 
     220            VLC_Die( 0 ); 
     221        } 
     222        else if( time( NULL ) > abort_time + 2 ) 
     223        { 
     224            /* If user asks again 1 or 2 seconds later, die badly */ 
     225            pthread_sigmask (SIG_UNBLOCK, set, NULL); 
     226            fprintf( stderr, "user insisted too much, dying badly\n" ); 
     227            abort(); 
     228        } 
     229        pthread_setcancelstate (state, NULL); 
     230    } 
     231    /* Never reached */ 
    207232} 
    208233#endif