From owner-svn-src-all@FreeBSD.ORG Sun Feb 12 05:01:50 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2864A106564A; Sun, 12 Feb 2012 05:01:50 +0000 (UTC) (envelope-from mckay@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 0D6768FC0A; Sun, 12 Feb 2012 05:01:50 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q1C51nw8065895; Sun, 12 Feb 2012 05:01:49 GMT (envelope-from mckay@svn.freebsd.org) Received: (from mckay@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q1C51noc065893; Sun, 12 Feb 2012 05:01:49 GMT (envelope-from mckay@svn.freebsd.org) Message-Id: <201202120501.q1C51noc065893@svn.freebsd.org> From: Stephen McKay Date: Sun, 12 Feb 2012 05:01:49 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r231542 - stable/8/usr.bin/xargs X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 12 Feb 2012 05:01:50 -0000 Author: mckay Date: Sun Feb 12 05:01:49 2012 New Revision: 231542 URL: http://svn.freebsd.org/changeset/base/231542 Log: MFC r215615, r215642: Fix several misbehaviours by making xargs keep track of its child processes. Modified: stable/8/usr.bin/xargs/xargs.c Directory Properties: stable/8/usr.bin/xargs/ (props changed) Modified: stable/8/usr.bin/xargs/xargs.c ============================================================================== --- stable/8/usr.bin/xargs/xargs.c Sun Feb 12 01:07:15 2012 (r231541) +++ stable/8/usr.bin/xargs/xargs.c Sun Feb 12 05:01:49 2012 (r231542) @@ -73,7 +73,16 @@ static int prompt(void); static void run(char **); static void usage(void); void strnsubst(char **, const char *, const char *, size_t); +static pid_t xwait(int block, int *status); static void waitchildren(const char *, int); +static void pids_init(void); +static int pids_empty(void); +static int pids_full(void); +static void pids_add(pid_t pid); +static int pids_remove(pid_t pid); +static int findslot(pid_t pid); +static int findfreeslot(void); +static void clearslot(int slot); static char echo[] = _PATH_ECHO; static char **av, **bxp, **ep, **endxp, **xp; @@ -82,6 +91,7 @@ static const char *eofstr; static int count, insingle, indouble, oflag, pflag, tflag, Rflag, rval, zflag; static int cnt, Iflag, jfound, Lflag, Sflag, wasquoted, xflag; static int curprocs, maxprocs; +static pid_t *childpids; static volatile int childerr; @@ -205,6 +215,8 @@ main(int argc, char *argv[]) if (replstr != NULL && *replstr == '\0') errx(1, "replstr may not be empty"); + pids_init(); + /* * Allocate pointers for the utility name, the utility arguments, * the maximum arguments to be read from stdin and the trailing @@ -556,19 +568,41 @@ exec: childerr = errno; _exit(1); } - curprocs++; + pids_add(pid); waitchildren(*argv, 0); } +/* + * Wait for a tracked child to exit and return its pid and exit status. + * + * Ignores (discards) all untracked child processes. + * Returns -1 and sets errno to ECHILD if no tracked children exist. + * If block is set, waits indefinitely for a child process to exit. + * If block is not set and no children have exited, returns 0 immediately. + */ +static pid_t +xwait(int block, int *status) { + pid_t pid; + + if (pids_empty()) { + errno = ECHILD; + return (-1); + } + + while ((pid = waitpid(-1, status, block ? 0 : WNOHANG)) > 0) + if (pids_remove(pid)) + break; + + return (pid); +} + static void waitchildren(const char *name, int waitall) { pid_t pid; int status; - while ((pid = waitpid(-1, &status, !waitall && curprocs < maxprocs ? - WNOHANG : 0)) > 0) { - curprocs--; + while ((pid = xwait(waitall || pids_full(), &status)) > 0) { /* If we couldn't invoke the utility, exit. */ if (childerr != 0) { errno = childerr; @@ -583,8 +617,87 @@ waitchildren(const char *name, int waita if (WEXITSTATUS(status)) rval = 1; } + if (pid == -1 && errno != ECHILD) - err(1, "wait3"); + err(1, "waitpid"); +} + +#define NOPID (0) + +static void +pids_init(void) +{ + int i; + + if ((childpids = malloc(maxprocs * sizeof(*childpids))) == NULL) + errx(1, "malloc failed"); + + for (i = 0; i < maxprocs; i++) + clearslot(i); +} + +static int +pids_empty(void) +{ + return (curprocs == 0); +} + +static int +pids_full(void) +{ + return (curprocs >= maxprocs); +} + +static void +pids_add(pid_t pid) +{ + int slot; + + slot = findfreeslot(); + childpids[slot] = pid; + curprocs++; +} + +static int +pids_remove(pid_t pid) +{ + int slot; + + if ((slot = findslot(pid)) < 0) + return (0); + + clearslot(slot); + curprocs--; + return (1); +} + +static int +findfreeslot(void) +{ + int slot; + + if ((slot = findslot(NOPID)) < 0) + errx(1, "internal error: no free pid slot"); + + return (slot); +} + +static int +findslot(pid_t pid) +{ + int slot; + + for (slot = 0; slot < maxprocs; slot++) + if (childpids[slot] == pid) + return (slot); + + return (-1); +} + +static void +clearslot(int slot) +{ + childpids[slot] = NOPID; } /*