1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 *
11 * Copyright 2014 Ryan Zezeski. All rights reserved.
12 */
13 #include <signal.h>
14 #include <stdarg.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #include <unistd.h>
20
21 /*
22 * The `seq` struct and `sh` handler are used to record the order in which
23 * the signals are delivered to the parent process. When a signal is
24 * delivered the handler records it in seq and then increments the index.
25 */
26 struct seq {
27 int sig, num;
28 };
29
30 static struct seq *seqp;
31
32 /* ARGSUSED */
33 void
34 sh(int sig, siginfo_t *info, void *unused)
35 {
36 static int i;
37 seqp[i].num = info->si_value.sival_int;
38 seqp[i++].sig = sig;
39 }
40
41 static void
42 test_start(const char *test_name, const char *format, ...)
43 {
44 va_list args;
45
46 (void) printf("TEST STARTING %s: ", test_name);
47
48 va_start(args, format);
49 (void) vprintf(format, args);
50 va_end(args);
51 (void) fflush(stdout);
52 }
53
54 static void
55 test_failed(const char *test_name, const char *format, ...)
56 {
57 va_list args;
58
59 (void) printf("TEST FAILED %s: ", test_name);
60
61 va_start(args, format);
62 (void) vprintf(format, args);
63 va_end(args);
64
65 (void) exit(-1);
66 }
67
68 static void
69 test_passed(const char *test_name)
70 {
71 (void) printf("TEST PASS: %s\n", test_name);
72 (void) fflush(stdout);
73 }
74
75 /*
76 * Verify the delivery order of realtime (RT) signals. RT signals were
77 * introduced in POSIX.1b and differ from regular signals in several key
78 * ways:
79 *
80 * 1. Multiple instances of the same signal are queued and must be
81 * delivered in FIFO order.
82 *
83 * 2. If multiple different RT signals are pending then the lower numbered
84 * RT signals are delivered first. I.e., RT signals have a notion of
85 * priority.
86 *
87 * See sections 2.4.2 (Realtime Signal Generation and Delivery) and B.2.4
88 * of the POSIX.1-2008 standard for more information.
89 */
90 static int
91 rt_delivery(const char *test_name, int no_defer)
92 {
93 int i, j, sig, sival, sigend, numsig, rc, fail = 0;
94 pid_t p = getpid(), chld;
95 struct sigaction sa;
96 sigset_t ss, ssold;
97 union sigval sv;
98
99 /*
100 * Range of signals to send. Each signal is sent 2 times to verify FIFO
101 * order.
102 */
103 sigend = SIGRTMIN + (sysconf(_SC_SIGQUEUE_MAX) / 2);
104 sigend = sigend > SIGRTMAX ? SIGRTMAX : sigend;
105 numsig = (sigend - SIGRTMIN) * 2;
106
107 seqp = malloc(sizeof (struct seq) * numsig);
108
109 /*
110 * Step 1:
111 *
112 * Install the signal handler (sh) on this process (the parent).
113 */
114 (void) sigemptyset(&ss);
115 for (i = SIGRTMIN; i < sigend; i++) {
116 sa.sa_sigaction = sh;
117 sa.sa_flags = SA_SIGINFO;
118 sa.sa_flags |= (no_defer ? SA_NODEFER : 0);
119 (void) sigemptyset(&sa.sa_mask);
120 sigaction(i, &sa, NULL);
121 (void) sigaddset(&ss, i);
122 }
123
124 /*
125 * Step 2:
126 *
127 * Block all signals that are about to be sent to this process.
128 * This is needed to make sure all signals are pending at once.
129 * This is related to step 4.
130 */
131 (void) sigprocmask(SIG_BLOCK, &ss, &ssold);
132
133 /*
134 * Step 3:
135 *
136 * Fork a child process to send each RT signal 2 times to the
137 * parent process. Remember, all signals being sent are RT
138 * signals and thus are subject to explicit ordering guarantees
139 * spelled out in POSIX.1b. Lower numbered RT signals are
140 * _always_ delivered before higher RT signals.
141 */
142 if ((chld = fork()) == 0) {
143 for (i = SIGRTMIN; i < sigend; i++) {
144 for (j = 0; j < 2; j++) {
145 sv.sival_int = j;
146 if (sigqueue(p, i, sv) == -1) {
147 perror("problem generating signal");
148 exit(1);
149 }
150 }
151 }
152 exit(0);
153 }
154
155 /*
156 * Step 4:
157 *
158 * Wait for forked process to finish sending all signals. This is
159 * to make sure that all signals are pending before allowing the
160 * kernel to deliver them to the handler. If you don't both wait
161 * and block then the handler will process the signals as they
162 * come in and thus we will not be testing the ordering
163 * guarentees. Related to step 2.
164 */
165 if (wait(&rc) != chld) {
166 test_failed(test_name, "failed to wait for child\n");
167 }
168
169 if (rc != 0) {
170 test_failed(test_name, "child exited non-zero\n");
171 }
172 (void) sigprocmask(SIG_SETMASK, &ssold, NULL);
173
174 /*
175 * Step 5:
176 *
177 * Verify that multiple pending RT signals are delivered in
178 * correct priority (lower signals first), and that multiple
179 * instances of the same RT signal are delivered in FIFO order.
180 *
181 * E.g. if SIGRTMIN is 42 then the handler should record this
182 * ordering:
183 *
184 * {42, 0}, {42, 1}, {42, 2}, {43, 0}, {43, 1}, {43, 2}, ...
185 */
186 sig = SIGRTMIN;
187 sival = 0;
188 for (i = 0; i < numsig; i++) {
189 if ((seqp[i].sig != sig) || seqp[i].num != sival) {
190 fail = 1;
191 }
192 sig = ((i + 1) % 2) == 0 ? sig + 1 : sig;
193 sival = ((i + 1) % 2) == 0 ? 0 : sival + 1;
194 }
195
196 if (fail) {
197 sig = SIGRTMIN;
198 sival = 0;
199 (void) fprintf(stderr, "Excpted Actual\n");
200 for (i = 0; i < numsig; i++) {
201 (void) fprintf(stderr, "{%2d,%d} {%2d,%d}\n",
202 sig, sival, seqp[i].sig, seqp[i].num);
203
204 sig = ((i + 1) % 2) == 0 ? sig + 1 : sig;
205 sival = ((i + 1) % 2) == 0 ? 0 : sival + 1;
206 }
207 test_failed(test_name, "incorrect order\n");
208 }
209
210 free(seqp);
211 return (0);
212 }
213
214 static void
215 rt_delivery_defer_test(void)
216 {
217 const char *test_name = __func__;
218 test_start(test_name, "verify delivery order of pending RT signals\n");
219 (void) rt_delivery(test_name, 0);
220 test_passed(test_name);
221 }
222
223 static void
224 rt_delivery_nodefer_test(void)
225 {
226 const char *test_name = __func__;
227 test_start(test_name,
228 "verify delivery order of pending RT signals w/ SA_NODEFER\n");
229 (void) rt_delivery(test_name, 1);
230 test_passed(test_name);
231 }
232
233 static void
234 run_tests(void)
235 {
236 rt_delivery_defer_test();
237 rt_delivery_nodefer_test();
238 }
239
240 /* ARGSUSED */
241 int
242 main(int argc, char *argv[])
243 {
244 run_tests();
245 return (EXIT_SUCCESS);
246 }