From c7d66f8340aeb03c9915de48190bbb9ac6e6d1e8 Mon Sep 17 00:00:00 2001 From: James Youngman Date: Sat, 23 Aug 2014 12:45:28 +0100 Subject: [PATCH] Don't overflow sig_atomic_t for --max-procs. * xargs/xargs.c (__STDC_LIMIT_MACROS): Define __STDC_LIMIT_MACROS in order to ensure that defines the SIG_ATOMIC_MAX macro, which we need. (MAX_PROC_MAX): Define this as the maximum allowed value of proc_max. (main): Show the value of MAX_PROC_MAX for --show-limits. (increment_proc_max): Don't increment proc_max beyond MAX_PROC_MAX. (parse_num): Fix small error in the error message; if the limit on the value of a command-line argument is N, explain that the user should specify a value <= N, not < N. * xargs/xargs.1: Document the upper limit on --max-procs. * doc/find.texi (Controlling Parallelism): Document the upper limit on the amount of parallelism. (xargs options): Document the limit on the value you can specify for --max-procs. --- ChangeLog | 18 ++++++++++++++++++ doc/find.texi | 13 +++++++++++-- xargs/xargs.1 | 9 +++++---- xargs/xargs.c | 21 +++++++++++++++++---- 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index cfcd1bc8..19178d90 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,23 @@ 2014-08-23 James Youngman + Don't overflow sig_atomic_t for --max-procs. + * xargs/xargs.c (__STDC_LIMIT_MACROS): Define __STDC_LIMIT_MACROS + in order to ensure that defines the SIG_ATOMIC_MAX + macro, which we need. + (MAX_PROC_MAX): Define this as the maximum allowed value of + proc_max. + (main): Show the value of MAX_PROC_MAX for --show-limits. + (increment_proc_max): Don't increment proc_max beyond + MAX_PROC_MAX. + (parse_num): Fix small error in the error message; if the limit on + the value of a command-line argument is N, explain that the user + should specify a value <= N, not < N. + * xargs/xargs.1: Document the upper limit on --max-procs. + * doc/find.texi (Controlling Parallelism): Document the upper + limit on the amount of parallelism. + (xargs options): Document the limit on the value you can specify + for --max-procs. + Prepare for later generating the ChangeLog file from the git log. * ChangeLog-2008: Split this file out from the main ChangeLog file. * Makefile.am (EXTRA_DIST): Distribute ChangeLog-2008. diff --git a/doc/find.texi b/doc/find.texi index 61ffee8c..7aa20e50 100644 --- a/doc/find.texi +++ b/doc/find.texi @@ -2617,7 +2617,15 @@ it a @code{SIGUSR1}. @code{xargs} will never terminate any existing commands when you ask it to run fewer processes. It merely waits for the excess commands to finish. If you ask it to run more commands, it will start the next -one immediately (if it has more work to do). +one immediately (if it has more work to do). If the degree of +parallelism is already 1, sending @code{SIGUSR2} will have no futher +effect (since @code{--max-procs=0} means that there should be no limit +on the number of processes to run). + +There is an implementation-defined limit on the number of processes. +This limit is shown with @code{xargs --show-limits}. The limit is at +least 127 on all systems (and on the author's system it is +2147483647). If you send several identical signals quickly, the operating system does not guarantee that each of them will be delivered to @code{xargs}. @@ -3794,7 +3802,8 @@ Exit if the size (see the @samp{-s} option) is exceeded. @itemx -P @var{max-procs} Run simultaneously up to @var{max-procs} processes at once; the default is 1. If @var{max-procs} is 0, @code{xargs} will run as many processes as -possible simultaneously. +possible simultaneously. @xref{Controlling Parallelism} for +information on dynamically controlling parallelism. @item --process-slot-var=@var{environment-variable-name} Set the environment variable @var{environment-variable-name} to a diff --git a/xargs/xargs.1 b/xargs/xargs.1 index be8a319c..b0555296 100644 --- a/xargs/xargs.1 +++ b/xargs/xargs.1 @@ -229,10 +229,11 @@ option with otherwise chances are that only one exec will be done. While .B xargs -is running, you can -send its process -a SIGUSR1 signal to increase the number of commands to run simultaneously, -or a SIGUSR2 to decrease the number. You cannot decrease it below 1. +is running, you can send its process a SIGUSR1 signal to increase the +number of commands to run simultaneously, or a SIGUSR2 to decrease the +number. You cannot increase it above an implementation-defined limit +(which is shown with \-\-show-limits). You cannot decrease it below +1. .B xargs never terminates its commands; when asked to decrease, it merely waits for more than one existing command to terminate before starting diff --git a/xargs/xargs.c b/xargs/xargs.c index 89e78a3a..2b0f8f28 100644 --- a/xargs/xargs.c +++ b/xargs/xargs.c @@ -23,10 +23,18 @@ Dmitry V. Levin */ +/* We want SIG_ATOMIC_MAX to be defined. The implementation only does + this if __STDC_LIMIT_MACROS is #defined before is + included (see the footnote to section 7.18.3 of ISO C99). Because + some other header may #include , we define the macro + here, first. */ +#define __STDC_LIMIT_MACROS + /* config.h must be included first. */ #include /* system headers. */ + #include #include #include @@ -120,6 +128,7 @@ static bool initial_args = true; /* If nonzero, the maximum number of child processes that can be running at once. */ /* TODO: check conversion safety (i.e. range) for -P option. */ +#define MAX_PROC_MAX SIG_ATOMIC_MAX static volatile sig_atomic_t proc_max = 1; /* Did we fork a child yet? */ @@ -587,8 +596,8 @@ main (int argc, char **argv) break; case 'P': - /* Allow only up to LONG_MAX child processes. */ - proc_max = parse_num (optarg, 'P', 0L, LONG_MAX, 1); + /* Allow only up to MAX_PROC_MAX child processes. */ + proc_max = parse_num (optarg, 'P', 0L, MAX_PROC_MAX, 1); break; case 'a': @@ -706,6 +715,9 @@ main (int argc, char **argv) fprintf (stderr, _("Size of command buffer we are actually using: %" PRIuMAX "\n"), (uintmax_t)bc_ctl.arg_max); + fprintf (stderr, + _("Maximum parallelism (--max-procs must be no greater): %" PRIuMAX "\n"), + (uintmax_t)MAX_PROC_MAX); if (isatty (STDIN_FILENO)) { @@ -1544,7 +1556,8 @@ increment_proc_max (int ignore) { (void) ignore; /* If user increments from 0 to 1, we'll take it and serialize. */ - proc_max++; + if (proc_max < MAX_PROC_MAX) + proc_max++; /* If we're waiting for a process to die before doing something, no need to wait any more. */ stop_waiting = 1; @@ -1595,7 +1608,7 @@ parse_num (char *str, int option, long int min, long int max, int fatal) } else if (max >= 0 && val > max) { - fprintf (stderr, _("%s: value for -%c option should be < %ld\n"), + fprintf (stderr, _("%s: value for -%c option should be <= %ld\n"), program_name, option, max); if (fatal) {