1 /*
2 * Copyright (c) 2011, Novell Inc. All rights reserved.
3 * Author: Peter W. Morreale <pmorreale@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 */
lookup(int signo)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 */
handler(int signo)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 */
threaded(void * arg)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
test_sig(struct sig_info * s)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
main(void)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