--- old/usr/src/cmd/xargs/xargs.c	2014-03-31 18:53:08.000000000 +0000
+++ new/usr/src/cmd/xargs/xargs.c	2014-03-31 18:53:08.000000000 +0000
@@ -89,6 +89,7 @@
 #define	MISSQUOTE	"Missing quote"
 #define	BADESCAPE	"Incomplete escape"
 #define	IBUFOVERFLOW	"Insert buffer overflow"
+#define	NOCHILDSLOT	"No free child slot available"
 
 #define	_(x)	gettext(x)
 
@@ -109,6 +110,7 @@
 
 static int	PROMPT = -1;
 static int	BUFLIM = BUFSIZE;
+static int	MAXPROCS = 1;
 static int	N_ARGS = 0;
 static int	N_args = 0;
 static int	N_lines = 0;
@@ -127,15 +129,17 @@
 static int	mac;		/* modified argc, after parsing		*/
 static char	**mav;		/* modified argv, after parsing		*/
 static int	n_inserts;	/* # of insertions.			*/
+static pid_t	*procs;		/* pids of children			*/
+static int	n_procs;	/* # of child processes.		*/
 
 /* our usage message:							*/
 #define	USAGEMSG "Usage: xargs: [-t] [-p] [-0] [-e[eofstr]] [-E eofstr] "\
-	"[-I replstr] [-i[replstr]] [-L #] [-l[#]] [-n # [-x]] [-s size] "\
+	"[-I replstr] [-i[replstr]] [-L #] [-l[#]] [-n # [-x]] [-P maxprocs] [-s size] "\
 	"[cmd [args ...]]\n"
 
 static int	echoargs();
 static wint_t	getwchr(char *, size_t *);
-static int	lcall(char *sub, char **subargs);
+static void	lcall(char *sub, char **subargs);
 static void	addibuf(struct inserts *p);
 static void	ermsg(char *messages, ...);
 static char	*addarg(char *arg);
@@ -144,6 +148,12 @@
 static char	*insert(char *pattern, char *subst);
 static void	usage();
 static void	parseargs();
+static void	procs_malloc(void);
+static int	procs_find(pid_t child);
+static void	procs_store(pid_t child);
+static int	procs_delete(pid_t child);
+static pid_t	procs_waitpid(int blocking, int *stat_loc);
+static void	procs_wait(int blocking);
 
 int
 main(int argc, char **argv)
@@ -173,7 +183,7 @@
 	parseargs(argc, argv);
 
 	/* handling all of xargs arguments:				*/
-	while ((c = getopt(mac, mav, "0tpe:E:I:i:L:l:n:s:x")) != EOF) {
+	while ((c = getopt(mac, mav, "0tpe:E:I:i:L:l:n:P:s:x")) != EOF) {
 		switch (c) {
 		case '0':
 			ZERO = TRUE;
@@ -296,6 +306,14 @@
 			}
 			break;
 
+		case 'P':	/* -P maxprocs: # of child processses	*/
+			MAXPROCS = atoi(optarg);
+			if (MAXPROCS <= 0) {
+				ermsg(_("#maxprocs must be positive int: %s\n"),
+				    optarg);
+			}
+			break;
+
 		case 's':	/* -s size: set max size of each arg list */
 			BUFLIM = atoi(optarg);
 			if (BUFLIM > BUFSIZE || BUFLIM <= 0) {
@@ -336,6 +354,8 @@
 	mac -= optind;	/* dec arg count by what we've processed 	*/
 	mav += optind;	/* inc to current mav				*/
 
+	(void) procs_malloc();
+
 	if (mac <= 0) {	/* if there're no more args to process,	*/
 		cmdname = "/usr/bin/echo";	/* our default command	*/
 		*ARGV++ = addarg(cmdname);	/* use the default cmd.	*/
@@ -406,6 +426,7 @@
 				 */
 				if (LEGAL || N_args == 0) {
 					EMSG(LIST2LONG);
+					(void) procs_wait(1);
 					exit(2);
 					/* NOTREACHED */
 				}
@@ -435,7 +456,7 @@
 		*ARGV = NULL;
 		if (N_args == 0) {
 			/* Reached the end with no more work. */
-			exit(exitstat);
+			break;
 		}
 
 		/* insert arg if requested */
@@ -464,6 +485,7 @@
 			}
 			if (linesize >= BUFLIM) {
 				EMSG(LIST2LONG);
+				(void) procs_wait(1);
 				exit(2);
 				/* NOTREACHED */
 			}
@@ -484,11 +506,13 @@
 				 * so if we have a non-zero status here,
 				 * quit immediately.
 				 */
-				exitstat |= lcall(cmdname, arglist);
+				(void) lcall(cmdname, arglist);
 			}
 		}
 	}
 
+	(void) procs_wait(1);
+
 	if (OK)
 		return (exitstat);
 
@@ -837,34 +861,18 @@
 }
 
 
-static int
+static void
 lcall(char *sub, char **subargs)
 {
-	int retcode, retry = 0;
-	pid_t iwait, child;
+	int	retry = 0;
+	pid_t	child;
 
 	for (;;) {
 		switch (child = fork()) {
 		default:
-			while ((iwait = wait(&retcode)) != child &&
-			    iwait != (pid_t)-1)
-				;
-			if (iwait == (pid_t)-1) {
-				PERR(WAITFAIL);
-				exit(122);
-				/* NOTREACHED */
-			}
-			if (WIFSIGNALED(retcode)) {
-				EMSG2(CHILDSIG, WTERMSIG(retcode));
-				exit(125);
-				/* NOTREACHED */
-			}
-			if ((WEXITSTATUS(retcode) & 0377) == 0377) {
-				EMSG(CHILDFAIL);
-				exit(124);
-				/* NOTREACHED */
-			}
-			return (WEXITSTATUS(retcode));
+			(void) procs_store(child);
+			(void) procs_wait(0);
+			return;
 		case 0:
 			(void) execvp(sub, subargs);
 			PERR(EXECFAIL);
@@ -882,6 +890,112 @@
 	}
 }
 
+static void
+procs_malloc(void)
+{
+	int	i;
+
+	procs = (pid_t *)(malloc(MAXPROCS * sizeof(pid_t)));
+	if (procs == NULL) {
+		PERR(MALLOCFAIL);
+		exit(1);
+	}
+
+	for (i = 0; i < MAXPROCS; i++) {
+		procs[i] = (pid_t)(0);
+	}
+}
+
+static int
+procs_find(pid_t child)
+{
+	int	i;
+
+	for (i = 0; i < MAXPROCS; i++) {
+		if (procs[i] == child) {
+			return (i);
+		}
+	}
+
+	return (-1);
+}
+
+static void
+procs_store(pid_t child)
+{
+	int	i;
+
+	i = procs_find((pid_t)(0));
+	if (i < 0) {
+		PERR(NOCHILDSLOT);
+		exit(1);
+	}
+	procs[i] = child;
+	n_procs++;
+}
+
+static int
+procs_delete(pid_t child)
+{
+	int	i;
+
+	i = procs_find(child);
+	if (i < 0) {
+		return (0);
+	}
+	procs[i] = (pid_t)(0);
+	n_procs--;
+	return (1);
+}
+
+static pid_t
+procs_waitpid(int blocking, int *stat_loc)
+{
+	pid_t	child;
+	int	options;
+
+	if (n_procs == 0) {
+		errno = ECHILD;
+		return (-1);
+	}
+
+	options = (blocking) ? 0 : WNOHANG;
+
+	while ((child = waitpid(-1, stat_loc, options)) > 0) {
+		if (procs_delete(child)) {
+			break;
+		}
+	}
+
+	return (child);
+}
+
+static void
+procs_wait(int blocking)
+{
+	pid_t	child;
+	int	stat_loc;
+
+	while ((child = procs_waitpid(blocking || (n_procs >= MAXPROCS) ? 1 : 0, &stat_loc)) > 0) {
+		if (WIFSIGNALED(stat_loc)) {
+			EMSG2(CHILDSIG, WTERMSIG(stat_loc));
+			exit(125);
+			/* NOTREACHED */
+		} else if ((WEXITSTATUS(stat_loc) & 0377) == 0377) {
+			EMSG(CHILDFAIL);
+			exit(124);
+			/* NOTREACHED */
+		} else {
+			exitstat |= WEXITSTATUS(stat_loc);
+		}
+	}
+
+	if (child == (pid_t)(-1) && errno != ECHILD) {
+		EMSG(WAITFAIL);
+		exit(122);
+		/* NOTREACHED */
+	}
+}
 
 static void
 usage()
@@ -980,6 +1094,7 @@
 			 * and the new XCU4 way of handling things are allowed.
 			 */
 			case	'n':	/* FALLTHROUGH			*/
+			case	'P':	/* FALLTHROUGH			*/
 			case	's':	/* FALLTHROUGH			*/
 			case	'E':	/* FALLTHROUGH			*/
 			case	'I':	/* FALLTHROUGH			*/
--- old/usr/src/man/man1/xargs.1	2014-03-31 18:53:09.000000000 +0000
+++ new/usr/src/man/man1/xargs.1	2014-03-31 18:53:09.000000000 +0000
@@ -7,7 +7,7 @@
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH XARGS 1 "November 24, 2012"
+.TH XARGS 1 "March 31, 2014"
 .SH NAME
 xargs \- construct argument lists and invoke utility
 .SH SYNOPSIS
@@ -15,7 +15,8 @@
 .nf
 \fBxargs\fR [\fB-t\fR] [\fB-0\fR] [\fB-p\fR] [\fB-e\fR[\fIeofstr\fR]] [\fB-E\fR \fIeofstr\fR]
      [\fB-I\fR \fIreplstr\fR] [\fB-i\fR[\fIreplstr\fR]] [\fB-L\fR \fInumber\fR] [\fB-l\fR[\fInumber\fR]]
-     [\fB-n\fR \fInumber\fR [\fB-x\fR]] [\fB-s\fR \fIsize\fR] [\fIutility\fR [\fIargument\fR...]]
+     [\fB-n\fR \fInumber\fR [\fB-x\fR]] [\fB-P\fR \fImaxprocs\fR] [\fB-s\fR \fIsize\fR]
+     [\fIutility\fR [\fIargument\fR...]]
 .fi
 
 .SH DESCRIPTION
@@ -169,6 +170,16 @@
 .RE
 
 .sp
+.ne 2
+.na
+\fB\fB-P\fR \fImaxprocs\fR\fR
+.ad
+.RS 15n
+Invokes \fIutility\fR using at most \fImaxprocs\fR (a positive decimal integer)
+parallel child processes.
+.RE
+
+.sp
 .ne 2
 .na
 \fB\fB-s\fR \fIsize\fR\fR
