• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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