From 8d7be232a39c6fb85b6870d1a705ceca48bed869 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 25 May 2009 16:38:32 +0200 Subject: [PATCH] hush: fix SIGCHLD counting code, but keep it disabled for now. Signed-off-by: Denys Vlasenko --- shell/hush.c | 85 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 19 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index acc8ef944..fd839d061 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -69,7 +69,7 @@ #endif -/* Debug build knobs */ +/* Build knobs */ #define LEAK_HUNTING 0 #define BUILD_AS_NOMMU 0 /* Enable/disable sanity checks. Ok to enable in production, @@ -77,6 +77,13 @@ * Keeping 1 for now even in released versions. */ #define HUSH_DEBUG 1 +/* Slightly bigger (+200 bytes), but faster hush. + * So far it only enables a trick with counting SIGCHLDs and forks, + * which allows us to do fewer waitpid's. + * (we can detect a case where neither forks were done nor SIGCHLDs happened + * and therefore waitpid will return the same result as last time) + */ +#define ENABLE_HUSH_FAST 0 #if BUILD_AS_NOMMU @@ -485,8 +492,11 @@ struct globals { struct function *top_func; #endif /* Signal and trap handling */ -// unsigned count_SIGCHLD; -// unsigned handled_SIGCHLD; +#if ENABLE_HUSH_FAST + unsigned count_SIGCHLD; + unsigned handled_SIGCHLD; + smallint last_waitpid_was_0; +#endif /* which signals have non-DFL handler (even with no traps set)? */ unsigned non_DFL_mask; char **traps; /* char *traps[NSIG] */ @@ -1050,7 +1060,7 @@ static void restore_G_args(save_arg_t *sv, char **argv) * Restore blocked signal set to one inherited by shell just prior to exec. * * Note: as a result, we do not use signal handlers much. The only uses - * are to count SIGCHLDs [disabled - bug somewhere, + bloat] + * are to count SIGCHLDs * and to restore tty pgrp on signal-induced exit. */ enum { @@ -1067,10 +1077,13 @@ enum { #endif }; -//static void SIGCHLD_handler(int sig UNUSED_PARAM) -//{ -// G.count_SIGCHLD++; -//} +#if ENABLE_HUSH_FAST +static void SIGCHLD_handler(int sig UNUSED_PARAM) +{ + G.count_SIGCHLD++; +//bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); +} +#endif #if ENABLE_HUSH_JOB @@ -1158,9 +1171,12 @@ static int check_and_run_traps(int sig) } /* not a trap: special action */ switch (sig) { -// case SIGCHLD: -// G.count_SIGCHLD++; -// break; +#if ENABLE_HUSH_FAST + case SIGCHLD: + G.count_SIGCHLD++; +//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); + break; +#endif case SIGINT: /* Builtin was ^C'ed, make it look prettier: */ bb_putchar('\n'); @@ -2665,6 +2681,10 @@ static void setup_heredoc(struct redir_struct *redir) #endif } /* parent */ +#if ENABLE_HUSH_FAST + G.count_SIGCHLD++; +//bb_error_msg("[%d] fork in setup_heredoc: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); +#endif enable_restore_tty_pgrp_on_exit(); #if !BB_MMU free(to_free); @@ -3273,9 +3293,16 @@ static int checkjobs(struct pipe* fg_pipe) debug_printf_jobs("checkjobs %p\n", fg_pipe); errno = 0; -// if (G.handled_SIGCHLD == G.count_SIGCHLD) -// /* avoid doing syscall, nothing there anyway */ -// return rcode; +#if ENABLE_HUSH_FAST + if (G.handled_SIGCHLD == G.count_SIGCHLD) { +//bb_error_msg("[%d] checkjobs: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d was 0?:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD, G.last_waitpid_was_0); + /* avoid doing syscall, nothing there anyway */ + if (G.last_waitpid_was_0) + return 0; + errno = ECHILD; + return -1; + } +#endif attributes = WUNTRACED; if (fg_pipe == NULL) @@ -3294,13 +3321,20 @@ static int checkjobs(struct pipe* fg_pipe) int i; int dead; -// i = G.count_SIGCHLD; +#if ENABLE_HUSH_FAST + i = G.count_SIGCHLD; +#endif childpid = waitpid(-1, &status, attributes); if (childpid <= 0) { if (childpid && errno != ECHILD) bb_perror_msg("waitpid"); -// else /* Until next SIGCHLD, waitpid's are useless */ -// G.handled_SIGCHLD = i; +#if ENABLE_HUSH_FAST + else { /* Until next SIGCHLD, waitpid's are useless */ + G.last_waitpid_was_0 = (childpid == 0); + G.handled_SIGCHLD = i; +//bb_error_msg("[%d] checkjobs: waitpid returned <= 0, G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); + } +#endif break; } dead = WIFEXITED(status) || WIFSIGNALED(status); @@ -3696,6 +3730,10 @@ static int run_pipe(struct pipe *pi) } /* parent or error */ +#if ENABLE_HUSH_FAST + G.count_SIGCHLD++; +//bb_error_msg("[%d] fork in run_pipe: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); +#endif enable_restore_tty_pgrp_on_exit(); #if !BB_MMU /* Clean up after vforked child */ @@ -4861,6 +4899,10 @@ static FILE *generate_stream_from_string(const char *s) } /* parent */ +#if ENABLE_HUSH_FAST + G.count_SIGCHLD++; +//bb_error_msg("[%d] fork in generate_stream_from_string: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); +#endif enable_restore_tty_pgrp_on_exit(); #if !BB_MMU free(to_free); @@ -5990,9 +6032,14 @@ static void block_signals(int second_time) second_time ? NULL : &G.inherited_set); /* POSIX allows shell to re-enable SIGCHLD * even if it was SIG_IGN on entry */ -// G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ +#if ENABLE_HUSH_FAST + G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ if (!second_time) - signal(SIGCHLD, SIG_DFL); // SIGCHLD_handler); + signal(SIGCHLD, SIGCHLD_handler); +#else + if (!second_time) + signal(SIGCHLD, SIG_DFL); +#endif } #if ENABLE_HUSH_JOB