From 2ac6b62df2b4ce1e2c1a8afeea1ce1c9cf4b70f4 Mon Sep 17 00:00:00 2001 From: axel Date: Thu, 6 Oct 2005 21:54:16 +1000 Subject: [PATCH] Various updates to signal event handling darcs-hash:20051006115416-ac50b-ab0a1be946f758cfdeaa5dfe172f417acb9b6e79.gz --- builtin.c | 55 +++++++++++++++++++++++++++++++++++++++++------ event.c | 64 +++++++++++++++++++++++++++++++++++++++++-------------- event.h | 5 ++++- exec.c | 7 +----- parser.c | 1 + signal.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++----- signal.h | 13 +++++++++++ 7 files changed, 175 insertions(+), 34 deletions(-) diff --git a/builtin.c b/builtin.c index 152bb670f..bb54cd216 100644 --- a/builtin.c +++ b/builtin.c @@ -800,11 +800,24 @@ static int builtin_function( wchar_t **argv ) case 's': { - event_t *e = malloc( sizeof(event_t)); + int sig = wcs2sig( woptarg ); + event_t *e; + + if( sig < 0 ) + { + sb_printf( sb_err, + L"%ls: Unknown signal %ls\n", + argv[0], + woptarg ); + res=1; + break; + } + + e = malloc( sizeof(event_t)); if( !e ) die_mem(); e->type = EVENT_SIGNAL; - e->signal = wcs2sig( woptarg ); + e->signal = sig; e->function_name=0; al_push( events, e ); break; @@ -812,7 +825,19 @@ static int builtin_function( wchar_t **argv ) case 'v': { - event_t *e = malloc( sizeof(event_t)); + event_t *e; + + if( !wcsvarname( woptarg ) ) + { + sb_printf( sb_err, + L"%ls: Invalid variable name %ls\n", + argv[0], + woptarg ); + res=1; + break; + } + + e = malloc( sizeof(event_t)); if( !e ) die_mem(); e->type = EVENT_VARIABLE; @@ -824,11 +849,29 @@ static int builtin_function( wchar_t **argv ) case 'x': { - event_t *e = malloc( sizeof(event_t)); + pid_t pid; + wchar_t *end; + event_t *e; + + errno = 0; + pid = wcstol( woptarg, &end, 10 ); + if( errno || !end || *end ) + { + sb_printf( sb_err, + L"%ls: Invalid process id %ls\n", + argv[0], + woptarg ); + res=1; + break; + } + + + + e = malloc( sizeof(event_t)); if( !e ) die_mem(); e->type = EVENT_EXIT; - e->pid = wcstol( woptarg, 0, 10 ); + e->pid = pid; e->function_name=0; al_push( events, e ); break; @@ -916,7 +959,7 @@ static int builtin_function( wchar_t **argv ) al_foreach( events, (void (*)(const void *))&event_free ); al_destroy( events ); - + free( events ); } else { diff --git a/event.c b/event.c index acc8d873c..dc75e68f1 100644 --- a/event.c +++ b/event.c @@ -131,20 +131,24 @@ void event_add_handler( event_t *event ) if( !events ) events = al_new(); - debug( 1, L"add event of type %d", e->type ); - + if( e->type == EVENT_SIGNAL ) + { + signal_handle( e->signal, 1 ); + } + al_push( events, e ); } void event_remove( event_t *criterion ) { int i; - array_list_t *new_list = al_new(); - + array_list_t *new_list=0; + event_t e; + /* Because of concurrency issues, env_remove does not actually free - anything - instead it simply moves all events that should be - removed to the killme list. + any events - instead it simply moves all events that should be + removed from the event list to the killme list. */ if( !events ) @@ -159,30 +163,56 @@ void event_remove( event_t *criterion ) killme = al_new(); al_push( killme, n ); + + /* + If this event was a signal handler and no other handler handles + the specified signal type, do not handle that type of signal any + more. + */ + if( n->type == EVENT_SIGNAL ) + { + e.type = EVENT_SIGNAL; + e.signal = n->signal; + e.function_name = 0; + + if( event_get( &e, 0 ) == 1 ) + { + signal_handle( e.signal, 0 ); + } + } + } else { + if( !new_list ) + new_list = al_new(); al_push( new_list, n ); } } al_destroy( events ); + free( events ); events = new_list; } -void event_get( event_t *criterion, array_list_t *out ) +int event_get( event_t *criterion, array_list_t *out ) { int i; + int found = 0; if( !events ) - return; + return 0; for( i=0; ifunction_name ); + free( (void *)e->function_name ); if( e->type == EVENT_VARIABLE ) - free( e->variable ); + free( (void *)e->variable ); free( e ); } diff --git a/event.h b/event.h index 7e032cdce..8e9685a9e 100644 --- a/event.h +++ b/event.h @@ -74,8 +74,11 @@ void event_remove( event_t *event ); Return all events which match the specified event class \param criterion Is the class of events to return. If the criterion has a non-null function_name, only events which trigger the specified function will return. + \param out the list to add events to. May be 0, in which case no events will be added, but the result count will still be valid + + \return the number of found matches */ -void event_get( event_t *criterion, array_list_t *out ); +int event_get( event_t *criterion, array_list_t *out ); /** Fire the specified event. The function_name field of the event must diff --git a/exec.c b/exec.c index b3d34a730..f9f922ef6 100644 --- a/exec.c +++ b/exec.c @@ -391,12 +391,7 @@ static void setup_child_process( job_t *j ) } /* Set the handling for job control signals back to the default. */ - signal (SIGINT, SIG_DFL); - signal (SIGQUIT, SIG_DFL); - signal (SIGTSTP, SIG_DFL); - signal (SIGTTIN, SIG_DFL); - signal (SIGTTOU, SIG_DFL); - signal (SIGCHLD, SIG_DFL); + signal_reset_handlers(); sigset_t chldset; sigemptyset( &chldset ); diff --git a/parser.c b/parser.c index a50dfe81f..1268944f8 100644 --- a/parser.c +++ b/parser.c @@ -212,6 +212,7 @@ void parser_pop_block() free( current_block->function_description ); al_foreach( current_block->function_events, (void (*)(const void *))&event_free ); + al_destroy( current_block->function_events ); free( current_block->function_events ); break; } diff --git a/signal.c b/signal.c index 720dde10e..f2f1f276f 100644 --- a/signal.c +++ b/signal.c @@ -12,8 +12,11 @@ The library for various signal related issues #include #include #include +#include #include "common.h" +#include "util.h" +#include "wutil.h" #include "signal.h" #include "event.h" #include "reader.h" @@ -250,7 +253,9 @@ static int match_signal_name( const wchar_t *canonical, int wcs2sig( const wchar_t *str ) { - int i; + int i, res; + wchar_t *end=0; + for( i=0; lookup[i].desc ; i++ ) { if( match_signal_name( lookup[i].name, str) ) @@ -258,6 +263,11 @@ int wcs2sig( const wchar_t *str ) return lookup[i].signal; } } + errno=0; + res = wcstol( str, &end, 10 ); + if( !errno && end && !*end ) + return res; + return -1; } @@ -318,6 +328,31 @@ static void handle_int( int sig, siginfo_t *info, void *context ) default_handler( sig, info, context); } +/** + sigchld handler. Does notification and calls the handler in proc.c +*/ +static void handle_chld( int sig, siginfo_t *info, void *context ) +{ + job_handle_signal( sig, info, context ); + default_handler( sig, info, context); +} + +void signal_reset_handlers() +{ + int i; + + struct sigaction act; + sigemptyset( & act.sa_mask ); + act.sa_flags=0; + act.sa_handler=SIG_DFL; + + for( i=0; lookup[i].desc ; i++ ) + { + sigaction( lookup[i].signal, &act, 0); + } +} + + /** Sets appropriate signal handlers. */ @@ -338,7 +373,6 @@ void signal_set_handlers() sigaction( SIGTTIN, &act, 0); sigaction( SIGTTOU, &act, 0); sigaction( SIGCHLD, &act, 0); - sigaction( SIGALRM, &act, 0); /* Ignore sigpipe, it is generated if fishd dies, but we can @@ -348,7 +382,6 @@ void signal_set_handlers() if( is_interactive ) { - /* Interactive mode. Ignore interactive signals. We are a shell, we know whats best for the user. ;-) @@ -370,7 +403,7 @@ void signal_set_handlers() exit(1); } - act.sa_sigaction = &job_handle_signal; + act.sa_sigaction = &handle_chld; act.sa_flags = SA_SIGINFO; if( sigaction( SIGCHLD, &act, 0) ) { @@ -400,7 +433,7 @@ void signal_set_handlers() act.sa_handler=SIG_DFL; - act.sa_sigaction = &job_handle_signal; + act.sa_sigaction = &handle_chld; act.sa_flags = SA_SIGINFO; if( sigaction( SIGCHLD, &act, 0) ) { @@ -410,3 +443,24 @@ void signal_set_handlers() } } +void signal_handle( int sig, int do_handle ) +{ + struct sigaction act; + + /* + These should always be handled + */ + if( (sig == SIGINT) || + (sig == SIGQUIT) || + (sig == SIGTSTP) || + (sig == SIGTTIN) || + (sig == SIGTTOU) || + (sig == SIGCHLD) ) + return; + + sigemptyset( & act.sa_mask ); + act.sa_flags=SA_SIGINFO; + act.sa_sigaction = (do_handle?&default_handler:SIG_DFL); + sigaction( sig, &act, 0); +} + diff --git a/signal.h b/signal.h index f76966110..ef491a143 100644 --- a/signal.h +++ b/signal.h @@ -20,4 +20,17 @@ const wchar_t *sig2wcs( int sig ); */ const wchar_t *sig_description( int sig ); +/** + Set all signal handlers to SIG_DFL +*/ +void signal_reset_handlers(); + +/** + Set signal handlers to fish default handlers +*/ void signal_set_handlers(); + +/** + Tell fish to catch the specified signal and fire an event, instead of performing the default action +*/ +void signal_handle( int sig, int do_handle );