aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-03-31 17:24:49 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-03-31 17:24:49 +0000
commit7566bae19715a493f40fd3fae4d69d10089af411 (patch)
tree90f41b90064a0530004c7df70b4036f2e9ad2859
parent70c6e40e478e83020e35a00517feab659ee0e782 (diff)
downloadbusybox-w32-7566bae19715a493f40fd3fae4d69d10089af411.tar.gz
busybox-w32-7566bae19715a493f40fd3fae4d69d10089af411.tar.bz2
busybox-w32-7566bae19715a493f40fd3fae4d69d10089af411.zip
hush: fix wait builtin
function old new delta builtin_wait 174 275 +101 sigwaitinfo - 48 +48 __GI_sigwaitinfo - 48 +48 check_and_run_traps 133 169 +36 checkjobs 349 380 +31 hush_main 971 991 +20 static.zero_timespec - 8 +8 run_list 2010 2016 +6 file_get 254 260 +6 static.zero_ts 8 - -8 ------------------------------------------------------------------------------ (add/remove: 3/1 grow/shrink: 6/0 up/down: 304/-8) Total: 296 bytes
-rw-r--r--shell/hush.c130
1 files changed, 99 insertions, 31 deletions
diff --git a/shell/hush.c b/shell/hush.c
index de3b56d21..af6763517 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -491,13 +491,14 @@ struct globals {
491 unsigned char charmap[256]; 491 unsigned char charmap[256];
492 char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2]; 492 char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
493 /* Signal and trap handling */ 493 /* Signal and trap handling */
494 char **traps; /* char *traps[NSIG] */ 494// unsigned count_SIGCHLD;
495// unsigned handled_SIGCHLD;
495 /* which signals have non-DFL handler (even with no traps set)? */ 496 /* which signals have non-DFL handler (even with no traps set)? */
496 unsigned non_DFL_mask; 497 unsigned non_DFL_mask;
498 char **traps; /* char *traps[NSIG] */
497 sigset_t blocked_set; 499 sigset_t blocked_set;
498 sigset_t inherited_set; 500 sigset_t inherited_set;
499}; 501};
500
501#define G (*ptr_to_globals) 502#define G (*ptr_to_globals)
502/* Not #defining name to G.name - this quickly gets unwieldy 503/* Not #defining name to G.name - this quickly gets unwieldy
503 * (too many defines). Also, I actually prefer to see when a variable 504 * (too many defines). Also, I actually prefer to see when a variable
@@ -829,12 +830,18 @@ static void free_strings(char **strings)
829 * POSIX says pending signal mask is cleared in child - no need to clear it. 830 * POSIX says pending signal mask is cleared in child - no need to clear it.
830 * Restore blocked signal set to one inherited by shell just prior to exec. 831 * Restore blocked signal set to one inherited by shell just prior to exec.
831 * 832 *
832 * Note: as a result, we do not use signal handlers much. The only use 833 * Note: as a result, we do not use signal handlers much. The only uses
833 * is to restore terminal pgrp on exit. 834 * are to count SIGCHLDs [disabled - bug somewhere, + bloat]
835 * and to restore tty pgrp on signal-induced exit.
834 * 836 *
835 * TODO: check/fix wait builtin to be interruptible. 837 * TODO: check/fix wait builtin to be interruptible.
836 */ 838 */
837 839
840//static void SIGCHLD_handler(int sig UNUSED_PARAM)
841//{
842// G.count_SIGCHLD++;
843//}
844
838/* called once at shell init */ 845/* called once at shell init */
839static void init_signal_mask(void) 846static void init_signal_mask(void)
840{ 847{
@@ -863,20 +870,24 @@ static void init_signal_mask(void)
863 mask >>= 1; 870 mask >>= 1;
864 sig++; 871 sig++;
865 } 872 }
873 sigdelset(&G.blocked_set, SIGCHLD);
866 sigprocmask(SIG_SETMASK, &G.blocked_set, &G.inherited_set); 874 sigprocmask(SIG_SETMASK, &G.blocked_set, &G.inherited_set);
867} 875}
868 876
869static void check_and_run_traps(void) 877static int check_and_run_traps(int sig)
870{ 878{
871 static const struct timespec zero_ts = { 0, 0 }; 879 static const struct timespec zero_timespec = { 0, 0 };
872 smalluint save_rcode; 880 smalluint save_rcode;
873 int sig; 881 int last_sig = 0;
874 882
883 if (sig)
884 goto jump_in;
875 while (1) { 885 while (1) {
876 sig = sigtimedwait(&G.blocked_set, NULL, &zero_ts); 886 sig = sigtimedwait(&G.blocked_set, NULL, &zero_timespec);
877 if (sig <= 0) 887 if (sig <= 0)
878 break; 888 break;
879 889 jump_in:
890 last_sig = sig;
880 if (G.traps && G.traps[sig]) { 891 if (G.traps && G.traps[sig]) {
881 if (G.traps[sig][0]) { 892 if (G.traps[sig][0]) {
882 /* We have user-defined handler */ 893 /* We have user-defined handler */
@@ -890,7 +901,11 @@ static void check_and_run_traps(void)
890 } 901 }
891 /* not a trap: special action */ 902 /* not a trap: special action */
892 switch (sig) { 903 switch (sig) {
904// case SIGCHLD:
905// G.count_SIGCHLD++;
906// break;
893 case SIGINT: 907 case SIGINT:
908 bb_putchar('\n');
894 G.flag_SIGINT = 1; 909 G.flag_SIGINT = 1;
895 break; 910 break;
896//TODO 911//TODO
@@ -900,6 +915,7 @@ static void check_and_run_traps(void)
900 break; 915 break;
901 } 916 }
902 } 917 }
918 return last_sig;
903} 919}
904 920
905#if ENABLE_HUSH_JOB 921#if ENABLE_HUSH_JOB
@@ -1209,7 +1225,7 @@ static void get_user_input(struct in_str *i)
1209 * only after <Enter>. (^C will work) */ 1225 * only after <Enter>. (^C will work) */
1210 r = read_line_input(prompt_str, G.user_input_buf, BUFSIZ-1, G.line_input_state); 1226 r = read_line_input(prompt_str, G.user_input_buf, BUFSIZ-1, G.line_input_state);
1211 /* catch *SIGINT* etc (^C is handled by read_line_input) */ 1227 /* catch *SIGINT* etc (^C is handled by read_line_input) */
1212 check_and_run_traps(); 1228 check_and_run_traps(0);
1213 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */ 1229 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */
1214 i->eof_flag = (r < 0); 1230 i->eof_flag = (r < 0);
1215 if (i->eof_flag) { /* EOF/error detected */ 1231 if (i->eof_flag) { /* EOF/error detected */
@@ -1223,7 +1239,7 @@ static void get_user_input(struct in_str *i)
1223 fflush(stdout); 1239 fflush(stdout);
1224 G.user_input_buf[0] = r = fgetc(i->file); 1240 G.user_input_buf[0] = r = fgetc(i->file);
1225 /*G.user_input_buf[1] = '\0'; - already is and never changed */ 1241 /*G.user_input_buf[1] = '\0'; - already is and never changed */
1226//do we need check_and_run_traps()? (maybe only if stdin) 1242//do we need check_and_run_traps(0)? (maybe only if stdin)
1227 } while (G.flag_SIGINT); 1243 } while (G.flag_SIGINT);
1228 i->eof_flag = (r == EOF); 1244 i->eof_flag = (r == EOF);
1229#endif 1245#endif
@@ -2329,6 +2345,11 @@ static int checkjobs(struct pipe* fg_pipe)
2329 2345
2330 debug_printf_jobs("checkjobs %p\n", fg_pipe); 2346 debug_printf_jobs("checkjobs %p\n", fg_pipe);
2331 2347
2348 errno = 0;
2349// if (G.handled_SIGCHLD == G.count_SIGCHLD)
2350// /* avoid doing syscall, nothing there anyway */
2351// return rcode;
2352
2332 attributes = WUNTRACED; 2353 attributes = WUNTRACED;
2333 if (fg_pipe == NULL) 2354 if (fg_pipe == NULL)
2334 attributes |= WNOHANG; 2355 attributes |= WNOHANG;
@@ -2346,10 +2367,21 @@ static int checkjobs(struct pipe* fg_pipe)
2346// + killall -STOP cat 2367// + killall -STOP cat
2347 2368
2348 wait_more: 2369 wait_more:
2349// TODO: safe_waitpid? 2370 while (1) {
2350 while ((childpid = waitpid(-1, &status, attributes)) > 0) {
2351 int i; 2371 int i;
2352 const int dead = WIFEXITED(status) || WIFSIGNALED(status); 2372 int dead;
2373
2374// i = G.count_SIGCHLD;
2375 childpid = waitpid(-1, &status, attributes);
2376 if (childpid <= 0) {
2377 if (childpid && errno != ECHILD)
2378 bb_perror_msg("waitpid");
2379// else /* Until next SIGCHLD, waitpid's are useless */
2380// G.handled_SIGCHLD = i;
2381 break;
2382 }
2383 dead = WIFEXITED(status) || WIFSIGNALED(status);
2384
2353#if DEBUG_JOBS 2385#if DEBUG_JOBS
2354 if (WIFSTOPPED(status)) 2386 if (WIFSTOPPED(status))
2355 debug_printf_jobs("pid %d stopped by sig %d (exitcode %d)\n", 2387 debug_printf_jobs("pid %d stopped by sig %d (exitcode %d)\n",
@@ -2428,10 +2460,6 @@ static int checkjobs(struct pipe* fg_pipe)
2428#endif 2460#endif
2429 } /* while (waitpid succeeds)... */ 2461 } /* while (waitpid succeeds)... */
2430 2462
2431 /* wait found no children or failed */
2432
2433 if (childpid && errno != ECHILD)
2434 bb_perror_msg("waitpid");
2435 return rcode; 2463 return rcode;
2436} 2464}
2437 2465
@@ -3004,7 +3032,7 @@ static int run_list(struct pipe *pi)
3004 if (r != -1) { 3032 if (r != -1) {
3005 /* we only ran a builtin: rcode is already known 3033 /* we only ran a builtin: rcode is already known
3006 * and we don't need to wait for anything. */ 3034 * and we don't need to wait for anything. */
3007 check_and_run_traps(); 3035 check_and_run_traps(0);
3008#if ENABLE_HUSH_LOOPS 3036#if ENABLE_HUSH_LOOPS
3009 /* was it "break" or "continue"? */ 3037 /* was it "break" or "continue"? */
3010 if (G.flag_break_continue) { 3038 if (G.flag_break_continue) {
@@ -3029,7 +3057,7 @@ static int run_list(struct pipe *pi)
3029 /* even bash 3.2 doesn't do that well with nested bg: 3057 /* even bash 3.2 doesn't do that well with nested bg:
3030 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &". 3058 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &".
3031 * I'm NOT treating inner &'s as jobs */ 3059 * I'm NOT treating inner &'s as jobs */
3032 check_and_run_traps(); 3060 check_and_run_traps(0);
3033#if ENABLE_HUSH_JOB 3061#if ENABLE_HUSH_JOB
3034 if (G.run_list_level == 1) 3062 if (G.run_list_level == 1)
3035 insert_bg_job(pi); 3063 insert_bg_job(pi);
@@ -3040,13 +3068,13 @@ static int run_list(struct pipe *pi)
3040 if (G.run_list_level == 1 && G.interactive_fd) { 3068 if (G.run_list_level == 1 && G.interactive_fd) {
3041 /* waits for completion, then fg's main shell */ 3069 /* waits for completion, then fg's main shell */
3042 rcode = checkjobs_and_fg_shell(pi); 3070 rcode = checkjobs_and_fg_shell(pi);
3043 check_and_run_traps(); 3071 check_and_run_traps(0);
3044 debug_printf_exec(": checkjobs_and_fg_shell returned %d\n", rcode); 3072 debug_printf_exec(": checkjobs_and_fg_shell returned %d\n", rcode);
3045 } else 3073 } else
3046#endif 3074#endif
3047 { /* this one just waits for completion */ 3075 { /* this one just waits for completion */
3048 rcode = checkjobs(pi); 3076 rcode = checkjobs(pi);
3049 check_and_run_traps(); 3077 check_and_run_traps(0);
3050 debug_printf_exec(": checkjobs returned %d\n", rcode); 3078 debug_printf_exec(": checkjobs returned %d\n", rcode);
3051 } 3079 }
3052 } 3080 }
@@ -3668,9 +3696,9 @@ static int process_command_subs(o_string *dest,
3668 } 3696 }
3669 3697
3670 debug_printf("done reading from pipe, pclose()ing\n"); 3698 debug_printf("done reading from pipe, pclose()ing\n");
3671 /* This is the step that wait()s for the child. Should be pretty 3699 /* This is the step that waits for the child. Should be pretty
3672 * safe, since we just read an EOF from its stdout. We could try 3700 * safe, since we just read an EOF from its stdout. We could try
3673 * to do better, by using wait(), and keeping track of background jobs 3701 * to do better, by using waitpid, and keeping track of background jobs
3674 * at the same time. That would be a lot of work, and contrary 3702 * at the same time. That would be a lot of work, and contrary
3675 * to the KISS philosophy of this program. */ 3703 * to the KISS philosophy of this program. */
3676 retcode = fclose(p); 3704 retcode = fclose(p);
@@ -4586,7 +4614,7 @@ int hush_main(int argc, char **argv)
4586 // to (inadvertently) close/redirect it 4614 // to (inadvertently) close/redirect it
4587 } 4615 }
4588 } 4616 }
4589 init_signal_mask(); 4617 init_signal_mask(); /* note: ensures SIGCHLD is not masked */
4590 debug_printf("G.interactive_fd=%d\n", G.interactive_fd); 4618 debug_printf("G.interactive_fd=%d\n", G.interactive_fd);
4591 if (G.interactive_fd) { 4619 if (G.interactive_fd) {
4592 fcntl(G.interactive_fd, F_SETFD, FD_CLOEXEC); 4620 fcntl(G.interactive_fd, F_SETFD, FD_CLOEXEC);
@@ -4617,8 +4645,12 @@ int hush_main(int argc, char **argv)
4617 fcntl(G.interactive_fd, F_SETFD, FD_CLOEXEC); 4645 fcntl(G.interactive_fd, F_SETFD, FD_CLOEXEC);
4618 } 4646 }
4619 } 4647 }
4620 init_signal_mask(); 4648 init_signal_mask(); /* note: ensures SIGCHLD is not masked */
4621#endif 4649#endif
4650 /* POSIX allows shell to re-enable SIGCHLD
4651 * even if it was SIG_IGN on entry */
4652// G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
4653 signal(SIGCHLD, SIG_DFL); // SIGCHLD_handler);
4622 4654
4623#if ENABLE_HUSH_INTERACTIVE && !ENABLE_FEATURE_SH_EXTRA_QUIET 4655#if ENABLE_HUSH_INTERACTIVE && !ENABLE_FEATURE_SH_EXTRA_QUIET
4624 if (G.interactive_fd) { 4656 if (G.interactive_fd) {
@@ -5164,12 +5196,48 @@ static int builtin_unset(char **argv)
5164static int builtin_wait(char **argv) 5196static int builtin_wait(char **argv)
5165{ 5197{
5166 int ret = EXIT_SUCCESS; 5198 int ret = EXIT_SUCCESS;
5167 int status; 5199 int status, sig;
5168 5200
5169 if (*++argv == NULL) 5201 if (*++argv == NULL) {
5170 /* don't care about exit status */ 5202 /* Don't care about wait results */
5171 wait(NULL); 5203 /* Note 1: must wait until there are no more children */
5204 /* Note 2: must be interruptible */
5205 /* Examples:
5206 * $ sleep 3 & sleep 6 & wait
5207 * [1] 30934 sleep 3
5208 * [2] 30935 sleep 6
5209 * [1] Done sleep 3
5210 * [2] Done sleep 6
5211 * $ sleep 3 & sleep 6 & wait
5212 * [1] 30936 sleep 3
5213 * [2] 30937 sleep 6
5214 * [1] Done sleep 3
5215 * ^C <-- after ~4 sec from keyboard
5216 * $
5217 */
5218 sigaddset(&G.blocked_set, SIGCHLD);
5219 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
5220 while (1) {
5221 checkjobs(NULL);
5222 if (errno == ECHILD)
5223 break;
5224 /* Wait for SIGCHLD or any other signal of interest */
5225 /* sigtimedwait with infinite timeout: */
5226 sig = sigwaitinfo(&G.blocked_set, NULL);
5227 if (sig > 0) {
5228 sig = check_and_run_traps(sig);
5229 if (sig && sig != SIGCHLD) { /* see note 2 */
5230 ret = 128 + sig;
5231 break;
5232 }
5233 }
5234 }
5235 sigdelset(&G.blocked_set, SIGCHLD);
5236 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
5237 return ret;
5238 }
5172 5239
5240 /* This is probably buggy wrt interruptible-ness */
5173 while (*argv) { 5241 while (*argv) {
5174 pid_t pid = bb_strtou(*argv, NULL, 10); 5242 pid_t pid = bb_strtou(*argv, NULL, 10);
5175 if (errno) { 5243 if (errno) {