svn commit: trunk/busybox/shell

vda at busybox.net vda at busybox.net
Sun Feb 10 19:02:53 UTC 2008


Author: vda
Date: 2008-02-10 11:02:53 -0800 (Sun, 10 Feb 2008)
New Revision: 20973

Log:
ash: fix "orwell bug" 1984. Testcase:
    trap_handler() {
        echo trap
    }
    trap trap_handler USR1
    sleep 3600 &
    while true; do wait; done



Added:
   trunk/busybox/shell/ash_doc.txt

Modified:
   trunk/busybox/shell/ash.c


Changeset:
Modified: trunk/busybox/shell/ash.c
===================================================================
--- trunk/busybox/shell/ash.c	2008-02-10 16:00:30 UTC (rev 20972)
+++ trunk/busybox/shell/ash.c	2008-02-10 19:02:53 UTC (rev 20973)
@@ -164,7 +164,16 @@
 	char *arg0; /* value of $0 */
 
 	struct jmploc *exception_handler;
-	int exception;
+
+// disabled by vda: cannot understand how it was supposed to work -
+// cannot fix bugs. That's why you have to explain your non-trivial designs!
+//	/* do we generate EXSIG events */
+//	int exsig; /* counter */
+	volatile int suppressint; /* counter */
+	volatile /*sig_atomic_t*/ smallint intpending; /* 1 = got SIGINT */
+	/* last pending signal */
+	volatile /*sig_atomic_t*/ smallint pendingsig;
+	smallint exception; /* kind of exception (0..5) */
 	/* exceptions */
 #define EXINT 0         /* SIGINT received */
 #define EXERROR 1       /* a generic error */
@@ -172,12 +181,6 @@
 #define EXEXEC 3        /* command execution failed */
 #define EXEXIT 4        /* exit the shell */
 #define EXSIG 5         /* trapped signal in wait(1) */
-	volatile int suppressint;
-	volatile sig_atomic_t intpending;
-	/* do we generate EXSIG events */
-	int exsig;
-	/* last pending signal */
-	volatile sig_atomic_t pendingsig;
 
 	/* trap handler commands */
 	char *trap[NSIG];
@@ -211,7 +214,7 @@
 #define exception         (G_misc.exception        )
 #define suppressint       (G_misc.suppressint      )
 #define intpending        (G_misc.intpending       )
-#define exsig             (G_misc.exsig            )
+//#define exsig             (G_misc.exsig            )
 #define pendingsig        (G_misc.pendingsig       )
 #define trap      (G_misc.trap     )
 #define isloginsh (G_misc.isloginsh)
@@ -281,6 +284,7 @@
 	i = EXSIG;
 	if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
 		if (!(rootshell && iflag)) {
+			/* Kill ourself with SIGINT */
 			signal(SIGINT, SIG_DFL);
 			raise(SIGINT);
 		}
@@ -333,15 +337,6 @@
 			raise_interrupt(); \
 	} while (0)
 
-#define EXSIGON \
-	do { \
-		exsig++; \
-		xbarrier(); \
-		if (pendingsig) \
-			raise_exception(EXSIG); \
-	} while (0)
-/* EXSIG is turned off by evalbltin(). */
-
 /*
  * Ignore a signal. Only one usage site - in forkchild()
  */
@@ -363,10 +358,10 @@
 	gotsig[signo - 1] = 1;
 	pendingsig = signo;
 
-	if (exsig || (signo == SIGINT && !trap[SIGINT])) {
+	if ( /* exsig || */ (signo == SIGINT && !trap[SIGINT])) {
 		if (!suppressint) {
 			pendingsig = 0;
-			raise_interrupt();
+			raise_interrupt(); /* does not return */
 		}
 		intpending = 1;
 	}
@@ -3256,12 +3251,11 @@
 	struct sigaction act;
 
 	t = trap[signo];
+	action = S_IGN;
 	if (t == NULL)
 		action = S_DFL;
 	else if (*t != '\0')
 		action = S_CATCH;
-	else
-		action = S_IGN;
 	if (rootshell && action == S_DFL) {
 		switch (signo) {
 		case SIGINT:
@@ -3294,7 +3288,7 @@
 		/*
 		 * current setting unknown
 		 */
-		if (sigaction(signo, 0, &act) == -1) {
+		if (sigaction(signo, NULL, &act) == -1) {
 			/*
 			 * Pretend it worked; maybe we should give a warning
 			 * here, but other shells don't. We don't alter
@@ -3302,19 +3296,19 @@
 			 */
 			return;
 		}
+		tsig = S_RESET; /* force to be set */
 		if (act.sa_handler == SIG_IGN) {
+			tsig = S_HARD_IGN;
 			if (mflag
 			 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
 			) {
 				tsig = S_IGN;   /* don't hard ignore these */
-			} else
-				tsig = S_HARD_IGN;
-		} else {
-			tsig = S_RESET; /* force to be set */
+			}
 		}
 	}
 	if (tsig == S_HARD_IGN || tsig == action)
 		return;
+	act.sa_handler = SIG_DFL;
 	switch (action) {
 	case S_CATCH:
 		act.sa_handler = onsig;
@@ -3322,13 +3316,11 @@
 	case S_IGN:
 		act.sa_handler = SIG_IGN;
 		break;
-	default:
-		act.sa_handler = SIG_DFL;
 	}
 	*t = action;
 	act.sa_flags = 0;
 	sigfillset(&act.sa_mask);
-	sigaction(signo, &act, 0);
+	sigaction(signo, &act, NULL);
 }
 
 /* mode flags for set_curjob */
@@ -3763,7 +3755,8 @@
 	if (jobctl)
 		wait_flags |= WUNTRACED;
 #endif
-	return waitpid(-1, status, wait_flags); // safe_waitpid?
+	/* NB: _not_ safe_waitpid, we need to detect EINTR */
+	return waitpid(-1, status, wait_flags);
 }
 
 /*
@@ -3781,8 +3774,14 @@
 	TRACE(("dowait(%d) called\n", wait_flags));
 	pid = waitproc(wait_flags, &status);
 	TRACE(("wait returns pid=%d, status=%d\n", pid, status));
-	if (pid <= 0)
+	if (pid <= 0) {
+		/* If we were doing blocking wait and (probably) got EINTR,
+		 * check for pending sigs received while waiting.
+		 * (NB: can be moved into callers if needed) */
+		if (wait_flags == DOWAIT_BLOCK && pendingsig)
+			raise_exception(EXSIG);
 		return pid;
+	}
 	INT_OFF;
 	thisjob = NULL;
 	for (jp = curjob; jp; jp = jp->prev_job) {
@@ -4004,7 +4003,10 @@
 	int retval;
 	struct job *jp;
 
-	EXSIGON;
+//	exsig++;
+//	xbarrier();
+	if (pendingsig)
+		raise_exception(EXSIG);
 
 	nextopt(nullstr);
 	retval = 0;
@@ -4015,10 +4017,8 @@
 		for (;;) {
 			jp = curjob;
 			while (1) {
-				if (!jp) {
-					/* no running procs */
-					goto out;
-				}
+				if (!jp) /* no running procs */
+					goto ret;
 				if (jp->state == JOBRUNNING)
 					break;
 				jp->waited = 1;
@@ -4051,7 +4051,7 @@
 		;
 	} while (*++argv);
 
- out:
+ ret:
 	return retval;
 }
 
@@ -4450,7 +4450,7 @@
 	char **tp;
 
 	for (tp = trap; tp < &trap[NSIG]; tp++) {
-		if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
+		if (*tp && **tp) {      /* trap not NULL or "" (SIG_IGN) */
 			INT_OFF;
 			free(*tp);
 			*tp = NULL;
@@ -4613,8 +4613,8 @@
 		 * intuit from the subprocess exit status whether a SIGINT
 		 * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
 		 */
-		if (jp->sigint)
-			raise(SIGINT);
+		if (jp->sigint) /* TODO: do the same with all signals */
+			raise(SIGINT); /* ... by raise(jp->sig) instead? */
 	}
 	if (jp->state == JOBDONE)
 #endif
@@ -6268,7 +6268,7 @@
 		p++;
 	if (*p == '.')
 		matchdot++;
-	while (! intpending && (dp = readdir(dirp)) != NULL) {
+	while (!intpending && (dp = readdir(dirp)) != NULL) {
 		if (dp->d_name[0] == '.' && ! matchdot)
 			continue;
 		if (pmatch(start, dp->d_name)) {
@@ -7437,7 +7437,7 @@
 	char *q;
 	int i;
 	int savestatus;
-	int skip = 0;
+	int skip;
 
 	savestatus = exitstatus;
 	pendingsig = 0;
@@ -7454,10 +7454,10 @@
 		skip = evalstring(p, SKIPEVAL);
 		exitstatus = savestatus;
 		if (skip)
-			break;
+			return skip;
 	}
 
-	return skip;
+	return 0;
 }
 
 /* forward declarations - evaluation is fairly recursive business... */
@@ -8434,22 +8434,15 @@
 		}
 		if (evalbltin(cmdentry.u.cmd, argc, argv)) {
 			int exit_status;
-			int i, j;
-
-			i = exception;
+			int i = exception;
 			if (i == EXEXIT)
 				goto raise;
-
 			exit_status = 2;
-			j = 0;
 			if (i == EXINT)
-				j = SIGINT;
+				exit_status = 128 + SIGINT;
 			if (i == EXSIG)
-				j = pendingsig;
-			if (j)
-				exit_status = j + 128;
+				exit_status = 128 + pendingsig;
 			exitstatus = exit_status;
-
 			if (i == EXINT || spclbltin > 0) {
  raise:
 				longjmp(exception_handler->loc, 1);
@@ -8499,7 +8492,7 @@
 	exitstatus |= ferror(stdout);
 	clearerr(stdout);
 	commandname = savecmdname;
-	exsig = 0;
+//	exsig = 0;
 	exception_handler = savehandler;
 
 	return i;

Added: trunk/busybox/shell/ash_doc.txt
===================================================================
--- trunk/busybox/shell/ash_doc.txt	                        (rev 0)
+++ trunk/busybox/shell/ash_doc.txt	2008-02-10 19:02:53 UTC (rev 20973)
@@ -0,0 +1,31 @@
+	Wait + signals
+
+We had some bugs here which are hard to test in testsuite.
+
+Bug 1280 (http://busybox.net/bugs/view.php?id=1280):
+was misbehaving in interactive ash. Correct behavior:
+
+$ sleep 20 &
+$ wait
+^C
+$ wait
+^C
+$ wait
+^C
+...
+
+Bug 1984 (http://busybox.net/bugs/view.php?id=1984):
+traps were not triggering:
+
+trap_handler_usr () {
+    echo trap usr
+}
+trap_handler_int () {
+    echo trap int
+}
+trap trap_handler_usr USR1
+trap trap_handler_int INT
+sleep 3600 &
+echo "Please do: kill -USR1 $$"
+echo "or: kill -INT $$"
+while true; do wait; echo wait interrupted; done




More information about the busybox-cvs mailing list