@@ -11,7 +11,7 @@ ci_go_lint() {
1111ci_waitjobs () {
1212 if [ -z " ${CI-} " ]; then
1313 waitjobs
14- return 0
14+ return " $? "
1515 fi
1616
1717 capcode waitjobs
@@ -24,7 +24,6 @@ ci_waitjobs() {
2424 notify
2525 return " $code "
2626 fi
27- capcode nofixups
2827 notify
2928 return " $code "
3029}
@@ -435,6 +434,8 @@ LIB_JOB=1
435434# and propogating of signals. Not sure how to debug even without something like gdb and
436435# going through the source code of the shell too.
437436runjob () {(
437+ # A child must never wait on its parent's other jobs.
438+ JOB_PIDS=
438439 jobname=$1
439440 export JOBNAME=${JOBNAME+$JOBNAME / } $jobname
440441 shift
@@ -462,16 +463,29 @@ runjob() {(
462463 # We add the prefix to all lines and remove any warning lines about recursive make.
463464 # We cannot silence these with -s which is unfortunate.
464465 (sed -e " s#^#$( echop " $jobname " ) : #" -e " /make\[.\]: warning: -j/d" " $stdout " || true) &
466+ RUNJOB_READERS=" $! "
465467 # This intentionally does not output to our stderr, it becomes our stdout.
466468 (sed -e " s#^#$( echop " $jobname " ) : #" -e " /make\[.\]: warning: -j/d" " $stderr " || true) &
469+ RUNJOB_READERS=" $RUNJOB_READERS $! "
467470
468471 start=" $( awk ' BEGIN{srand(); print srand()}' ) "
469472 trap runjob_exittrap EXIT
470473 # For some reason without wrapping this in a subshell, the waitjobs in subjob
471474 # case_notequal_sign of ./lib/flags_test.sh freezes.
472- ( eval " $* " > " $stdout " 2> " $stderr " )
475+ ( JOB_PIDS= ; eval " $* " > " $stdout " 2> " $stderr " )
473476)}
474477
478+ # Use this instead of `runjob ... &` so the shell retains the child's exit status.
479+ runjob_bg () {
480+ _job_bg runjob " $@ "
481+ }
482+
483+ # Register an unprefixed helper without adding a job-filter level.
484+ _job_bg () {
485+ JOB_PIDS= " $@ " &
486+ JOB_PIDS=" ${JOB_PIDS-} $! "
487+ }
488+
475489_runjob_filter () {
476490 if [ -z " ${JOBFILTER-} " ]; then
477491 return 0
@@ -511,42 +525,62 @@ runjob_filter() {
511525
512526runjob_exittrap () {
513527 code=" $? "
528+ trap - EXIT
514529 end=" $( awk ' BEGIN{srand(); print srand()}' ) "
515530 dur=" $(( end - start)) "
516531
517- waitjobs_sigtrap
532+ # Preserve the existing output-reader shutdown behavior. Their status must
533+ # never replace the command's exit status.
534+ for reader_pid in $RUNJOB_READERS ; do
535+ kill " $reader_pid " 2> /dev/null || true
536+ done
537+ for reader_pid in $RUNJOB_READERS ; do
538+ wait " $reader_pid " 2> /dev/null || true
539+ done
518540 if [ " $code " -eq 0 ]; then
519541 echop " $jobname \$ " " $( setaf 2 success) " " ($( echo_dur " $dur " ) )"
520542 else
521543 echop " $jobname \$ " " $( setaf 1 failure) " " ($( echo_dur " $dur " ) )"
522544 fi
545+ exit " $code "
523546}
524547
525548waitjobs () {
549+ waitjobs_status=0
550+ # Fail clearly for legacy callers rather than silently dropping their failures.
551+ # `jobs` must run in this shell: dash has an empty job table in substitutions.
526552 wait_tmpdir=" $( mktempd) "
527- jobs -l > " $wait_tmpdir /jobsl"
528- trap waitjobs_sigtrap INT TERM
529-
530- jobs -p > " $wait_tmpdir /jobsp"
553+ jobs -p > " $wait_tmpdir /jobsp"
531554 for pid in $( cat " $wait_tmpdir /jobsp" ) ; do
555+ case " ${JOB_PIDS-} " in
556+ * " $pid " * ) ;;
557+ * )
558+ echoerr " unregistered background job $pid : use runjob_bg instead of runjob ... &"
559+ JOB_PIDS=" ${JOB_PIDS-} $pid "
560+ waitjobs_status=1
561+ ;;
562+ esac
563+ done
564+ trap waitjobs_sigtrap INT TERM
565+ set -- ${JOB_PIDS-}
566+ for pid do
532567 if ! wait " $pid " ; then
533- caterr << EOF
534- failed to wait on $pid :
535- $( < " $wait_tmpdir /jobsl" grep " $pid " )
536- EOF
537- FAILURE=1
568+ echoerr " background job $pid failed"
569+ waitjobs_status=1
538570 fi
571+ shift
572+ JOB_PIDS=" $* "
539573 done
540- if [ -n " ${FAILURE-} " ] ; then
541- return 1
542- fi
574+ JOB_PIDS=
575+ trap - INT TERM
576+ return " $waitjobs_status "
543577}
544578
545579waitjobs_sigtrap () {
546- for pid in $( jobs -p) ; do
580+ waitjobs_status=1
581+ for pid in ${JOB_PIDS-} ; do
547582 kill " $pid " 2> /dev/null || true
548583 done
549- waitjobs
550584}
551585
552586job_parseflags () {
@@ -1060,9 +1094,6 @@ EOF
10601094 return 1
10611095 fi
10621096
1063- if [ " $code " -eq 0 ]; then
1064- capcode nofixups
1065- fi
10661097 if [ " $code " -eq 0 ]; then
10671098 status=success
10681099 emoji=🟢
0 commit comments