diff --git a/usr.bin/xargs/xargs.1 b/usr.bin/xargs/xargs.1 index 045e235..4d76b98 100644 --- a/usr.bin/xargs/xargs.1 +++ b/usr.bin/xargs/xargs.1 @@ -58,6 +58,7 @@ .Fl n Ar number .Op Fl x .Oc +.Op Fl P Ar maxjobs .Op Fl s Ar size .Op Ar utility Op Ar argument ... .Sh DESCRIPTION @@ -192,6 +193,12 @@ arguments remaining for the last invocation of The current default value for .Ar number is 5000. +.It Fl P Ar maxprocs +Parallel mode: run at most +.Ar maxprocs +invocations of +.Ar utility +at once. .It Fl o Reopen stdin as .Pa /dev/tty @@ -285,7 +292,7 @@ utility is expected to be .St -p1003.2 compliant. The -.Fl J , o +.Fl J , o , P and .Fl R options are non-standard diff --git a/usr.bin/xargs/xargs.c b/usr.bin/xargs/xargs.c index f48b975..cc0a59c 100644 --- a/usr.bin/xargs/xargs.c +++ b/usr.bin/xargs/xargs.c @@ -66,6 +66,7 @@ static int prompt(void); static void run(char **); static void usage(void); void strnsubst(char **, const char *, const char *, size_t); +static void waitchildren(const char *, int); static char echo[] = _PATH_ECHO; static char **av, **bxp, **ep, **expx, **xp; @@ -73,6 +74,8 @@ static char *argp, *bbp, *ebp, *inpline, *p, *replstr; static const char *eofstr; static int count, insingle, indouble, oflag, pflag, tflag, Rflag, rval, zflag; static int cnt, Iflag, jfound, Lflag, wasquoted, xflag; +static int curprocs, maxprocs; +static volatile int childerr; extern char **environ; @@ -112,7 +115,9 @@ main(int argc, char *argv[]) /* 1 byte for each '\0' */ nline -= strlen(*ep++) + 1 + sizeof(*ep); } - while ((ch = getopt(argc, argv, "0E:I:J:L:n:opR:s:tx")) != -1) + + maxprocs = 1; + while ((ch = getopt(argc, argv, "0E:I:J:L:n:P:opR:s:tx")) != -1) switch(ch) { case 'E': eofstr = optarg; @@ -144,6 +149,10 @@ main(int argc, char *argv[]) case 'p': pflag = 1; break; + case 'P': + if ((maxprocs = atoi(optarg)) <= 0) + errx(1, "max.processes must be >0"); + break; case 'R': if ((Rflag = atoi(optarg)) <= 0) errx(1, "illegal number of replacements"); @@ -245,8 +254,10 @@ parse_input(int argc, char *argv[]) switch(ch = getchar()) { case EOF: /* No arguments since last exec. */ - if (p == bbp) + if (p == bbp) { + waitchildren(*argv, 1); exit(rval); + } goto arg1; case ' ': case '\t': @@ -323,8 +334,10 @@ arg2: *xp++ = *avj; } prerun(argc, av); - if (ch == EOF || foundeof) + if (ch == EOF || foundeof) { + waitchildren(*argv, 1); exit(rval); + } p = bbp; xp = bxp; count = 0; @@ -463,10 +476,8 @@ prerun(int argc, char *argv[]) static void run(char **argv) { - volatile int childerr; char **avec; pid_t pid; - int status; /* * If the user wants to be notified of each command before it is @@ -516,17 +527,40 @@ exec: childerr = errno; _exit(1); } - pid = waitpid(pid, &status, 0); - if (pid == -1) - err(1, "waitpid"); - /* If we couldn't invoke the utility, exit. */ - if (childerr != 0) - err(childerr == ENOENT ? 127 : 126, "%s", *argv); - /* If utility signaled or exited with a value of 255, exit 1-125. */ - if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255) - exit(1); - if (WEXITSTATUS(status)) - rval = 1; + curprocs++; + waitchildren(*argv, 0); +} + +/* + * Handle child processes. + */ +static void +waitchildren(const char *name, int waitall) +{ + pid_t pid; + int status; + + while ((pid = wait3(&status, !waitall && curprocs < maxprocs ? + WNOHANG : 0, NULL)) > 0) { + curprocs--; + + /* If we couldn't invoke the utility, exit. */ + if (childerr != 0) { + errno = childerr; + err(errno == ENOENT ? 127 : 126, "%s", name); + } + + /* + * If utility signaled or exited with a value of 255, + * exit 1-125. + */ + if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255) + exit(1); + if (WEXITSTATUS(status)) + rval = 1; + } + if (pid == -1 && errno != ECHILD) + err(1, "wait3"); } /* @@ -567,6 +601,7 @@ usage(void) { fprintf(stderr, "usage: xargs [-0opt] [-E eofstr] [-I replstr [-R replacements]] [-J replstr]\n" -" [-L number] [-n number [-x] [-s size] [utility [argument ...]]\n"); +" [-L number] [-n number [-x] [-P maxprocs] [-s size]\n" +" [utility [argument ...]]\n"); exit(1); }