1 /* 2 * Copyright (c) 2011, Novell Inc. All rights reserved. 3 * Author: Peter W. Morreale <pmorreale (at) novell.com> 4 * 5 * Based on a similar original program written by Sebastien Decugis 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of version 2 of the GNU General Public License as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it would be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * This sample test aims to check the following assertions: 20 * 21 * If SA_RESTART is set in sa_flags, interruptible function interrupted 22 * by signal shall restart silently. 23 * 24 */ 25 26 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 27 #define _POSIX_C_SOURCE 200112L 28 29 /* This test tests for an XSI feature */ 30 #define _XOPEN_SOURCE 600 31 32 #include <pthread.h> 33 #include <stdarg.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 #include <semaphore.h> 39 #include <signal.h> 40 #include <errno.h> 41 #include <posixtest.h> 42 43 /* 44 * Define an array of signals we want to test against. 45 * Add more if desired. 46 */ 47 48 struct sig_info { 49 int sig; 50 char *sig_name; 51 char caught; 52 }; 53 54 static struct sig_info sigs[] = { 55 {SIGHUP, "SIGHUP", 0}, 56 {SIGINT, "SIGINT", 0}, 57 {SIGQUIT, "SIGQUIT", 0}, 58 {SIGILL, "SIGILL", 0}, 59 {SIGTRAP, "SIGTRAP", 0}, 60 {SIGABRT, "SIGABRT", 0}, 61 {SIGBUS, "SIGBUS", 0}, 62 {SIGFPE, "SIGFPE", 0}, 63 {SIGUSR1, "SIGUSR1", 0}, 64 {SIGSEGV, "SIGSEGV", 0}, 65 {SIGUSR2, "SIGUSR2", 0}, 66 {SIGPIPE, "SIGPIPE", 0}, 67 {SIGALRM, "SIGALRM", 0}, 68 {SIGTERM, "SIGTERM", 0}, 69 #ifdef SIGSTKFLT 70 {SIGSTKFLT, "SIGSTKFLT", 0}, 71 #endif 72 {SIGCHLD, "SIGCHLD", 0}, 73 {SIGCONT, "SIGCONT", 0}, 74 {SIGTSTP, "SIGTSTP", 0}, 75 {SIGTTIN, "SIGTTIN", 0}, 76 {SIGTTOU, "SIGTTOU", 0}, 77 {SIGURG, "SIGURG", 0}, 78 {SIGXCPU, "SIGXCPU", 0}, 79 {SIGXFSZ, "SIGXFSZ", 0}, 80 {SIGVTALRM, "SIGVTALRM", 0}, 81 {SIGPROF, "SIGPROF", 0}, 82 {SIGWINCH, "SIGWINCH", 0}, 83 {SIGPOLL, "SIGPOLL", 0}, 84 {-1, NULL, 0} /* add real time sigs? */ 85 }; 86 87 static volatile int ready; 88 static sem_t sem; 89 90 /* Lookup */ 91 struct sig_info *lookup(int signo) 92 { 93 struct sig_info *s = &sigs[0]; 94 95 while (s->sig > 0) { 96 if (s->sig == signo) 97 return s; 98 s++; 99 } 100 return NULL; 101 } 102 103 /* Handler function */ 104 void handler(int signo) 105 { 106 struct sig_info *s; 107 108 s = lookup(signo); 109 if (s) 110 s->caught = 1; 111 } 112 113 /* Thread function */ 114 void *threaded(void *arg) 115 { 116 int rc; 117 int status = PTS_PASS; 118 struct sched_param sp = { 10 }; 119 struct sig_info *s = arg; 120 121 /* 122 * Move into SCHED_FIFO to help ensure we are waiting in 123 * sem_wait when the signal is delivered 124 */ 125 rc = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp); 126 if (rc) { 127 printf("Failed: pthread_setschedparam(SCHED_FIFO), root?\n"); 128 129 if (rc == EPERM) 130 exit(PTS_UNTESTED); 131 else 132 exit(PTS_UNRESOLVED); 133 } 134 135 ready = 1; 136 137 rc = sem_wait(&sem); 138 if (rc) { 139 status = PTS_UNRESOLVED; 140 printf("Failed: sem_wait(): errno: %s signal: %s\n", 141 strerror(errno), s->sig_name); 142 if (errno == EINTR) 143 status = PTS_FAIL; 144 } 145 146 return (void *)((long)status); 147 } 148 149 int test_sig(struct sig_info *s) 150 { 151 int rc; 152 int status = PTS_UNRESOLVED; 153 pthread_t child; 154 char *label; 155 void *thread_status; 156 157 label = "sem_init()"; 158 rc = sem_init(&sem, 0, 0); 159 if (rc) 160 goto done; 161 162 /* reset flag */ 163 ready = 0; 164 165 label = "pthread_create()"; 166 errno = pthread_create(&child, NULL, threaded, s); 167 if (errno) 168 goto done; 169 170 /* 171 * sync on the ready flag. Since the child is running in 172 * SCHED_FIFO, it likely will continue running and wind up in 173 * sem_wait() prior to this thread sending a signal. 174 * 175 * Do one more yield for good luck. 176 */ 177 while (!ready) 178 sched_yield(); 179 sched_yield(); 180 181 label = "pthread_kill()"; 182 errno = pthread_kill(child, s->sig); 183 if (errno) 184 goto done; 185 186 while (!s->caught) 187 sched_yield(); 188 189 label = "sem_post()"; 190 rc = sem_post(&sem); 191 if (rc) 192 goto done; 193 194 label = "pthread_join()"; 195 errno = pthread_join(child, &thread_status); 196 if (errno) 197 goto done; 198 199 sem_destroy(&sem); 200 201 status = ((long)thread_status) & 0xFFFFFFFF; 202 203 return status; 204 205 done: 206 printf("Failed: func: %s, rc: %d errno: %s signal: %s\n", 207 label, rc, strerror(errno), s->sig_name); 208 return status; 209 } 210 211 int main(void) 212 { 213 int rc = 0; 214 struct sig_info *s = &sigs[0]; 215 struct sigaction sa; 216 struct sigaction sa_org; 217 218 sa.sa_flags = SA_RESTART; 219 sa.sa_handler = handler; 220 221 while (s->sig > 0) { 222 sigemptyset(&sa.sa_mask); 223 rc = sigaction(s->sig, &sa, &sa_org); 224 if (rc) 225 goto done; 226 227 rc = test_sig(s); 228 if (rc != PTS_PASS) 229 break; 230 231 sigaction(s->sig, &sa_org, NULL); 232 s++; 233 } 234 235 if (rc == PTS_PASS) 236 printf("Test PASSED\n"); 237 238 return rc; 239 240 done: 241 printf("Failed: sigaction(): errno: %s, signal: %s\n", 242 strerror(errno), s->sig_name); 243 return PTS_FAIL; 244 } 245