--- /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);
+}
