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 }