--- old/usr/src/man/man5/resource_controls.5	2013-09-26 12:54:42.355112010 +0000
+++ new/usr/src/man/man5/resource_controls.5	2013-09-26 12:54:42.369763476 +0000
@@ -3,7 +3,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 RESOURCE_CONTROLS 5 "Jul 2, 2007"
+.TH RESOURCE_CONTROLS 5 "Jul 19, 2013"
 .SH NAME
 resource_controls \- resource controls available through project database
 .SH DESCRIPTION
@@ -171,6 +171,16 @@
 .sp
 .ne 2
 .na
+\fB\fBprocess.max-sigqueue-size\fR\fR
+.ad
+.sp .6
+.RS 4n
+Maximum number of outstanding queued signals.
+.RE
+
+.sp
+.ne 2
+.na
 \fB\fBprocess.max-stack-size\fR\fR
 .ad
 .sp .6
--- old/usr/src/pkg/manifests/system-test-ostest.mf	2013-09-26 12:54:42.802014479 +0000
+++ new/usr/src/pkg/manifests/system-test-ostest.mf	2013-09-26 12:54:42.814830766 +0000
@@ -23,11 +23,13 @@
 dir path=opt/os-tests/bin
 dir path=opt/os-tests/runfiles
 dir path=opt/os-tests/tests
+dir path=opt/os-tests/tests/sigqueue
 file path=opt/os-tests/README mode=0444
 file path=opt/os-tests/bin/ostest mode=0555
 file path=opt/os-tests/runfiles/delphix.run mode=0444
 file path=opt/os-tests/runfiles/openindiana.run mode=0444
 file path=opt/os-tests/tests/poll_test mode=0555
+file path=opt/os-tests/tests/sigqueue/sigqueue_queue_size mode=0555
 license cr_Sun license=cr_Sun
 license lic_CDDL license=lic_CDDL
 depend fmri=system/test/testrunner type=require
--- old/usr/src/test/os-tests/runfiles/delphix.run	2013-09-26 12:54:43.250339033 +0000
+++ new/usr/src/test/os-tests/runfiles/delphix.run	2013-09-26 12:54:43.269542979 +0000
@@ -17,10 +17,12 @@
 pre =
 verbose = False
 quiet = False
-user = root
 timeout = 60
 post =
 outputdir = /var/tmp/test_results
 
 [/opt/os-tests/tests/poll_test]
+user = root
 
+[/opt/os-tests/tests/sigqueue]
+tests = ['sigqueue_queue_size']
--- old/usr/src/test/os-tests/runfiles/openindiana.run	2013-09-26 12:54:43.651988775 +0000
+++ new/usr/src/test/os-tests/runfiles/openindiana.run	2013-09-26 12:54:43.667224230 +0000
@@ -17,10 +17,12 @@
 pre =
 verbose = False
 quiet = False
-user = root
 timeout = 60
 post =
 outputdir = /var/tmp/test_results
 
 [/opt/os-tests/tests/poll_test]
+user = root
 
+[/opt/os-tests/tests/sigqueue]
+tests = ['sigqueue_queue_size']
--- old/usr/src/test/os-tests/tests/Makefile	2013-09-26 12:54:44.092672861 +0000
+++ new/usr/src/test/os-tests/tests/Makefile	2013-09-26 12:54:44.111260488 +0000
@@ -13,6 +13,6 @@
 # Copyright (c) 2012 by Delphix. All rights reserved.
 #
 
-SUBDIRS = poll
+SUBDIRS = poll sigqueue
 
 include $(SRC)/test/Makefile.com
--- /dev/null	2013-09-26 12:54:44.000000000 +0000
+++ new/usr/src/test/os-tests/tests/sigqueue/Makefile	2013-09-26 12:54:44.567954986 +0000
@@ -0,0 +1,57 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright (c) 2013 David Hoeppner. All rights reserved.
+#
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+PROG = sigqueue_queue_size
+OBJS = $(PROG:%=%.o)
+SRCS = $(OBJS:%.o=%.c)
+
+C99MODE = -xc99=%all
+
+ROOTOPTPKG = $(ROOT)/opt/os-tests
+TESTDIR = $(ROOTOPTPKG)/tests/sigqueue
+
+CMDS = $(PROG:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+	$(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+	$(POST_PROCESS)
+
+%.o: ../%.c
+	$(COMPILE.c) $<
+
+install: all $(CMDS)
+
+lint: lint_SRCS
+
+clobber: clean
+	-$(RM) $(PROG)
+
+clean:
+	-$(RM) $(OBJS)
+
+$(CMDS): $(TESTDIR) $(PROG)
+
+$(TESTDIR):
+	$(INS.dir)
+
+$(TESTDIR)/%: %
+	$(INS.file)
--- /dev/null	2013-09-26 12:54:44.000000000 +0000
+++ new/usr/src/test/os-tests/tests/sigqueue/sigqueue_queue_size.c	2013-09-26 12:54:44.792940082 +0000
@@ -0,0 +1,168 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2013 David Hoeppner.  All rights reserved.
+ */
+
+/*
+ * Queue maximum number of signals and test if we can queue more signals then
+ * allowed.
+ */
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+#define	SIGQUEUE_SIGNAL		SIGRTMIN	/* Signal used for testing */
+
+int nreceived = 0;
+
+static void
+test_start(const char *test_name, const char *format, ...)
+{
+	va_list args;
+
+	(void) printf("TEST STARTING %s: ", test_name);
+
+	va_start(args, format);
+	(void) vprintf(format, args);
+	va_end(args);
+	(void) fflush(stdout);
+}
+
+static void
+test_failed(const char *test_name, const char *format, ...)
+{
+	va_list args;
+
+	(void) printf("TEST FAILED %s: ", test_name);
+
+	va_start(args, format);
+	(void) vprintf(format, args);
+	va_end(args);
+
+	(void) exit(-1);
+}
+
+static void
+test_passed(const char *test_name)
+{
+	(void) printf("TEST PASS: %s\n", test_name);
+	(void) fflush(stdout);
+}
+
+/* ARGSUSED */
+static void
+maximum_test_handler(int signal, siginfo_t *siginfo, void *context)
+{
+	nreceived++;
+}
+
+static void
+sigqueue_maximum_test(void)
+{
+	const char *test_name = __func__;
+	struct sigaction action;
+	long sigqueue_max, i;
+	pid_t pid;
+	union sigval value;
+	int error;
+
+	test_start(test_name, "queue maximum number of signals\n");
+
+	/*
+	 * Get the maximum size of the queue.
+	 */
+	sigqueue_max = sysconf(_SC_SIGQUEUE_MAX);
+	if (sigqueue_max == -1) {
+		test_failed(test_name, "sysconf\n");
+	}
+
+	/*
+	 * Put the signal on hold.
+	 */
+	error = sighold(SIGQUEUE_SIGNAL);
+	if (error == -1) {
+		test_failed(test_name, "sighold\n");
+	}
+
+	pid = getpid();
+	value.sival_int = 0;
+
+	action.sa_flags = SA_SIGINFO;
+	action.sa_sigaction = maximum_test_handler;
+
+	error = sigemptyset(&action.sa_mask);
+	if (error == -1) {
+		test_failed(test_name, "sigemptyset\n");
+	}
+
+	/*
+	 * Set signal handler.
+	 */
+	error = sigaction(SIGQUEUE_SIGNAL, &action, 0);
+	if (error == -1) {
+		test_failed(test_name, "sigaction\n");
+	}
+
+	/*
+	 * Fill the signal queue to the maximum.
+	 */
+	for (i = 0; i < sigqueue_max; i++) {
+		error = sigqueue(pid, SIGQUEUE_SIGNAL, value);
+		if (error == -1) {
+			test_failed(test_name, "sigqueue\n");
+		}
+	}
+
+	/*
+	 * Send a further signal and test if we get the expected
+	 * error.
+	 */
+	error = sigqueue(pid, SIGQUEUE_SIGNAL, value);
+	if (error != -1) {
+		test_failed(test_name, "sigqueue\n");
+	}
+
+	/*
+	 * Unblock the signals and check if we received all messages
+	 * from the signal queue.
+	 */
+	error = sigrelse(SIGQUEUE_SIGNAL);
+	if (error == -1) {
+		test_failed(test_name, "sigrelse\n");
+	}
+
+	if (nreceived != sigqueue_max) {
+		test_failed(test_name, "nreceived != sigqueue_max\n");
+	}
+
+	test_passed(test_name);
+}
+
+static void
+run_tests(void)
+{
+	sigqueue_maximum_test();
+}
+
+/* ARGSUSED */
+int
+main(int argc, char *argv[])
+{
+	run_tests();
+
+	return (EXIT_SUCCESS);
+}
--- old/usr/src/test/test-runner/cmd/run.py	2013-09-26 12:54:44.999486185 +0000
+++ new/usr/src/test/test-runner/cmd/run.py	2013-09-26 12:54:45.015542337 +0000
@@ -714,7 +714,7 @@
     p = Popen(testcmd)
     p.wait()
     if p.returncode is not 0:
-        logger.info("Warning: user '%s' cannot use paswordless sudo.", user)
+        logger.info("Warning: user '%s' cannot use passwordless sudo.", user)
         return False
     else:
         Cmd.verified_users.append(user)
--- old/usr/src/uts/common/os/rctl_proc.c	2013-09-26 12:54:45.460193163 +0000
+++ new/usr/src/uts/common/os/rctl_proc.c	2013-09-26 12:54:45.472256654 +0000
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/cmn_err.h>
 #include <sys/sysmacros.h>
@@ -32,6 +30,8 @@
 #include <sys/rctl.h>
 #include <sys/rctl_impl.h>
 #include <sys/port_kernel.h>
+#include <sys/signal.h>
+#include <sys/var.h>
 
 #include <sys/vmparam.h>
 #include <sys/machparam.h>
@@ -65,6 +65,7 @@
 rctl_hndl_t rc_process_semmsl;
 rctl_hndl_t rc_process_semopm;
 rctl_hndl_t rc_process_portev;
+rctl_hndl_t rc_process_sigqueue;
 
 /*
  * process.max-cpu-time / RLIMIT_CPU
@@ -288,7 +289,7 @@
  *   here as the native and ILP32 infinite values for each resource control.
  */
 void
-rctlproc_init()
+rctlproc_init(void)
 {
 	rctl_set_t *set;
 	rctl_alloc_gp_t *gp;
@@ -369,6 +370,20 @@
 	    RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
 
 	/*
+	 * We set the upper limit to the maximum number of processes per user
+	 * to make it theoretical possible to deliver all SIGCHILD signals on
+	 * child termination, but at least to 8k.
+	 */
+	rc_process_sigqueue = rctl_register("process.max-sigqueue-size",
+	    RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
+	    RCTL_GLOBAL_COUNT, MAX(v.v_maxup, 8192), MAX(v.v_maxup, 8192),
+	    &rctl_absolute_ops);
+	rctl_add_default_limit("process.max-sigqueue-size",
+	    _SIGQUEUE_SIZE_BASIC, RCPRIV_BASIC, RCTL_LOCAL_DENY);
+	rctl_add_default_limit("process.max-sigqueue-size",
+	    _SIGQUEUE_SIZE_PRIVILEGED, RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
+
+	/*
 	 * Place minimal set of controls on "sched" process for inheritance by
 	 * processes created via newproc().
 	 */
--- old/usr/src/uts/common/os/sig.c	2013-09-26 12:54:45.886512550 +0000
+++ new/usr/src/uts/common/os/sig.c	2013-09-26 12:54:45.901651710 +0000
@@ -2371,13 +2371,9 @@
 	return (0);
 }
 
-#ifndef	UCHAR_MAX
-#define	UCHAR_MAX	255
-#endif
-
 /*
- * The entire pool (with maxcount entries) is pre-allocated at
- * the first sigqueue/signotify call.
+ * The pre-allocated pool (with _SIGQUEUE_PREALLOC entries) is
+ * allocated at the first sigqueue/signotify call.
  */
 sigqhdr_t *
 sigqhdralloc(size_t size, uint_t maxcount)
@@ -2386,16 +2382,22 @@
 	sigqueue_t *sq, *next;
 	sigqhdr_t *sqh;
 
-	i = (maxcount * size) + sizeof (sigqhdr_t);
-	ASSERT(maxcount <= UCHAR_MAX && i <= USHRT_MAX);
+	/*
+	 * Before the introduction of process.max-sigqueue-size
+	 * _SC_SIGQUEUE_MAX had this static value.
+	 */
+#define	_SIGQUEUE_PREALLOC	32
+
+	i = (_SIGQUEUE_PREALLOC * size) + sizeof (sigqhdr_t);
+	ASSERT(maxcount <= INT_MAX);
 	sqh = kmem_alloc(i, KM_SLEEP);
-	sqh->sqb_count = (uchar_t)maxcount;
-	sqh->sqb_maxcount = (uchar_t)maxcount;
-	sqh->sqb_size = (ushort_t)i;
+	sqh->sqb_count = maxcount;
+	sqh->sqb_maxcount = maxcount;
+	sqh->sqb_size = i;
 	sqh->sqb_pexited = 0;
 	sqh->sqb_sent = 0;
 	sqh->sqb_free = sq = (sigqueue_t *)(sqh + 1);
-	for (i = maxcount - 1; i != 0; i--) {
+	for (i = _SIGQUEUE_PREALLOC - 1; i != 0; i--) {
 		next = (sigqueue_t *)((uintptr_t)sq + size);
 		sq->sq_next = next;
 		sq = next;
@@ -2409,8 +2411,9 @@
 static void sigqrel(sigqueue_t *);
 
 /*
- * allocate a sigqueue/signotify structure from the per process
- * pre-allocated pool.
+ * Allocate a sigqueue/signotify structure from the per process
+ * pre-allocated pool or allocate a new sigqueue/signotify structure
+ * if the pre-allocated pool is exhausted.
  */
 sigqueue_t *
 sigqalloc(sigqhdr_t *sqh)
@@ -2423,12 +2426,20 @@
 		mutex_enter(&sqh->sqb_lock);
 		if (sqh->sqb_count > 0) {
 			sqh->sqb_count--;
-			sq = sqh->sqb_free;
-			sqh->sqb_free = sq->sq_next;
+			if (sqh->sqb_free == NULL) {
+				/*
+				 * The pre-allocated pool is exhausted.
+				 */
+				sq = kmem_alloc(sizeof (sigqueue_t), KM_SLEEP);
+				sq->sq_func = NULL;
+			} else {
+				sq = sqh->sqb_free;
+				sq->sq_func = sigqrel;
+				sqh->sqb_free = sq->sq_next;
+			}
 			mutex_exit(&sqh->sqb_lock);
 			bzero(&sq->sq_info, sizeof (k_siginfo_t));
 			sq->sq_backptr = sqh;
-			sq->sq_func = sigqrel;
 			sq->sq_next = NULL;
 			sq->sq_external = 0;
 		} else {
--- old/usr/src/uts/common/sys/signal.h	2013-09-26 12:54:46.405739161 +0000
+++ new/usr/src/uts/common/sys/signal.h	2013-09-26 12:54:46.416168552 +0000
@@ -300,19 +300,20 @@
 	u_longlong_t	sn_snid;	/* unique id for notification	*/
 } signotifyq_t;
 
-
 typedef struct sigqhdr {		/* sigqueue pool header		*/
 	sigqueue_t	*sqb_free;	/* free sigq struct list	*/
-	uchar_t		sqb_count;	/* sigq free count		*/
-	uchar_t		sqb_maxcount;	/* sigq max free count		*/
-	ushort_t	sqb_size;	/* size of header+free structs	*/
+	int		sqb_count;	/* sigq free count		*/
+	uint_t		sqb_maxcount;	/* sigq max free count		*/
+	size_t		sqb_size;	/* size of header+free structs	*/
 	uchar_t		sqb_pexited;	/* process has exited		*/
-	uchar_t		sqb_sent;	/* number of sigq sent		*/
+	uint_t		sqb_sent;	/* number of sigq sent		*/
 	kcondvar_t	sqb_cv;		/* waiting for a sigq struct	*/
 	kmutex_t	sqb_lock;	/* lock for sigq pool		*/
 } sigqhdr_t;
 
-#define	_SIGQUEUE_MAX	32
+#define	_SIGQUEUE_SIZE_BASIC		128	/* basic limit */
+#define	_SIGQUEUE_SIZE_PRIVILEGED	512	/* privileged limit */
+
 #define	_SIGNOTIFY_MAX	32
 
 extern	void	setsigact(int, void (*)(int), const k_sigset_t *, int);
--- old/usr/src/uts/common/syscall/sigqueue.c	2013-09-26 12:54:46.850451582 +0000
+++ new/usr/src/uts/common/syscall/sigqueue.c	2013-09-26 12:54:46.862537949 +0000
@@ -26,8 +26,6 @@
 
 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/sysmacros.h>
@@ -40,6 +38,8 @@
 #include <sys/siginfo.h>
 #include <sys/debug.h>
 
+extern rctl_hndl_t rc_process_sigqueue;
+
 static int
 sigqkill(pid_t pid, sigsend_t *sigsend)
 {
@@ -121,7 +121,7 @@
  */
 int
 sigqueue(pid_t pid, int sig, /* union sigval */ void *value,
-	int si_code, int block)
+    int si_code, int block)
 {
 	int error;
 	sigsend_t v;
@@ -133,8 +133,15 @@
 		return (set_errno(EINVAL));
 
 	if ((sqh = p->p_sigqhdr) == NULL) {
+		rlim64_t sigqsz_max;
+
+		mutex_enter(&p->p_lock);
+		sigqsz_max = rctl_enforced_value(rc_process_sigqueue,
+		    p->p_rctls, p);
+		mutex_exit(&p->p_lock);
+
 		/* Allocate sigqueue pool first time */
-		sqh = sigqhdralloc(sizeof (sigqueue_t), _SIGQUEUE_MAX);
+		sqh = sigqhdralloc(sizeof (sigqueue_t), (uint_t)sigqsz_max);
 		mutex_enter(&p->p_lock);
 		if (p->p_sigqhdr == NULL) {
 			/* hang the pool head on proc */
--- old/usr/src/uts/common/syscall/sysconfig.c	2013-09-26 12:54:47.288065793 +0000
+++ new/usr/src/uts/common/syscall/sysconfig.c	2013-09-26 12:54:47.306884039 +0000
@@ -47,6 +47,8 @@
 #include <sys/zone.h>
 #include <sys/vm_usage.h>
 
+extern rctl_hndl_t rc_process_sigqueue;
+
 long
 sysconfig(int which)
 {
@@ -140,7 +142,17 @@
 		return (_SEM_VALUE_MAX);
 
 	case _CONFIG_SIGQUEUE_MAX:
-		return (_SIGQUEUE_MAX);
+		/*
+		 * Maximum number of outstanding queued signals.
+		 */
+		{
+			rlim64_t sigqsz_max;
+			mutex_enter(&curproc->p_lock);
+			sigqsz_max = rctl_enforced_value(rc_process_sigqueue,
+			    curproc->p_rctls, curproc);
+			mutex_exit(&curproc->p_lock);
+			return ((uint_t)sigqsz_max);
+		}
 
 	case _CONFIG_SIGRT_MIN:
 		return (_SIGRTMIN);
