commit:     55e0227999a66dc13291f709f9a66d6ff1a31883
Author:     Kerin Millar <kfm <AT> plushkava <DOT> net>
AuthorDate: Sat Jun 28 05:27:30 2025 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Sat Jun 28 23:50:57 2025 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=55e02279

isolated-functions.sh: avoid issuing wait -n in parallel() where no jobs are 
left

Presently, the parallel() function executes a read loop, consuming
null-terminated records from STDIN that are used to compose simple
commands that are executed asychronously. One this loop has concluded, a
second loop begins in which any outstanding subprocesses are waited for.
The latter loop is implemented as an infinite one that breaks upon the
wait -n command producing an exit status of 127, for that is the number
indicating that there are no more subprocesses left to be reaped.

Sam reported that this technique raises an annoying internal debug
message for the bash 5.3 release candidates. As the following examples
show, it can be reproduced by issuing wait -n from the subshell of a
non-interactive shell that has no remaining jobs in flight.

$ bash -c '( : & wait -n; wait -n )'
bash: line 1: DEBUG warning: notify_of_job_status: catch-all setting
J_NOTIFIED on job 0 (32), startup state = 2

$ bash -c '{ : & wait -n; wait -n; } | :'
bash: line 1: DEBUG warning: notify_of_job_status: catch-all setting
J_NOTIFIED on job 0 (32), startup state = 2

It should be noted that such messages only appear in DEBUG builds.
Therefore, there is no chance of them appearing in the upcoming 5.3.0
release. Nevertheless, address this issue by tasking the 'i' variable
with keeping track of how many jobs are in flight, and by having the
second loop iterate exactly as many times as 'i' can be decremented
until it reaches 0.

Reported-by: Sam James <sam <AT> gentoo.org>
Signed-off-by: Kerin Millar <kfm <AT> plushkava.net>
Signed-off-by: Sam James <sam <AT> gentoo.org>

 bin/isolated-functions.sh | 29 ++++++++++-------------------
 1 file changed, 10 insertions(+), 19 deletions(-)

diff --git a/bin/isolated-functions.sh b/bin/isolated-functions.sh
index acf945eb99..9b4090862b 100644
--- a/bin/isolated-functions.sh
+++ b/bin/isolated-functions.sh
@@ -513,40 +513,31 @@ ___makeopts_jobs() {
 # xargs -0 -L1 -P"$(___makeopts_jobs)".
 #
 # If no records are read, or if all commands complete successfully, the return
-# value shall be 0. Otherwise, the return value shall be that of the failed
-# command that was last reaped by bash. Should any command fail, no further
-# records shall be consumed and the function shall attempt to return as soon as
-# possible. Hence, the caller should assume that not all records were processed
-# in the event of a non-zero return value. As a special case, the function 
shall
-# return 127 if the first parameter cannot be resolved as a valid command name.
+# value shall be 0. Otherwise, the return value shall be that of the last
+# reaped command that produced a non-zero exit status. As soon as any command
+# fails, no further records shall be read, nor any further commands executed.
 ___parallel() (
        local max_procs retval arg i
 
-       if ! hash "$1" 2>/dev/null; then
-               printf >&2 '%s: %q: command not found\n' "$0" "$1"
-               return 127
-       fi
-
        max_procs=$(___makeopts_jobs)
        retval=0
 
        while IFS= read -rd '' arg; do
-               if (( ++i > max_procs )); then
+               if (( i >= max_procs )); then
                        wait -n
                        case $? in
-                               0) ;;
-                               *) retval=$?; break
+                               0) (( i-- )) ;;
+                               *) retval=$?; (( i-- )); break
                        esac
                fi
-               "$@" "${arg}" &
+               "$@" "${arg}" & (( ++i ))
        done
 
-       while true; do
+       while (( i-- )); do
                wait -n
                case $? in
-                       127) break ;; # no more unwaited-for children left
-                       0)   ;;
-                       *)   retval=$?
+                       0) ;;
+                       *) retval=$?
                esac
        done
 

Reply via email to