• 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 
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