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
27 /* This test tests for an XSI feature */
28
29 #include <pthread.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <semaphore.h>
36 #include <signal.h>
37 #include <errno.h>
38 #include <posixtest.h>
39
40 /*
41 * Define an array of signals we want to test against.
42 * Add more if desired.
43 */
44
45 struct sig_info {
46 int sig;
47 char *sig_name;
48 char caught;
49 };
50
51 static struct sig_info sigs[] = {
52 {SIGHUP, "SIGHUP", 0},
53 {SIGINT, "SIGINT", 0},
54 {SIGQUIT, "SIGQUIT", 0},
55 {SIGILL, "SIGILL", 0},
56 {SIGTRAP, "SIGTRAP", 0},
57 {SIGABRT, "SIGABRT", 0},
58 {SIGBUS, "SIGBUS", 0},
59 {SIGFPE, "SIGFPE", 0},
60 {SIGUSR1, "SIGUSR1", 0},
61 {SIGSEGV, "SIGSEGV", 0},
62 {SIGUSR2, "SIGUSR2", 0},
63 {SIGPIPE, "SIGPIPE", 0},
64 {SIGALRM, "SIGALRM", 0},
65 {SIGTERM, "SIGTERM", 0},
66 #ifdef SIGSTKFLT
67 {SIGSTKFLT, "SIGSTKFLT", 0},
68 #endif
69 {SIGCHLD, "SIGCHLD", 0},
70 {SIGCONT, "SIGCONT", 0},
71 {SIGTSTP, "SIGTSTP", 0},
72 {SIGTTIN, "SIGTTIN", 0},
73 {SIGTTOU, "SIGTTOU", 0},
74 {SIGURG, "SIGURG", 0},
75 {SIGXCPU, "SIGXCPU", 0},
76 {SIGXFSZ, "SIGXFSZ", 0},
77 {SIGVTALRM, "SIGVTALRM", 0},
78 {SIGPROF, "SIGPROF", 0},
79 {SIGWINCH, "SIGWINCH", 0},
80 {SIGPOLL, "SIGPOLL", 0},
81 {-1, NULL, 0} /* add real time sigs? */
82 };
83
84 static volatile int ready;
85 static sem_t sem;
86
87 /* Lookup */
lookup(int signo)88 static struct sig_info *lookup(int signo)
89 {
90 struct sig_info *s = &sigs[0];
91
92 while (s->sig > 0) {
93 if (s->sig == signo)
94 return s;
95 s++;
96 }
97 return NULL;
98 }
99
100 /* Handler function */
handler(int signo)101 static void handler(int signo)
102 {
103 struct sig_info *s;
104
105 s = lookup(signo);
106 if (s)
107 s->caught = 1;
108 }
109
110 /* Thread function */
threaded(void * arg)111 static void *threaded(void *arg)
112 {
113 int rc;
114 int status = PTS_PASS;
115 struct sched_param sp = { 10 };
116 struct sig_info *s = arg;
117
118 /*
119 * Move into SCHED_FIFO to help ensure we are waiting in
120 * sem_wait when the signal is delivered
121 */
122 rc = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp);
123 if (rc) {
124 printf("Failed: pthread_setschedparam(SCHED_FIFO), root?\n");
125
126 if (rc == EPERM)
127 exit(PTS_UNTESTED);
128 else
129 exit(PTS_UNRESOLVED);
130 }
131
132 ready = 1;
133
134 rc = sem_wait(&sem);
135 if (rc) {
136 status = PTS_UNRESOLVED;
137 printf("Failed: sem_wait(): errno: %s signal: %s\n",
138 strerror(errno), s->sig_name);
139 if (errno == EINTR)
140 status = PTS_FAIL;
141 }
142
143 return (void *)((long)status);
144 }
145
test_sig(struct sig_info * s)146 static int test_sig(struct sig_info *s)
147 {
148 int rc;
149 int status = PTS_UNRESOLVED;
150 pthread_t child;
151 char *label;
152 void *thread_status;
153
154 label = "sem_init()";
155 rc = sem_init(&sem, 0, 0);
156 if (rc)
157 goto done;
158
159 /* reset flag */
160 ready = 0;
161
162 label = "pthread_create()";
163 errno = pthread_create(&child, NULL, threaded, s);
164 if (errno)
165 goto done;
166
167 /*
168 * sync on the ready flag. Since the child is running in
169 * SCHED_FIFO, it likely will continue running and wind up in
170 * sem_wait() prior to this thread sending a signal.
171 *
172 * Do one more yield for good luck.
173 */
174 while (!ready)
175 sched_yield();
176 sched_yield();
177
178 label = "pthread_kill()";
179 errno = pthread_kill(child, s->sig);
180 if (errno)
181 goto done;
182
183 while (!s->caught)
184 sched_yield();
185
186 label = "sem_post()";
187 rc = sem_post(&sem);
188 if (rc)
189 goto done;
190
191 label = "pthread_join()";
192 errno = pthread_join(child, &thread_status);
193 if (errno)
194 goto done;
195
196 sem_destroy(&sem);
197
198 status = ((long)thread_status) & 0xFFFFFFFF;
199
200 return status;
201
202 done:
203 printf("Failed: func: %s, rc: %d errno: %s signal: %s\n",
204 label, rc, strerror(errno), s->sig_name);
205 return status;
206 }
207
main(void)208 int main(void)
209 {
210 int rc = 0;
211 struct sig_info *s = &sigs[0];
212 struct sigaction sa;
213 struct sigaction sa_org;
214
215 sa.sa_flags = SA_RESTART;
216 sa.sa_handler = handler;
217
218 while (s->sig > 0) {
219 sigemptyset(&sa.sa_mask);
220 rc = sigaction(s->sig, &sa, &sa_org);
221 if (rc)
222 goto done;
223
224 rc = test_sig(s);
225 if (rc != PTS_PASS)
226 break;
227
228 sigaction(s->sig, &sa_org, NULL);
229 s++;
230 }
231
232 if (rc == PTS_PASS)
233 printf("Test PASSED\n");
234
235 return rc;
236
237 done:
238 printf("Failed: sigaction(): errno: %s, signal: %s\n",
239 strerror(errno), s->sig_name);
240 return PTS_FAIL;
241 }
242