[git commit] hush: install signal handlers with filled sigmask

Denys Vlasenko vda.linux at googlemail.com
Thu May 12 21:06:20 UTC 2011


commit: http://git.busybox.net/busybox/commit/?id=0806e401d6747c391fa0427e0ccba9951f9a1c3d
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
install_sighandler                                     -      39     +39
hush_main                                           1001    1031     +30
builtin_trap                                         386     392      +6
install_sighandlers                                  121     123      +2
switch_off_special_sigs                               87      86      -1
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 3/1 up/down: 77/-1)              Total: 76 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/hush.c |   37 ++++++++++++++++++++++++++++---------
 1 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/shell/hush.c b/shell/hush.c
index 132b974..4c348ec 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -815,6 +815,7 @@ struct globals {
 	unsigned long memleak_value;
 	int debug_indent;
 #endif
+	struct sigaction sa;
 	char user_input_buf[ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 2];
 };
 #define G (*ptr_to_globals)
@@ -823,6 +824,9 @@ struct globals {
  * is global, thus "G." prefix is a useful hint */
 #define INIT_G() do { \
 	SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+	/* memset(&G.sa, 0, sizeof(G.sa)); */  \
+	sigfillset(&G.sa.sa_mask); \
+	G.sa.sa_flags = SA_RESTART; \
 } while (0)
 
 
@@ -1414,9 +1418,6 @@ static void restore_G_args(save_arg_t *sv, char **argv)
  * Standard says "When a subshell is entered, traps that are not being ignored
  * are set to the default actions". bash interprets it so that traps which
  * are set to '' (ignore) are NOT reset to defaults. We do the same.
- *
- * TODO: don't use signal() to install sighandlers: need to mask ALL signals
- * while handler runs. I saw signal nesting in one strace, race window isn't small.
  */
 enum {
 	SPECIAL_INTERACTIVE_SIGS = 0
@@ -1444,6 +1445,24 @@ static void record_pending_signo(int sig)
 #endif
 }
 
+static sighandler_t install_sighandler(int sig, sighandler_t handler)
+{
+	struct sigaction old_sa;
+
+	/* We could use signal() to install handlers... almost:
+	 * except that we need to mask ALL signals while handlers run.
+	 * I saw signal nesting in strace, race window isn't small.
+	 * SA_RESTART is also needed, but in Linux, signal()
+	 * sets SA_RESTART too.
+	 */
+	/* memset(&G.sa, 0, sizeof(G.sa)); - already done */
+	/* sigfillset(&G.sa.sa_mask);      - already done */
+	/* G.sa.sa_flags = SA_RESTART;     - already done */
+	G.sa.sa_handler = handler;
+	sigaction(sig, &G.sa, &old_sa);
+	return old_sa.sa_handler;
+}
+
 #if ENABLE_HUSH_JOB
 
 /* After [v]fork, in child: do not restore tty pgrp on xfunc death */
@@ -5451,7 +5470,7 @@ static void switch_off_special_sigs(unsigned mask)
 			G.traps[sig] = NULL;
 		}
 		/* We are here only if no trap or trap was not '' */
-		signal(sig, SIG_DFL);
+		install_sighandler(sig, SIG_DFL);
 	}
 }
 
@@ -5496,7 +5515,7 @@ static void reset_traps_to_defaults(void)
 		/* There is no signal for trap 0 (EXIT) */
 		if (sig == 0)
 			continue;
-		signal(sig, pick_sighandler(sig));
+		install_sighandler(sig, pick_sighandler(sig));
 	}
 }
 
@@ -7524,7 +7543,7 @@ static void install_sighandlers(unsigned mask)
 		sig++;
 		if (!(mask & 1))
 			continue;
-		old_handler = signal(sig, pick_sighandler(sig));
+		old_handler = install_sighandler(sig, pick_sighandler(sig));
 		/* POSIX allows shell to re-enable SIGCHLD
 		 * even if it was SIG_IGN on entry.
 		 * Therefore we skip IGN check for it:
@@ -7533,7 +7552,7 @@ static void install_sighandlers(unsigned mask)
 			continue;
 		if (old_handler == SIG_IGN) {
 			/* oops... restore back to IGN, and record this fact */
-			signal(sig, old_handler);
+			install_sighandler(sig, old_handler);
 			if (!G.traps)
 				G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
 			free(G.traps[sig]);
@@ -7854,7 +7873,7 @@ int hush_main(int argc, char **argv)
 				for (sig = 1; sig < NSIG; sig++) {
 					if (empty_trap_mask & (1LL << sig)) {
 						G.traps[sig] = xzalloc(1); /* == xstrdup(""); */
-						signal(sig, SIG_IGN);
+						install_sighandler(sig, SIG_IGN);
 					}
 				}
 			}
@@ -8389,7 +8408,7 @@ static int FAST_FUNC builtin_trap(char **argv)
 			else
 				/* We are removing trap handler */
 				handler = pick_sighandler(sig);
-			signal(sig, handler);
+			install_sighandler(sig, handler);
 		}
 		return ret;
 	}
-- 
1.7.3.4



More information about the busybox-cvs mailing list