Date:        Thu, 27 Apr 2017 01:57:48 +0200
    From:        Vincent Lefevre <vincent-o...@vinc17.net>
    Message-ID:  <20170426235748.ga11...@zira.vinc17.org>

  | In such a case, how can you know the number of remaining processes?

Background processes, I assume you mean - you cannot, really,
the closest things come would be by using the jobs command,
or if you happen to know the order they should finish, you can wait
on each in turn, something like
        for pid in M N O P ...
        do
                wait $pid
                # whatever else needs doing
        done
and then you'll know how many have finished.

The shell's wait command doesn't allow for other find grained
control (as much as it might be nice if it did.)

Don't fool yourself into believing that SIGCHLD handling with traps
is useful for doing anything much in the shell - it is there because
there is a SIHCHLD signal, and processes can catch it, and the trap
command allows handling all signals that can be caught.  You can trap
on SEGV as well, but unless something is sending SEGV signals at the
shell (using kill or something) that won't be useful either.

But for SIGCHLD, at C level, the general idea is that the handler waits
with WNOHANG for as many processes as have exited (and retrieves status
of each of them).   But the shell wait command has no equiv of WNOHANG,
you either wait for a specific process (or job) or for all of them.
That means you cannot really implement a SIGCHLD trap handler in
(portable) sh that does anything particularly useful.

kre

ps: the seq command in your example cannot (properly) have caused the
SIGCHLD that you (think you) counted, as it is running in a sub-shell,
and traps get reset there (and even if they didn't, that would update
a different copy of the counter 'c')

What you're seeing is the effect of that wait for the subshell to exit,
combined with the way that traps are implemented, and processed - the
SIGCHLD that is caught that you thought was from seq is not, it is from
one or more of the background processes, or the subshell itself (or both
of those.)   When you enumerate the seq output instead of invoking it in ``
(or $()) you are just removing one of the instances where the the trap
could get executed.

You can see that background processes do generate SIGCHLD with a script like...

c=0
trap 'c=$((c + 1))' CHLD

while [ $c -lt 3 ]; do
        echo $c
        read junk
        sleep 0.5 &
done

which has no non-builtin foreground commands (in most shells anyway.)
If you start more background sleeps in the loop, you'll see that you
still advance by at most 1 (in ash derived shells) per iteration of
the loop, though unless you are very fast supplying the input for the
"read" you can expect all of the sleeps to finish (which is why you
want a sub-second delay ideally).


Reply via email to