aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-07-14 19:58:46 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-07-14 19:58:46 +0200
commit2ed74e25d354e6958dc86a21aa32c2dacb809bf0 (patch)
tree4fd9ec08db321fa8c771dc2b0c7de4efb1324d83
parent0c5657e9119eb52263e83e9b55394a8f43f4e928 (diff)
downloadbusybox-w32-2ed74e25d354e6958dc86a21aa32c2dacb809bf0.tar.gz
busybox-w32-2ed74e25d354e6958dc86a21aa32c2dacb809bf0.tar.bz2
busybox-w32-2ed74e25d354e6958dc86a21aa32c2dacb809bf0.zip
hush: make "wait %1" work even if the job is dead
Example script: sleep 1 | (sleep 1;exit 3) & sleep 2 echo Zero:$? wait %1 echo Three:$? function old new delta clean_up_last_dead_job - 24 +24 process_wait_result 426 447 +21 builtin_wait 285 293 +8 insert_job_into_table 264 269 +5 builtin_jobs 68 73 +5 remove_job_from_table 59 57 -2 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 4/1 up/down: 63/-2) Total: 61 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/hush.c91
1 files changed, 52 insertions, 39 deletions
diff --git a/shell/hush.c b/shell/hush.c
index af5c26090..b76351fde 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -7237,11 +7237,42 @@ static const char *get_cmdtext(struct pipe *pi)
7237 return pi->cmdtext; 7237 return pi->cmdtext;
7238} 7238}
7239 7239
7240static void remove_job_from_table(struct pipe *pi)
7241{
7242 struct pipe *prev_pipe;
7243
7244 if (pi == G.job_list) {
7245 G.job_list = pi->next;
7246 } else {
7247 prev_pipe = G.job_list;
7248 while (prev_pipe->next != pi)
7249 prev_pipe = prev_pipe->next;
7250 prev_pipe->next = pi->next;
7251 }
7252 G.last_jobid = 0;
7253 if (G.job_list)
7254 G.last_jobid = G.job_list->jobid;
7255}
7256
7257static void delete_finished_job(struct pipe *pi)
7258{
7259 remove_job_from_table(pi);
7260 free_pipe(pi);
7261}
7262
7263static void clean_up_last_dead_job(void)
7264{
7265 if (G.job_list && !G.job_list->alive_cmds)
7266 delete_finished_job(G.job_list);
7267}
7268
7240static void insert_job_into_table(struct pipe *pi) 7269static void insert_job_into_table(struct pipe *pi)
7241{ 7270{
7242 struct pipe *job, **jobp; 7271 struct pipe *job, **jobp;
7243 int i; 7272 int i;
7244 7273
7274 clean_up_last_dead_job();
7275
7245 /* Find the end of the list, and find next job ID to use */ 7276 /* Find the end of the list, and find next job ID to use */
7246 i = 0; 7277 i = 0;
7247 jobp = &G.job_list; 7278 jobp = &G.job_list;
@@ -7267,30 +7298,6 @@ static void insert_job_into_table(struct pipe *pi)
7267 printf("[%u] %u %s\n", job->jobid, (unsigned)job->cmds[0].pid, job->cmdtext); 7298 printf("[%u] %u %s\n", job->jobid, (unsigned)job->cmds[0].pid, job->cmdtext);
7268 G.last_jobid = job->jobid; 7299 G.last_jobid = job->jobid;
7269} 7300}
7270
7271static void remove_job_from_table(struct pipe *pi)
7272{
7273 struct pipe *prev_pipe;
7274
7275 if (pi == G.job_list) {
7276 G.job_list = pi->next;
7277 } else {
7278 prev_pipe = G.job_list;
7279 while (prev_pipe->next != pi)
7280 prev_pipe = prev_pipe->next;
7281 prev_pipe->next = pi->next;
7282 }
7283 if (G.job_list)
7284 G.last_jobid = G.job_list->jobid;
7285 else
7286 G.last_jobid = 0;
7287}
7288
7289static void delete_finished_job(struct pipe *pi)
7290{
7291 remove_job_from_table(pi);
7292 free_pipe(pi);
7293}
7294#endif /* JOB */ 7301#endif /* JOB */
7295 7302
7296static int job_exited_or_stopped(struct pipe *pi) 7303static int job_exited_or_stopped(struct pipe *pi)
@@ -7415,14 +7422,22 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status)
7415 pi->cmds[i].pid = 0; 7422 pi->cmds[i].pid = 0;
7416 pi->alive_cmds--; 7423 pi->alive_cmds--;
7417 if (!pi->alive_cmds) { 7424 if (!pi->alive_cmds) {
7418 if (G_interactive_fd) 7425 if (G_interactive_fd) {
7419 printf(JOB_STATUS_FORMAT, pi->jobid, 7426 printf(JOB_STATUS_FORMAT, pi->jobid,
7420 "Done", pi->cmdtext); 7427 "Done", pi->cmdtext);
7421 delete_finished_job(pi); 7428 delete_finished_job(pi);
7422//bash deletes finished jobs from job table only in interactive mode, after "jobs" cmd, 7429 } else {
7423//or if pid of a new process matches one of the old ones 7430/*
7424//(see cleanup_dead_jobs(), delete_old_job(), J_NOTIFIED in bash source). 7431 * bash deletes finished jobs from job table only in interactive mode,
7425//Testcase script: "(exit 3) & sleep 1; wait %1; echo $?" prints 3 in bash. 7432 * after "jobs" cmd, or if pid of a new process matches one of the old ones
7433 * (see cleanup_dead_jobs(), delete_old_job(), J_NOTIFIED in bash source).
7434 * Testcase script: "(exit 3) & sleep 1; wait %1; echo $?" prints 3 in bash.
7435 * We only retain one "dead" job, if it's the single job on the list.
7436 * This covers most of real-world scenarios where this is useful.
7437 */
7438 if (pi != G.job_list)
7439 delete_finished_job(pi);
7440 }
7426 } 7441 }
7427 } else { 7442 } else {
7428 /* child stopped */ 7443 /* child stopped */
@@ -9696,6 +9711,9 @@ static int FAST_FUNC builtin_jobs(char **argv UNUSED_PARAM)
9696 9711
9697 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext); 9712 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->cmdtext);
9698 } 9713 }
9714
9715 clean_up_last_dead_job();
9716
9699 return EXIT_SUCCESS; 9717 return EXIT_SUCCESS;
9700} 9718}
9701 9719
@@ -9939,17 +9957,12 @@ static int FAST_FUNC builtin_wait(char **argv)
9939 wait_pipe = parse_jobspec(*argv); 9957 wait_pipe = parse_jobspec(*argv);
9940 if (wait_pipe) { 9958 if (wait_pipe) {
9941 ret = job_exited_or_stopped(wait_pipe); 9959 ret = job_exited_or_stopped(wait_pipe);
9942 if (ret < 0) 9960 if (ret < 0) {
9943 ret = wait_for_child_or_signal(wait_pipe, 0); 9961 ret = wait_for_child_or_signal(wait_pipe, 0);
9944//bash immediately deletes finished jobs from job table only in interactive mode, 9962 } else {
9945//we _always_ delete them at once. If we'd start keeping some dead jobs, this 9963 /* waiting on "last dead job" removes it */
9946//(and more) would be necessary to avoid accumulating dead jobs: 9964 clean_up_last_dead_job();
9947# if 0
9948 else {
9949 if (!wait_pipe->alive_cmds)
9950 delete_finished_job(wait_pipe);
9951 } 9965 }
9952# endif
9953 } 9966 }
9954 /* else: parse_jobspec() already emitted error msg */ 9967 /* else: parse_jobspec() already emitted error msg */
9955 continue; 9968 continue;