2 * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Daniel M. Eischen.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS''
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 #include <pthread_np.h>
47 static int sigcounts[NSIG + 1];
48 static sigset_t wait_mask;
49 static pthread_mutex_t waiter_mutex;
60 sigaddset (&mask, SIGHUP);
61 sigprocmask (SIG_BLOCK, &mask, NULL);
63 while (sigcounts[SIGINT] == 0) {
64 if (sigwait (&wait_mask, &signo) != 0) {
66 "Unable to wait for signal, errno %d\n",
71 fprintf (stderr, "Sigwait caught signal %d\n", signo);
73 /* Allow the main thread to prevent the sigwait. */
74 pthread_mutex_lock (&waiter_mutex);
75 pthread_mutex_unlock (&waiter_mutex);
84 sighandler (int signo)
86 fprintf (stderr, " -> Signal handler caught signal %d\n", signo);
88 if ((signo >= 0) && (signo <= NSIG))
93 send_thread_signal (pthread_t tid, int signo)
95 if (pthread_kill (tid, signo) != 0) {
96 fprintf (stderr, "Unable to send thread signal, errno %d.\n",
103 send_process_signal (int signo)
105 if (kill (getpid (), signo) != 0) {
106 fprintf (stderr, "Unable to send process signal, errno %d.\n",
113 int main (int argc, char *argv[])
115 pthread_mutexattr_t mattr;
116 pthread_attr_t pattr;
119 struct sigaction act;
121 /* Initialize our signal counts. */
122 memset ((void *) sigcounts, 0, NSIG * sizeof (int));
124 /* Setup our wait mask. */
125 sigemptyset (&wait_mask); /* Default action */
126 sigaddset (&wait_mask, SIGHUP); /* terminate */
127 sigaddset (&wait_mask, SIGINT); /* terminate */
128 sigaddset (&wait_mask, SIGQUIT); /* create core image */
129 sigaddset (&wait_mask, SIGURG); /* ignore */
130 sigaddset (&wait_mask, SIGIO); /* ignore */
131 sigaddset (&wait_mask, SIGUSR1); /* terminate */
133 /* Ignore signals SIGHUP and SIGIO. */
134 sigemptyset (&act.sa_mask);
135 sigaddset (&act.sa_mask, SIGHUP);
136 sigaddset (&act.sa_mask, SIGIO);
137 act.sa_handler = SIG_IGN;
139 sigaction (SIGHUP, &act, NULL);
140 sigaction (SIGIO, &act, NULL);
142 /* Install a signal handler for SIGURG */
143 sigemptyset (&act.sa_mask);
144 sigaddset (&act.sa_mask, SIGURG);
145 act.sa_handler = sighandler;
146 act.sa_flags = SA_RESTART;
147 sigaction (SIGURG, &act, NULL);
149 /* Install a signal handler for SIGXCPU */
150 sigemptyset (&act.sa_mask);
151 sigaddset (&act.sa_mask, SIGXCPU);
152 sigaction (SIGXCPU, &act, NULL);
155 * Initialize the thread attribute.
157 if ((pthread_attr_init (&pattr) != 0) ||
158 (pthread_attr_setdetachstate (&pattr,
159 PTHREAD_CREATE_JOINABLE) != 0)) {
160 fprintf (stderr, "Unable to initialize thread attributes.\n");
165 * Initialize and create a mutex.
167 if ((pthread_mutexattr_init (&mattr) != 0) ||
168 (pthread_mutex_init (&waiter_mutex, &mattr) != 0)) {
169 fprintf (stderr, "Unable to create waiter mutex.\n");
174 * Create the sigwaiter thread.
176 if (pthread_create (&tid, &pattr, sigwaiter, NULL) != 0) {
177 fprintf (stderr, "Unable to create thread.\n");
180 #if defined(_LIBC_R_)
181 pthread_set_name_np (tid, "sigwaiter");
185 * Verify that an ignored signal doesn't cause a wakeup.
186 * We don't have a handler installed for SIGIO.
188 send_thread_signal (tid, SIGIO);
190 send_process_signal (SIGIO);
192 if (sigcounts[SIGIO] != 0)
194 "FAIL: sigwait wakes up for ignored signal SIGIO.\n");
197 * Verify that a signal with a default action of ignore, for
198 * which we have a signal handler installed, will release a sigwait.
200 send_thread_signal (tid, SIGURG);
202 send_process_signal (SIGURG);
204 if (sigcounts[SIGURG] != 2)
205 fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGURG.\n");
208 * Verify that a signal with a default action that terminates
209 * the process will release a sigwait.
211 send_thread_signal (tid, SIGUSR1);
213 send_process_signal (SIGUSR1);
215 if (sigcounts[SIGUSR1] != 2)
217 "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
220 * Verify that if we install a signal handler for a previously
221 * ignored signal, an occurrence of this signal will release
222 * the (already waiting) sigwait.
225 /* Install a signal handler for SIGHUP. */
226 sigemptyset (&act.sa_mask);
227 sigaddset (&act.sa_mask, SIGHUP);
228 act.sa_handler = sighandler;
229 act.sa_flags = SA_RESTART;
230 sigaction (SIGHUP, &act, NULL);
232 /* Sending SIGHUP should release the sigwait. */
233 send_process_signal (SIGHUP);
235 send_thread_signal (tid, SIGHUP);
237 if (sigcounts[SIGHUP] != 2)
238 fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
241 * Verify that a pending signal in the waiters mask will
242 * cause sigwait to return the pending signal. We do this
243 * by taking the waiters mutex and signaling the waiter to
244 * release him from the sigwait. The waiter will block
245 * on taking the mutex, and we can then send the waiter a
246 * signal which should be added to his pending signals.
247 * The next time the waiter does a sigwait, he should
248 * return with the pending signal.
250 sigcounts[SIGHUP] = 0;
251 pthread_mutex_lock (&waiter_mutex);
252 /* Release the waiter from sigwait. */
253 send_process_signal (SIGHUP);
255 if (sigcounts[SIGHUP] != 1)
256 fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
258 * Add SIGHUP to the process pending signals. Since there is
259 * a signal handler installed for SIGHUP and this signal is
260 * blocked from the waiter thread and unblocked in the main
261 * thread, the signal handler should be called once for SIGHUP.
263 send_process_signal (SIGHUP);
264 /* Release the waiter thread and allow him to run. */
265 pthread_mutex_unlock (&waiter_mutex);
267 if (sigcounts[SIGHUP] != 2)
269 "FAIL: sigwait doesn't return for pending SIGHUP.\n");
272 * Repeat the above test using pthread_kill and SIGUSR1.
274 sigcounts[SIGUSR1] = 0;
275 pthread_mutex_lock (&waiter_mutex);
276 /* Release the waiter from sigwait. */
277 send_thread_signal (tid, SIGUSR1);
279 if (sigcounts[SIGUSR1] != 1)
281 "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
282 /* Add SIGUSR1 to the waiters pending signals. */
283 send_thread_signal (tid, SIGUSR1);
284 /* Release the waiter thread and allow him to run. */
285 pthread_mutex_unlock (&waiter_mutex);
287 if (sigcounts[SIGUSR1] != 2)
289 "FAIL: sigwait doesn't return for pending SIGUSR1.\n");
292 * Verify that we can still kill the process for a signal
293 * not being waited on by sigwait.
295 send_process_signal (SIGPIPE);
296 fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n");
299 * Wait for the thread to finish.
301 pthread_join (tid, &exit_status);