159612Sjasone/*
259612Sjasone * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com>
359612Sjasone * All rights reserved.
459612Sjasone *
559612Sjasone * Redistribution and use in source and binary forms, with or without
659612Sjasone * modification, are permitted provided that the following conditions
759612Sjasone * are met:
859612Sjasone * 1. Redistributions of source code must retain the above copyright
959612Sjasone *    notice, this list of conditions and the following disclaimer.
1059612Sjasone * 2. Redistributions in binary form must reproduce the above copyright
1159612Sjasone *    notice, this list of conditions and the following disclaimer in the
1259612Sjasone *    documentation and/or other materials provided with the distribution.
1359612Sjasone * 3. All advertising materials mentioning features or use of this software
1459612Sjasone *    must display the following acknowledgement:
1559612Sjasone *	This product includes software developed by Daniel M. Eischen.
1659612Sjasone * 4. Neither the name of the author nor the names of any co-contributors
1759612Sjasone *    may be used to endorse or promote products derived from this software
1859612Sjasone *    without specific prior written permission.
1959612Sjasone *
2059612Sjasone * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS''
2159612Sjasone * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2259612Sjasone * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2359612Sjasone * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2459612Sjasone * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2559612Sjasone * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2659612Sjasone * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2759612Sjasone * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2859612Sjasone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2959612Sjasone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3059612Sjasone * SUCH DAMAGE.
3159612Sjasone *
3259612Sjasone * $FreeBSD$
3359612Sjasone */
3459612Sjasone#include <stdlib.h>
3559612Sjasone#include <unistd.h>
3659612Sjasone
3759612Sjasone#include <errno.h>
3859612Sjasone#include <pthread.h>
3959612Sjasone#include <signal.h>
4059612Sjasone#include <stdio.h>
4159612Sjasone#include <string.h>
4259612Sjasone
4359612Sjasone#if defined(_LIBC_R_)
4459612Sjasone#include <pthread_np.h>
4559612Sjasone#endif
4659612Sjasone
4759612Sjasonestatic int		sigcounts[NSIG + 1];
4859612Sjasonestatic sigset_t		wait_mask;
4959612Sjasonestatic pthread_mutex_t	waiter_mutex;
5059612Sjasone
5159612Sjasone
5259612Sjasonestatic void *
5359612Sjasonesigwaiter (void *arg)
5459612Sjasone{
5559612Sjasone	int signo;
5659612Sjasone	sigset_t mask;
5759612Sjasone
5859612Sjasone	/* Block SIGHUP */
5959612Sjasone	sigemptyset (&mask);
6059612Sjasone	sigaddset (&mask, SIGHUP);
6159612Sjasone	sigprocmask (SIG_BLOCK, &mask, NULL);
6259612Sjasone
6359612Sjasone	while (sigcounts[SIGINT] == 0) {
6459612Sjasone		if (sigwait (&wait_mask, &signo) != 0) {
6559612Sjasone			fprintf (stderr,
6659612Sjasone			    "Unable to wait for signal, errno %d\n",
6759612Sjasone			    errno);
6859612Sjasone			exit (1);
6959612Sjasone		}
7059612Sjasone		sigcounts[signo]++;
7159612Sjasone		fprintf (stderr, "Sigwait caught signal %d\n", signo);
7259612Sjasone
7359612Sjasone		/* Allow the main thread to prevent the sigwait. */
7459612Sjasone		pthread_mutex_lock (&waiter_mutex);
7559612Sjasone		pthread_mutex_unlock (&waiter_mutex);
7659612Sjasone	}
7759612Sjasone
7859612Sjasone	pthread_exit (arg);
7959612Sjasone	return (NULL);
8059612Sjasone}
8159612Sjasone
8259612Sjasone
8359612Sjasonestatic void
8459612Sjasonesighandler (int signo)
8559612Sjasone{
8659612Sjasone	fprintf (stderr, "  -> Signal handler caught signal %d\n", signo);
8759612Sjasone
8859612Sjasone	if ((signo >= 0) && (signo <= NSIG))
8959612Sjasone		sigcounts[signo]++;
9059612Sjasone}
9159612Sjasone
9259612Sjasonestatic void
9359612Sjasonesend_thread_signal (pthread_t tid, int signo)
9459612Sjasone{
9559612Sjasone	if (pthread_kill (tid, signo) != 0) {
9659612Sjasone		fprintf (stderr, "Unable to send thread signal, errno %d.\n",
9759612Sjasone		    errno);
9859612Sjasone		exit (1);
9959612Sjasone	}
10059612Sjasone}
10159612Sjasone
10259612Sjasonestatic void
10359612Sjasonesend_process_signal (int signo)
10459612Sjasone{
10559612Sjasone	if (kill (getpid (), signo) != 0) {
10659612Sjasone		fprintf (stderr, "Unable to send process signal, errno %d.\n",
10759612Sjasone		    errno);
10859612Sjasone		exit (1);
10959612Sjasone	}
11059612Sjasone}
11159612Sjasone
11259612Sjasone
11359612Sjasoneint main (int argc, char *argv[])
11459612Sjasone{
11559612Sjasone	pthread_mutexattr_t mattr;
11659612Sjasone	pthread_attr_t	pattr;
11759612Sjasone	pthread_t	tid;
11859612Sjasone	void *		exit_status;
11959612Sjasone	struct sigaction act;
12059612Sjasone
12159612Sjasone	/* Initialize our signal counts. */
12259612Sjasone	memset ((void *) sigcounts, 0, NSIG * sizeof (int));
12359612Sjasone
12459612Sjasone	/* Setup our wait mask. */
12559612Sjasone	sigemptyset (&wait_mask);		/* Default action	*/
12659612Sjasone	sigaddset (&wait_mask, SIGHUP);		/* terminate		*/
12759612Sjasone	sigaddset (&wait_mask, SIGINT);		/* terminate		*/
12859612Sjasone	sigaddset (&wait_mask, SIGQUIT);	/* create core image	*/
12959612Sjasone	sigaddset (&wait_mask, SIGURG);		/* ignore		*/
13059612Sjasone	sigaddset (&wait_mask, SIGIO);		/* ignore		*/
13159612Sjasone	sigaddset (&wait_mask, SIGUSR1);	/* terminate		*/
13259612Sjasone
13359612Sjasone	/* Ignore signals SIGHUP and SIGIO. */
13459612Sjasone	sigemptyset (&act.sa_mask);
13559612Sjasone	sigaddset (&act.sa_mask, SIGHUP);
13659612Sjasone	sigaddset (&act.sa_mask, SIGIO);
13759612Sjasone	act.sa_handler = SIG_IGN;
13859612Sjasone	act.sa_flags = 0;
13959612Sjasone	sigaction (SIGHUP, &act, NULL);
14059612Sjasone	sigaction (SIGIO, &act, NULL);
14159612Sjasone
14259612Sjasone	/* Install a signal handler for SIGURG */
14359612Sjasone	sigemptyset (&act.sa_mask);
14459612Sjasone	sigaddset (&act.sa_mask, SIGURG);
14559612Sjasone	act.sa_handler = sighandler;
14659612Sjasone	act.sa_flags = SA_RESTART;
14759612Sjasone	sigaction (SIGURG, &act, NULL);
14859612Sjasone
14959612Sjasone	/* Install a signal handler for SIGXCPU */
15059612Sjasone	sigemptyset (&act.sa_mask);
15159612Sjasone	sigaddset (&act.sa_mask, SIGXCPU);
15259612Sjasone	sigaction (SIGXCPU, &act, NULL);
15359612Sjasone
15459612Sjasone	/*
15559612Sjasone	 * Initialize the thread attribute.
15659612Sjasone	 */
15759612Sjasone	if ((pthread_attr_init (&pattr) != 0) ||
15859612Sjasone	    (pthread_attr_setdetachstate (&pattr,
15959612Sjasone	    PTHREAD_CREATE_JOINABLE) != 0)) {
16059612Sjasone		fprintf (stderr, "Unable to initialize thread attributes.\n");
16159612Sjasone		exit (1);
16259612Sjasone	}
16359612Sjasone
16459612Sjasone	/*
16559612Sjasone	 * Initialize and create a mutex.
16659612Sjasone	 */
16759612Sjasone	if ((pthread_mutexattr_init (&mattr) != 0) ||
16859612Sjasone	    (pthread_mutex_init (&waiter_mutex, &mattr) != 0)) {
16959612Sjasone		fprintf (stderr, "Unable to create waiter mutex.\n");
17059612Sjasone		exit (1);
17159612Sjasone	}
17259612Sjasone
17359612Sjasone	/*
17459612Sjasone	 * Create the sigwaiter thread.
17559612Sjasone	 */
17659612Sjasone	if (pthread_create (&tid, &pattr, sigwaiter, NULL) != 0) {
17759612Sjasone		fprintf (stderr, "Unable to create thread.\n");
17859612Sjasone		exit (1);
17959612Sjasone	}
18059612Sjasone#if defined(_LIBC_R_)
18159612Sjasone	pthread_set_name_np (tid, "sigwaiter");
18259612Sjasone#endif
18359612Sjasone
18459612Sjasone	/*
18559612Sjasone	 * Verify that an ignored signal doesn't cause a wakeup.
18659612Sjasone	 * We don't have a handler installed for SIGIO.
18759612Sjasone	 */
18859612Sjasone	send_thread_signal (tid, SIGIO);
18959612Sjasone	sleep (1);
19059612Sjasone	send_process_signal (SIGIO);
19159612Sjasone	sleep (1);
19259612Sjasone	if (sigcounts[SIGIO] != 0)
19359612Sjasone		fprintf (stderr,
19459612Sjasone		    "FAIL: sigwait wakes up for ignored signal SIGIO.\n");
19559612Sjasone
19659612Sjasone	/*
19759612Sjasone	 * Verify that a signal with a default action of ignore, for
19859612Sjasone	 * which we have a signal handler installed, will release a sigwait.
19959612Sjasone	 */
20059612Sjasone	send_thread_signal (tid, SIGURG);
20159612Sjasone	sleep (1);
20259612Sjasone	send_process_signal (SIGURG);
20359612Sjasone	sleep (1);
20459612Sjasone	if (sigcounts[SIGURG] != 2)
20559612Sjasone		fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGURG.\n");
20659612Sjasone
20759612Sjasone	/*
20859612Sjasone	 * Verify that a signal with a default action that terminates
20959612Sjasone	 * the process will release a sigwait.
21059612Sjasone	 */
21159612Sjasone	send_thread_signal (tid, SIGUSR1);
21259612Sjasone	sleep (1);
21359612Sjasone	send_process_signal (SIGUSR1);
21459612Sjasone	sleep (1);
21559612Sjasone	if (sigcounts[SIGUSR1] != 2)
21659612Sjasone		fprintf (stderr,
21759612Sjasone		    "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
21859612Sjasone
21959612Sjasone	/*
22059612Sjasone	 * Verify that if we install a signal handler for a previously
22159612Sjasone	 * ignored signal, an occurrence of this signal will release
22259612Sjasone	 * the (already waiting) sigwait.
22359612Sjasone	 */
22459612Sjasone
22559612Sjasone	/* Install a signal handler for SIGHUP. */
22659612Sjasone	sigemptyset (&act.sa_mask);
22759612Sjasone	sigaddset (&act.sa_mask, SIGHUP);
22859612Sjasone	act.sa_handler = sighandler;
22959612Sjasone	act.sa_flags = SA_RESTART;
23059612Sjasone	sigaction (SIGHUP, &act, NULL);
23159612Sjasone
23259612Sjasone	/* Sending SIGHUP should release the sigwait. */
23359612Sjasone	send_process_signal (SIGHUP);
23459612Sjasone	sleep (1);
23559612Sjasone	send_thread_signal (tid, SIGHUP);
23659612Sjasone	sleep (1);
23759612Sjasone	if (sigcounts[SIGHUP] != 2)
23859612Sjasone		fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
23959612Sjasone
24059612Sjasone	/*
24159612Sjasone	 * Verify that a pending signal in the waiters mask will
24259612Sjasone	 * cause sigwait to return the pending signal.  We do this
24359612Sjasone	 * by taking the waiters mutex and signaling the waiter to
24459612Sjasone	 * release him from the sigwait.  The waiter will block
24559612Sjasone	 * on taking the mutex, and we can then send the waiter a
24659612Sjasone	 * signal which should be added to his pending signals.
24759612Sjasone	 * The next time the waiter does a sigwait, he should
24859612Sjasone	 * return with the pending signal.
24959612Sjasone	 */
25059612Sjasone	sigcounts[SIGHUP] = 0;
25159612Sjasone 	pthread_mutex_lock (&waiter_mutex);
25259612Sjasone	/* Release the waiter from sigwait. */
25359612Sjasone	send_process_signal (SIGHUP);
25459612Sjasone	sleep (1);
25559612Sjasone	if (sigcounts[SIGHUP] != 1)
25659612Sjasone		fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
25759612Sjasone	/*
25859612Sjasone	 * Add SIGHUP to the process pending signals.  Since there is
25959612Sjasone	 * a signal handler installed for SIGHUP and this signal is
26059612Sjasone	 * blocked from the waiter thread and unblocked in the main
26159612Sjasone	 * thread, the signal handler should be called once for SIGHUP.
26259612Sjasone	 */
26359612Sjasone	send_process_signal (SIGHUP);
26459612Sjasone	/* Release the waiter thread and allow him to run. */
26559612Sjasone	pthread_mutex_unlock (&waiter_mutex);
26659612Sjasone	sleep (1);
26759612Sjasone	if (sigcounts[SIGHUP] != 2)
26859612Sjasone		fprintf (stderr,
26959612Sjasone		    "FAIL: sigwait doesn't return for pending SIGHUP.\n");
27059612Sjasone
27159612Sjasone	/*
27259612Sjasone	 * Repeat the above test using pthread_kill and SIGUSR1.
27359612Sjasone	 */
27459612Sjasone	sigcounts[SIGUSR1] = 0;
27559612Sjasone 	pthread_mutex_lock (&waiter_mutex);
27659612Sjasone	/* Release the waiter from sigwait. */
27759612Sjasone	send_thread_signal (tid, SIGUSR1);
27859612Sjasone	sleep (1);
27959612Sjasone	if (sigcounts[SIGUSR1] != 1)
28059612Sjasone		fprintf (stderr,
28159612Sjasone		    "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
28276910Sjasone	/* Add SIGUSR1 to the waiters pending signals. */
28359612Sjasone	send_thread_signal (tid, SIGUSR1);
28459612Sjasone	/* Release the waiter thread and allow him to run. */
28559612Sjasone	pthread_mutex_unlock (&waiter_mutex);
28659612Sjasone	sleep (1);
28759612Sjasone	if (sigcounts[SIGUSR1] != 2)
28859612Sjasone		fprintf (stderr,
28959612Sjasone		    "FAIL: sigwait doesn't return for pending SIGUSR1.\n");
29059612Sjasone
29159612Sjasone	/*
29259612Sjasone	 * Verify that we can still kill the process for a signal
29359612Sjasone	 * not being waited on by sigwait.
29459612Sjasone	 */
29559612Sjasone	send_process_signal (SIGPIPE);
29659612Sjasone	fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n");
29759612Sjasone
29859612Sjasone	/*
29959612Sjasone	 * Wait for the thread to finish.
30059612Sjasone	 */
30159612Sjasone	pthread_join (tid, &exit_status);
30259612Sjasone
30359612Sjasone	return (0);
30459612Sjasone}
305