--- old/usr/src/lib/libc/port/threads/sigaction.c	Sun Nov  2 01:27:47 2014
+++ new/usr/src/lib/libc/port/threads/sigaction.c	Sun Nov  2 01:27:47 2014
@@ -20,6 +20,7 @@
  */
 
 /*
+ * Copyright 2014 Ryan Zezeski.  All rights reserved.
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
@@ -70,6 +71,7 @@
 void
 call_user_handler(int sig, siginfo_t *sip, ucontext_t *ucp)
 {
+	int i;
 	ulwp_t *self = curthread;
 	uberdata_t *udp = self->ul_uberdata;
 	struct sigaction uact;
@@ -155,6 +157,20 @@
 	}
 	if (!(uact.sa_flags & SA_NODEFER))	/* add current signal */
 		(void) sigaddset(&uact.sa_mask, sig);
+
+	/*
+	 * Enforce the proper order for realtime signals.  Lower signals
+	 * have higher priority and multiple instances of the same signal
+	 * must arrive in FIFO order (NODEFER does not apply).
+	 *
+	 * See section 2.4.2 of POSIX.
+	 */
+	if ((sig >= SIGRTMIN) && (sig <= SIGRTMAX)) {
+		for (i = sig; i <= SIGRTMAX; i++) {
+			(void) sigaddset(&uact.sa_mask, i);
+		}
+	}
+
 	self->ul_sigmask = uact.sa_mask;
 	self->ul_siglink = ucp;
 	(void) __lwp_sigmask(SIG_SETMASK, &uact.sa_mask);
--- old/usr/src/man/man2/sigaction.2	Sun Nov  2 01:27:47 2014
+++ new/usr/src/man/man2/sigaction.2	Sun Nov  2 01:27:47 2014
@@ -1,10 +1,11 @@
 '\" te
+.\" Copyright (c) 2014, Ryan Zezeski.  All Rights Reserved.
 .\" Copyright (c) 2007, Sun Microsystems, Inc.  All Rights Reserved.
 .\" Copyright 1989 AT&T
 .\" 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 SIGACTION 2 "Mar 23, 2005"
+.TH SIGACTION 2 "Oct 22, 2014"
 .SH NAME
 sigaction \- detailed signal management
 .SH SYNOPSIS
@@ -17,7 +18,6 @@
 .fi
 
 .SH DESCRIPTION
-.sp
 .LP
 The \fBsigaction()\fR function allows the calling process to examine or specify
 the action to be taken on delivery of a specific signal. See
@@ -104,8 +104,10 @@
 \fB\fBSA_NODEFER\fR\fR
 .ad
 .RS 16n
-If set and the signal is caught, the signal will not be automatically blocked
-by the kernel while it is being caught.
+If set and the signal is caught, the signal will not be automatically
+blocked by the kernel while it is being caught.  Unless the signal is
+a realtime signal.  Multiple instances of the same realtime signal
+must be delivered in FIFO order and thus are always deferred.
 .RE
 
 .sp
@@ -167,13 +169,11 @@
 .RE
 
 .SH RETURN VALUES
-.sp
 .LP
 Upon successful completion, \fB0\fR is returned. Otherwise, \fB\(mi1\fR is
 returned, \fBerrno\fR is set to indicate the error, and no new signal handler
 is installed.
 .SH ERRORS
-.sp
 .LP
 The \fBsigaction()\fR function will fail if:
 .sp
@@ -188,7 +188,6 @@
 .RE
 
 .SH ATTRIBUTES
-.sp
 .LP
 See \fBattributes\fR(5) for descriptions of the following attributes:
 .sp
@@ -208,7 +207,6 @@
 .TE
 
 .SH SEE ALSO
-.sp
 .LP
 \fBkill\fR(1), \fBIntro\fR(2), \fBexit\fR(2), \fBfcntl\fR(2), \fBgetmsg\fR(2),
 \fBioctl\fR(2), \fBkill\fR(2), \fBpause\fR(2), \fBputmsg\fR(2), \fBread\fR(2),
@@ -218,7 +216,6 @@
 \fBsignal.h\fR(3HEAD), \fBsigsetops\fR(3C), \fBucontext.h\fR(3HEAD),
 \fBwait\fR(3C), \fBattributes\fR(5), \fBstandards\fR(5)
 .SH NOTES
-.sp
 .LP
 The handler routine can be declared:
 .sp
--- old/usr/src/pkg/manifests/system-test-ostest.mf	Sun Nov  2 01:27:48 2014
+++ new/usr/src/pkg/manifests/system-test-ostest.mf	Sun Nov  2 01:27:48 2014
@@ -12,6 +12,7 @@
 #
 # Copyright (c) 2012 by Delphix. All rights reserved.
 # Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
+# Copyright 2014, Ryan Zezeski. All rights reserved.
 #
 
 set name=pkg.fmri value=pkg:/system/test/ostest@$(PKGVERS)
@@ -24,6 +25,7 @@
 dir path=opt/os-tests/bin
 dir path=opt/os-tests/runfiles
 dir path=opt/os-tests/tests
+dir path=opt/os-tests/tests/rt_delivery
 dir path=opt/os-tests/tests/sigqueue
 file path=opt/os-tests/README mode=0444
 file path=opt/os-tests/bin/ostest mode=0555
@@ -31,6 +33,7 @@
 file path=opt/os-tests/runfiles/omnios.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/rt_delivery/rt_delivery 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
--- old/usr/src/test/os-tests/runfiles/delphix.run	Sun Nov  2 01:27:48 2014
+++ new/usr/src/test/os-tests/runfiles/delphix.run	Sun Nov  2 01:27:48 2014
@@ -10,6 +10,7 @@
 #
 
 #
+# Copyright (c) 2014 by Ryan Zezeski. All rights reserved.
 # Copyright (c) 2012 by Delphix. All rights reserved.
 #
 
@@ -26,3 +27,6 @@
 
 [/opt/os-tests/tests/sigqueue]
 tests = ['sigqueue_queue_size']
+
+[/opt/os-tests/tests/rt_delivery]
+tests = ['rt_delivery']
--- old/usr/src/test/os-tests/runfiles/omnios.run	Sun Nov  2 01:27:48 2014
+++ new/usr/src/test/os-tests/runfiles/omnios.run	Sun Nov  2 01:27:48 2014
@@ -10,6 +10,7 @@
 #
 
 #
+# Copyright (c) 2014 by Ryan Zezeski. All rights reserved.
 # Copyright (c) 2012 by Delphix. All rights reserved.
 #
 
@@ -26,3 +27,6 @@
 
 [/opt/os-tests/tests/sigqueue]
 tests = ['sigqueue_queue_size']
+
+[/opt/os-tests/tests/rt_delivery]
+tests = ['rt_delivery']
--- old/usr/src/test/os-tests/runfiles/openindiana.run	Sun Nov  2 01:27:48 2014
+++ new/usr/src/test/os-tests/runfiles/openindiana.run	Sun Nov  2 01:27:48 2014
@@ -10,6 +10,7 @@
 #
 
 #
+# Copyright (c) 2014 by Ryan Zezeski. All rights reserved.
 # Copyright (c) 2012 by Delphix. All rights reserved.
 #
 
@@ -26,3 +27,6 @@
 
 [/opt/os-tests/tests/sigqueue]
 tests = ['sigqueue_queue_size']
+
+[/opt/os-tests/tests/rt_delivery]
+tests = ['rt_delivery']
--- old/usr/src/test/os-tests/tests/Makefile	Sun Nov  2 01:27:48 2014
+++ new/usr/src/test/os-tests/tests/Makefile	Sun Nov  2 01:27:48 2014
@@ -10,9 +10,10 @@
 #
 
 #
+# Copyright (c) 2014 by Ryan Zezeski. All rights reserved.
 # Copyright (c) 2012 by Delphix. All rights reserved.
 #
 
-SUBDIRS = poll sigqueue
+SUBDIRS = poll sigqueue rt_delivery
 
 include $(SRC)/test/Makefile.com
--- /dev/null	Sun Nov  2 01:27:48 2014
+++ new/usr/src/test/os-tests/tests/rt_delivery/Makefile	Sun Nov  2 01:27:48 2014
@@ -0,0 +1,56 @@
+#
+# 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) 2014 Ryan Zezeski. All rights reserved.
+#
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+PROG = rt_delivery
+OBJS = $(PROG:%=%.o)
+SRCS = $(OBJS:%.o=%.c)
+
+C99MODE = -xc99=%all
+
+ROOTOPTPKG = $(ROOT)/opt/os-tests
+TESTDIR = $(ROOTOPTPKG)/tests/rt_delivery
+
+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	Sun Nov  2 01:27:48 2014
+++ new/usr/src/test/os-tests/tests/rt_delivery/rt_delivery.c	Sun Nov  2 01:27:48 2014
@@ -0,0 +1,246 @@
+/*
+ * 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 2014 Ryan Zezeski.  All rights reserved.
+ */
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+/*
+ * The `seq` struct and `sh` handler are used to record the order in which
+ * the signals are delivered to the parent process.  When a signal is
+ * delivered the handler records it in seq and then increments the index.
+ */
+struct seq {
+	int sig, num;
+};
+
+static struct seq *seqp;
+
+/* ARGSUSED */
+void
+sh(int sig, siginfo_t *info, void *unused)
+{
+	static int i;
+	seqp[i].num = info->si_value.sival_int;
+	seqp[i++].sig = sig;
+}
+
+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);
+}
+
+/*
+ * Verify the delivery order of realtime (RT) signals.  RT signals were
+ * introduced in POSIX.1b and differ from regular signals in several key
+ * ways:
+ *
+ * 1. Multiple instances of the same signal are queued and must be
+ * delivered in FIFO order.
+ *
+ * 2. If multiple different RT signals are pending then the lower numbered
+ * RT signals are delivered first.  I.e., RT signals have a notion of
+ * priority.
+ *
+ * See sections 2.4.2 (Realtime Signal Generation and Delivery) and B.2.4
+ * of the POSIX.1-2008 standard for more information.
+ */
+static int
+rt_delivery(const char *test_name, int no_defer)
+{
+	int i, j, sig, sival, sigend, numsig, rc, fail = 0;
+	pid_t p = getpid(), chld;
+	struct sigaction sa;
+	sigset_t ss, ssold;
+	union sigval sv;
+
+	/*
+	 * Range of signals to send.  Each signal is sent 2 times to verify FIFO
+	 * order.
+	 */
+	sigend = SIGRTMIN + (sysconf(_SC_SIGQUEUE_MAX) / 2);
+	sigend = sigend > SIGRTMAX ? SIGRTMAX : sigend;
+	numsig = (sigend - SIGRTMIN) * 2;
+
+	seqp = malloc(sizeof (struct seq) * numsig);
+
+	/*
+	 * Step 1:
+	 *
+	 * Install the signal handler (sh) on this process (the parent).
+	 */
+	(void) sigemptyset(&ss);
+	for (i = SIGRTMIN; i < sigend; i++) {
+		sa.sa_sigaction = sh;
+		sa.sa_flags = SA_SIGINFO;
+		sa.sa_flags |= (no_defer ? SA_NODEFER : 0);
+		(void) sigemptyset(&sa.sa_mask);
+		sigaction(i, &sa, NULL);
+		(void) sigaddset(&ss, i);
+	}
+
+	/*
+	 * Step 2:
+	 *
+	 * Block all signals that are about to be sent to this process.
+	 * This is needed to make sure all signals are pending at once.
+	 * This is related to step 4.
+	 */
+	(void) sigprocmask(SIG_BLOCK, &ss, &ssold);
+
+	/*
+	 * Step 3:
+	 *
+	 * Fork a child process to send each RT signal 2 times to the
+	 * parent process.  Remember, all signals being sent are RT
+	 * signals and thus are subject to explicit ordering guarantees
+	 * spelled out in POSIX.1b.  Lower numbered RT signals are
+	 * _always_ delivered before higher RT signals.
+	 */
+	if ((chld = fork()) == 0) {
+		for (i = SIGRTMIN; i < sigend; i++) {
+			for (j = 0; j < 2; j++) {
+				sv.sival_int = j;
+				if (sigqueue(p, i, sv) == -1) {
+					perror("problem generating signal");
+					exit(1);
+				}
+			}
+		}
+		exit(0);
+	}
+
+	/*
+	 * Step 4:
+	 *
+	 * Wait for forked process to finish sending all signals.  This is
+	 * to make sure that all signals are pending before allowing the
+	 * kernel to deliver them to the handler.  If you don't both wait
+	 * and block then the handler will process the signals as they
+	 * come in and thus we will not be testing the ordering
+	 * guarentees.  Related to step 2.
+	 */
+	if (wait(&rc) != chld) {
+		test_failed(test_name, "failed to wait for child\n");
+	}
+
+	if (rc != 0) {
+		test_failed(test_name, "child exited non-zero\n");
+	}
+	(void) sigprocmask(SIG_SETMASK, &ssold, NULL);
+
+	/*
+	 * Step 5:
+	 *
+	 * Verify that multiple pending RT signals are delivered in
+	 * correct priority (lower signals first), and that multiple
+	 * instances of the same RT signal are delivered in FIFO order.
+	 *
+	 * E.g. if SIGRTMIN is 42 then the handler should record this
+	 * ordering:
+	 *
+	 * {42, 0}, {42, 1}, {42, 2}, {43, 0}, {43, 1}, {43, 2}, ...
+	 */
+	sig = SIGRTMIN;
+	sival = 0;
+	for (i = 0; i < numsig; i++) {
+		if ((seqp[i].sig != sig) || seqp[i].num != sival) {
+			fail = 1;
+		}
+		sig = ((i + 1) % 2) == 0 ? sig + 1 : sig;
+		sival = ((i + 1) % 2) == 0 ? 0 : sival + 1;
+	}
+
+	if (fail) {
+		sig = SIGRTMIN;
+		sival = 0;
+		(void) fprintf(stderr, "Excpted Actual\n");
+		for (i = 0; i < numsig; i++) {
+			(void) fprintf(stderr, "{%2d,%d}  {%2d,%d}\n",
+			    sig, sival, seqp[i].sig, seqp[i].num);
+
+			sig = ((i + 1) % 2) == 0 ? sig + 1 : sig;
+			sival = ((i + 1) % 2) == 0 ? 0 : sival + 1;
+		}
+		test_failed(test_name, "incorrect order\n");
+	}
+
+	free(seqp);
+	return (0);
+}
+
+static void
+rt_delivery_defer_test(void)
+{
+	const char *test_name = __func__;
+	test_start(test_name, "verify delivery order of pending RT signals\n");
+	(void) rt_delivery(test_name, 0);
+	test_passed(test_name);
+}
+
+static void
+rt_delivery_nodefer_test(void)
+{
+	const char *test_name = __func__;
+	test_start(test_name,
+	    "verify delivery order of pending RT signals w/ SA_NODEFER\n");
+	(void) rt_delivery(test_name, 1);
+	test_passed(test_name);
+}
+
+static void
+run_tests(void)
+{
+	rt_delivery_defer_test();
+	rt_delivery_nodefer_test();
+}
+
+/* ARGSUSED */
+int
+main(int argc, char *argv[])
+{
+	run_tests();
+	return (EXIT_SUCCESS);
+}
