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 }