diff options
author | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2001-08-15 14:37:17 +0000 |
---|---|---|
committer | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2001-08-15 14:37:17 +0000 |
commit | ee29ce09990030fd5a7c6f78dde0dabfab952171 (patch) | |
tree | dc17f6ce9d5ba480f50f3c02569aa0737499684c /regress/lib/libpthread/sigwait | |
parent | 344dc84d0dc63d3256aca03797112a766d32f738 (diff) |
Regression tests for libc_r (pthreads) library.
Thanks to pval@ for resolving the license stuff.
Diffstat (limited to 'regress/lib/libpthread/sigwait')
-rw-r--r-- | regress/lib/libpthread/sigwait/Makefile | 6 | ||||
-rw-r--r-- | regress/lib/libpthread/sigwait/sigwait.c | 264 |
2 files changed, 270 insertions, 0 deletions
diff --git a/regress/lib/libpthread/sigwait/Makefile b/regress/lib/libpthread/sigwait/Makefile new file mode 100644 index 00000000000..52117d781b0 --- /dev/null +++ b/regress/lib/libpthread/sigwait/Makefile @@ -0,0 +1,6 @@ +# $OpenBSD: Makefile,v 1.1 2001/08/15 14:37:13 fgsch Exp $ + +PROG= sigwait +SRCS= sigwait.c + +.include <bsd.prog.mk> diff --git a/regress/lib/libpthread/sigwait/sigwait.c b/regress/lib/libpthread/sigwait/sigwait.c new file mode 100644 index 00000000000..a166eaf2a1e --- /dev/null +++ b/regress/lib/libpthread/sigwait/sigwait.c @@ -0,0 +1,264 @@ +/* $OpenBSD: sigwait.c,v 1.1 2001/08/15 14:37:16 fgsch Exp $ */ +/* + * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Daniel M. Eischen. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#include <stdlib.h> +#include <unistd.h> + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> + +#include <pthread_np.h> +#include "test.h" + +static int sigcounts[NSIG + 1]; +static sigset_t wait_mask; +static pthread_mutex_t waiter_mutex; + + +static void * +sigwaiter (void *arg) +{ + int signo; + sigset_t mask; + + SET_NAME("sigwaiter"); + + /* Block SIGHUP */ + sigemptyset (&mask); + sigaddset (&mask, SIGHUP); + CHECKe(sigprocmask (SIG_BLOCK, &mask, NULL)); + + while (sigcounts[SIGINT] == 0) { + printf("Sigwait waiting (thread %p)\n", pthread_self()); + CHECKe(sigwait (&wait_mask, &signo)); + sigcounts[signo]++; + printf ("Sigwait caught signal %d (%s)\n", signo, + strsignal(signo)); + + /* Allow the main thread to prevent the sigwait. */ + CHECKr(pthread_mutex_lock (&waiter_mutex)); + CHECKr(pthread_mutex_unlock (&waiter_mutex)); + } + + return (arg); +} + + +static void +sighandler (int signo) +{ + printf (" -> Signal handler caught signal %d (%s) in thread %p\n", + signo, strsignal(signo), pthread_self()); + + if ((signo >= 0) && (signo <= NSIG)) + sigcounts[signo]++; +} + +int main (int argc, char *argv[]) +{ + pthread_mutexattr_t mattr; + pthread_attr_t pattr; + pthread_t tid; + struct sigaction act; + + /* Initialize our signal counts. */ + memset ((void *) sigcounts, 0, NSIG * sizeof (int)); + + /* Setupt our wait mask. */ + sigemptyset (&wait_mask); /* Default action */ + sigaddset (&wait_mask, SIGHUP); /* terminate */ + sigaddset (&wait_mask, SIGINT); /* terminate */ + sigaddset (&wait_mask, SIGQUIT); /* create core image */ + sigaddset (&wait_mask, SIGURG); /* ignore */ + sigaddset (&wait_mask, SIGIO); /* ignore */ + sigaddset (&wait_mask, SIGUSR1); /* terminate */ + + /* Ignore signals SIGHUP and SIGIO. */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGHUP); + sigaddset (&act.sa_mask, SIGIO); + act.sa_handler = SIG_IGN; + act.sa_flags = 0; + CHECKe(sigaction (SIGHUP, &act, NULL)); + CHECKe(sigaction (SIGIO, &act, NULL)); + + /* Install a signal handler for SIGURG */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGURG); + act.sa_handler = sighandler; + act.sa_flags = SA_RESTART; + CHECKe(sigaction (SIGURG, &act, NULL)); + + /* Install a signal handler for SIGXCPU */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGXCPU); + CHECKe(sigaction (SIGXCPU, &act, NULL)); + + /* + * Initialize the thread attribute. + */ + CHECKr(pthread_attr_init (&pattr)); + CHECKr(pthread_attr_setdetachstate (&pattr, PTHREAD_CREATE_JOINABLE)); + + /* + * Initialize and create a mutex. + */ + CHECKr(pthread_mutexattr_init (&mattr)); + CHECKr(pthread_mutex_init (&waiter_mutex, &mattr)); + + /* + * Create the sigwaiter thread. + */ + CHECKr(pthread_create (&tid, &pattr, sigwaiter, NULL)); + + /* + * Verify that an ignored signal doesn't cause a wakeup. + * We don't have a handler installed for SIGIO. + */ + CHECKr(pthread_kill (tid, SIGIO)); + sleep (1); + CHECKe(kill(getpid(), SIGIO)); + sleep (1); + /* sigwait should not wake up for ignored signal SIGIO */ + ASSERT(sigcounts[SIGIO] == 0); + + /* + * Verify that a signal with a default action of ignore, for + * which we have a signal handler installed, will release a sigwait. + */ + CHECKr(pthread_kill (tid, SIGURG)); + sleep (1); + CHECKe(kill(getpid(), SIGURG)); + sleep (1); + /* sigwait should wake up for SIGURG */ + ASSERT(sigcounts[SIGURG] == 2); + + /* + * Verify that a signal with a default action that terminates + * the process will release a sigwait. + */ + CHECKr(pthread_kill (tid, SIGUSR1)); + sleep (1); + CHECKe(kill(getpid(), SIGUSR1)); + sleep (1); + if (sigcounts[SIGUSR1] != 2) + printf ("FAIL: sigwait doesn't wake up for SIGUSR1.\n"); + + /* + * Verify that if we install a signal handler for a previously + * ignored signal, an occurrence of this signal will release + * the (already waiting) sigwait. + */ + + /* Install a signal handler for SIGHUP. */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGHUP); + act.sa_handler = sighandler; + act.sa_flags = SA_RESTART; + CHECKe(sigaction (SIGHUP, &act, NULL)); + + /* Sending SIGHUP should release the sigwait. */ + CHECKe(kill(getpid(), SIGHUP)); + sleep (1); + CHECKr(pthread_kill (tid, SIGHUP)); + sleep (1); + /* sigwait should wake up for SIGHUP */ + ASSERT(sigcounts[SIGHUP] == 2); + + /* + * Verify that a pending signal in the waiters mask will + * cause sigwait to return the pending signal. We do this + * by taking the waiters mutex and signaling the waiter to + * release him from the sigwait. The waiter will block + * on taking the mutex, and we can then send the waiter a + * signal which should be added to his pending signals. + * The next time the waiter does a sigwait, he should + * return with the pending signal. + */ + sigcounts[SIGHUP] = 0; + CHECKr(pthread_mutex_lock (&waiter_mutex)); + /* Release the waiter from sigwait. */ + CHECKe(kill(getpid(), SIGHUP)); + sleep (1); + /* sigwait should wake up for SIGHUP */ + ASSERT(sigcounts[SIGHUP] == 1); + /* + * Add SIGHUP to all threads pending signals. Since there is + * a signal handler installed for SIGHUP and this signal is + * blocked from the waiter thread and unblocked in the main + * thread, the signal handler should be called once for SIGHUP. + */ + CHECKe(kill(getpid(), SIGHUP)); + /* Release the waiter thread and allow him to run. */ + CHECKr(pthread_mutex_unlock (&waiter_mutex)); + sleep (1); + /* sigwait should return for pending SIGHUP */ + ASSERT(sigcounts[SIGHUP] == 3); + + /* + * Repeat the above test using pthread_kill and SIGUSR1 + */ + sigcounts[SIGUSR1] = 0; + CHECKr(pthread_mutex_lock (&waiter_mutex)); + /* Release the waiter from sigwait. */ + CHECKr(pthread_kill (tid, SIGUSR1)); + sleep (1); + /* sigwait should wake up for SIGUSR1 */ + ASSERT(sigcounts[SIGUSR1] == 1); + /* Add SIGHUP to the waiters pending signals. */ + CHECKr(pthread_kill (tid, SIGUSR1)); + /* Release the waiter thread and allow him to run. */ + CHECKe(pthread_mutex_unlock (&waiter_mutex)); + sleep (1); + /* sigwait should return for pending SIGUSR1 */ + ASSERT(sigcounts[SIGUSR1] == 2); + +#if 0 + /* + * Verify that we can still kill the process for a signal + * not being waited on by sigwait. + */ + CHECKe(kill(getpid(), SIGPIPE)); + PANIC("SIGPIPE did not terminate process"); + + /* + * Wait for the thread to finish. + */ + CHECKr(pthread_join (tid, NULL)); +#endif + + SUCCEED; +} |