xargs: Wait for all children even if one exited with 255.

* xargs/xargs.c: fix Savannah bug #64451 (xargs -P exits before all
children have exited if one exits with status 255).
* xargs/xargs.1 (BUGS): mention this bug and the corrected behaviour.
* doc/find.texi: Likewise.
* NEWS: mention this bugfix.
This commit is contained in:
James Youngman 2024-05-18 10:36:17 +01:00
parent 8368fd0b2a
commit ad636eae01
4 changed files with 51 additions and 8 deletions

3
NEWS
View File

@ -4,6 +4,9 @@ GNU findutils NEWS - User visible changes. -*- outline -*- (allout)
** Bug Fixes
xargs -P now waits for all its child processes to compete before
exiting, even if one of them exits with status 255. [#64451]
'find -name /' no longer outputs a warning, because that is a valid pattern
to match the root directory "/". Previously, a diagnostic falsely claimed
that this pattern would not match anything. [#62227]

View File

@ -2740,7 +2740,9 @@ Run up to @var{max-procs} processes at a time; the default is 1. If
@var{max-procs} is 0, @code{xargs} will run as many processes as
possible at a time. Use the @samp{-n}, @samp{-s}, or @samp{-L} option
with @samp{-P}; otherwise chances are that the command will be run
only once.
only once. If a child process exits with status 255, @code{xargs} will
still wait for all child processes to exit (before version 4.9.0 this
might not happen).
@end table
For example, suppose you have a directory tree of large image files

View File

@ -225,6 +225,9 @@ You cannot decrease it below 1.
never terminates its commands; when asked to decrease, it merely
waits for more than one existing command to terminate before starting
another.
.B xargs
always waits for all child processes to exit before exiting itself
(but see BUGS).
.B Please note
that it is up to the called processes to properly manage parallel
@ -532,6 +535,13 @@ which is why this discussion appears in the BUGS section.
The problem doesn't occur with the output of
.BR find (1)
because it emits just one filename per line.
.P
In versions of
.B xargs
up to and including version 4.9.0,
.B xargs -P
would exit while some of its children were still running, if one of
them exited with status 255.
.
.SH "REPORTING BUGS"
GNU findutils online help: <https://www.gnu.org/software/findutils/#get-help>

View File

@ -1494,6 +1494,7 @@ static void
wait_for_proc (bool all, unsigned int minreap)
{
unsigned int reaped = 0;
int deferred_exit_status = 0;
while (procs_executing)
{
@ -1576,17 +1577,44 @@ wait_for_proc (bool all, unsigned int minreap)
procs_executing--;
reaped++;
#define set_deferred_exit_status(n) \
do \
{ \
if (deferred_exit_status < n) \
{ \
deferred_exit_status = n; \
} \
} while (0)
if (WEXITSTATUS (status) == CHILD_EXIT_PLEASE_STOP_IMMEDIATELY)
error (XARGS_EXIT_CLIENT_EXIT_255, 0,
_("%s: exited with status 255; aborting"), bc_state.cmd_argv[0]);
{
error (0, 0, _("%s: exited with status 255; aborting"), bc_state.cmd_argv[0]);
set_deferred_exit_status(XARGS_EXIT_CLIENT_EXIT_255);
}
if (WIFSTOPPED (status))
error (XARGS_EXIT_CLIENT_FATAL_SIG, 0,
_("%s: stopped by signal %d"), bc_state.cmd_argv[0], WSTOPSIG (status));
{
error (0, 0, _("%s: stopped by signal %d"), bc_state.cmd_argv[0], WSTOPSIG (status));
set_deferred_exit_status(XARGS_EXIT_CLIENT_FATAL_SIG);
}
if (WIFSIGNALED (status))
error (XARGS_EXIT_CLIENT_FATAL_SIG, 0,
_("%s: terminated by signal %d"), bc_state.cmd_argv[0], WTERMSIG (status));
{
error (0, 0,
_("%s: terminated by signal %d"), bc_state.cmd_argv[0], WTERMSIG (status));
set_deferred_exit_status(XARGS_EXIT_CLIENT_FATAL_SIG);
}
if (WEXITSTATUS (status) != 0)
child_error = XARGS_EXIT_CLIENT_EXIT_NONZERO;
{
child_error = XARGS_EXIT_CLIENT_EXIT_NONZERO;
}
if (deferred_exit_status && !all)
{
break;
}
}
if (deferred_exit_status)
{
child_error = deferred_exit_status > child_error ? deferred_exit_status : child_error;
exit (child_error);
}
}