Date: Sun, 30 Aug 1998 18:50:02 -0700 (PDT) From: "Daniel M. Eischen" <eischen@vigrid.com> To: freebsd-bugs@FreeBSD.ORG Subject: Re: kern/7586: [PATCH] Threads bug in libc_r preventing MySQL from shutting down Message-ID: <199808310150.SAA06643@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/7586; it has been noted by GNATS. From: "Daniel M. Eischen" <eischen@vigrid.com> To: freebsd-gnats-submit@freebsd.org, nik@iii.co.uk Cc: jb@freebsd.org Subject: Re: kern/7586: [PATCH] Threads bug in libc_r preventing MySQL from shutting down Date: Sun, 30 Aug 1998 17:41:26 -0400 This is a multi-part message in MIME format. --------------446B9B3D2781E494167EB0E7 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Here is a fix for the sigsuspend and sigwait problems. Sigsuspend and sigwait cannot use the same "waiting" mask. In the case of sigwait, the "waiting" mask is independent of the threads mask. I attach patches to the most recent threads library, and to test/sigwait to cover more test cases. I also include a separate program for testing sigsuspend. I guess the idea is to put these test cases in libc_r/test/. This should fix the reported MySQL shutdown problem. Someone should test this as I don't have MySQL installed. Dan Eischen eischen@vigrid.com --------------446B9B3D2781E494167EB0E7 Content-Type: text/plain; charset=us-ascii; name="uthread.diffs" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="uthread.diffs" Common subdirectories: ../uthread.orig/CVS and ./CVS diff -c ../uthread.orig/pthread_private.h ./pthread_private.h *** ../uthread.orig/pthread_private.h Tue Jun 9 19:02:43 1998 --- ./pthread_private.h Sat Aug 29 19:51:30 1998 *************** *** 240,245 **** --- 240,246 ---- PS_SELECT_WAIT, PS_SLEEP_WAIT, PS_WAIT_WAIT, + PS_SIGSUSPEND, PS_SIGWAIT, PS_JOIN, PS_SUSPENDED, diff -c ../uthread.orig/uthread_kill.c ./uthread_kill.c *** ../uthread.orig/uthread_kill.c Tue Aug 25 07:19:14 1998 --- ./uthread_kill.c Sat Aug 29 19:33:30 1998 *************** *** 46,63 **** /* Invalid signal: */ ret = EINVAL; /* Find the thread in the list of active threads: */ else if ((ret = _find_thread(pthread)) == 0) { ! if ((pthread->state == PS_SIGWAIT) && ! sigismember(&pthread->sigmask, sig)) { ! /* Change the state of the thread to run: */ ! PTHREAD_NEW_STATE(pthread,PS_RUNNING); ! /* Return the signal number: */ ! pthread->signo = sig; ! } else /* Increment the pending signal count: */ sigaddset(&pthread->sigpend,sig); } /* Return the completion status: */ --- 46,96 ---- /* Invalid signal: */ ret = EINVAL; + /* Ignored signals get dropped on the floor. */ + else if (_thread_sigact[sig - 1].sa_handler == SIG_IGN) + ret = 0; + /* Find the thread in the list of active threads: */ else if ((ret = _find_thread(pthread)) == 0) { ! switch (pthread->state) { ! case PS_SIGSUSPEND: ! /* ! * Only wake up the thread if the signal is unblocked ! * and there is a handler installed for the signal. ! */ ! if (!sigismember(&pthread->sigmask, sig) && ! _thread_sigact[sig - 1].sa_handler != SIG_DFL) { ! /* Change the state of the thread to run: */ ! PTHREAD_NEW_STATE(pthread,PS_RUNNING); ! ! /* Return the signal number: */ ! pthread->signo = sig; ! } ! /* Increment the pending signal count: */ ! sigaddset(&pthread->sigpend,sig); ! break; ! ! case PS_SIGWAIT: ! /* Wake up the thread if the signal is blocked. */ ! if (sigismember(pthread->data.sigwait, sig)) { ! /* Change the state of the thread to run: */ ! PTHREAD_NEW_STATE(pthread,PS_RUNNING); ! ! /* Return the signal number: */ ! pthread->signo = sig; ! } ! else ! /* ! * Increment the pending signal count. ! */ ! sigaddset(&pthread->sigpend,sig); ! break; ! default: /* Increment the pending signal count: */ sigaddset(&pthread->sigpend,sig); + break; + } } /* Return the completion status: */ diff -c ../uthread.orig/uthread_sig.c ./uthread_sig.c *** ../uthread.orig/uthread_sig.c Wed Aug 26 16:50:42 1998 --- ./uthread_sig.c Sat Aug 29 19:37:19 1998 *************** *** 199,205 **** /* * POSIX says that pending SIGCONT signals are ! * discarded when one of there signals occurs. */ if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) { /* --- 199,205 ---- /* * POSIX says that pending SIGCONT signals are ! * discarded when one of these signals occurs. */ if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) { /* *************** *** 212,217 **** --- 212,242 ---- sigdelset(&pthread->sigpend,SIGCONT); } + /* + * Enter a loop to process each thread in the linked + * list that is sigwait-ing on a signal. Since POSIX + * doesn't specify which thread will get the signal + * if there are multiple waiters, we'll give it to the + * first one we find. + */ + for (pthread = _thread_link_list; pthread != NULL; + pthread = pthread->nxt) { + if ((pthread->state == PS_SIGWAIT) && + sigismember(pthread->data.sigwait, sig)) { + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + + /* + * Do not attempt to deliver this signal + * to other threads. + */ + return; + } + } + /* Check if the signal is not being ignored: */ if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) /* *************** *** 258,263 **** --- 283,289 ---- case PS_MUTEX_WAIT: case PS_RUNNING: case PS_STATE_MAX: + case PS_SIGWAIT: case PS_SIGTHREAD: case PS_SUSPENDED: /* Nothing to do here. */ *************** *** 283,288 **** --- 309,328 ---- pthread->signo = sig; break; + case PS_SIGSUSPEND: + /* + * Only wake up the thread if the signal is unblocked + * and there is a handler installed for the signal. + */ + if (!sigismember(&pthread->sigmask, sig) && + _thread_sigact[sig - 1].sa_handler != SIG_DFL) { + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } + break; /* * States that are interrupted by the occurrence of a signal * other than the scheduling alarm: *************** *** 291,297 **** case PS_FDW_WAIT: case PS_SLEEP_WAIT: case PS_SELECT_WAIT: - case PS_SIGWAIT: if (sig != SIGCHLD || _thread_sigact[sig - 1].sa_handler != SIG_DFL) { /* Flag the operation as interrupted: */ --- 331,336 ---- diff -c ../uthread.orig/uthread_sigsuspend.c ./uthread_sigsuspend.c *** ../uthread.orig/uthread_sigsuspend.c Wed Apr 29 05:59:24 1998 --- ./uthread_sigsuspend.c Sat Aug 29 19:43:22 1998 *************** *** 44,57 **** /* Check if a new signal set was provided by the caller: */ if (set != NULL) { ! /* Save the current sigmal mask: */ oset = _thread_run->sigmask; ! /* Combine the caller's mask with the current one: */ ! _thread_run->sigmask |= *set; /* Wait for a signal: */ ! _thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__); /* Always return an interrupted error: */ errno = EINTR; --- 44,57 ---- /* Check if a new signal set was provided by the caller: */ if (set != NULL) { ! /* Save the current signal mask: */ oset = _thread_run->sigmask; ! /* Change the caller's mask: */ ! _thread_run->sigmask = *set; /* Wait for a signal: */ ! _thread_kern_sched_state(PS_SIGSUSPEND, __FILE__, __LINE__); /* Always return an interrupted error: */ errno = EINTR; diff -c ../uthread.orig/uthread_sigwait.c ./uthread_sigwait.c *** ../uthread.orig/uthread_sigwait.c Tue Aug 25 07:19:14 1998 --- ./uthread_sigwait.c Sun Aug 30 21:00:04 1998 *************** *** 41,47 **** { int ret = 0; int i; ! sigset_t oset; struct sigaction act; /* --- 41,47 ---- { int ret = 0; int i; ! sigset_t tempset; struct sigaction act; /* *************** *** 60,90 **** sigdelset(&act.sa_mask, SIGCHLD); sigdelset(&act.sa_mask, SIGINFO); /* * Enter a loop to find the signals that are SIG_DFL. For * these signals we must install a dummy signal handler in * order for the kernel to pass them in to us. POSIX says * that the application must explicitly install a dummy * handler for signals that are SIG_IGN in order to sigwait ! * on them, so we ignore SIG_IGN signals. */ for (i = 1; i < NSIG; i++) { if (sigismember(&act.sa_mask, i)) { ! if (_thread_sigact[i - 1].sa_handler == SIG_DFL) { if (_thread_sys_sigaction(i,&act,NULL) != 0) ret = -1; - } - else if (_thread_sigact[i - 1].sa_handler == SIG_IGN) - sigdelset(&act.sa_mask, i); } } - if (ret == 0) { ! /* Save the current signal mask: */ ! oset = _thread_run->sigmask; ! /* Combine the caller's mask with the current one: */ ! _thread_run->sigmask |= act.sa_mask; /* Wait for a signal: */ _thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__); --- 60,108 ---- sigdelset(&act.sa_mask, SIGCHLD); sigdelset(&act.sa_mask, SIGINFO); + /* Check to see if a pending signal is in the wait mask. */ + if (tempset = (_thread_run->sigpend & act.sa_mask)) { + /* Enter a loop to find a pending signal: */ + for (i = 1; i < NSIG; i++) { + if (sigismember (&tempset, i)) + break; + } + + /* Clear the pending signal: */ + sigdelset(&_thread_run->sigpend,i); + + /* Return the signal number to the caller: */ + *sig = i; + + return (0); + } + /* * Enter a loop to find the signals that are SIG_DFL. For * these signals we must install a dummy signal handler in * order for the kernel to pass them in to us. POSIX says * that the application must explicitly install a dummy * handler for signals that are SIG_IGN in order to sigwait ! * on them. Note that SIG_IGN signals are left in the ! * mask because a subsequent sigaction could enable an ! * ignored signal. */ for (i = 1; i < NSIG; i++) { if (sigismember(&act.sa_mask, i)) { ! if (_thread_sigact[i - 1].sa_handler == SIG_DFL) if (_thread_sys_sigaction(i,&act,NULL) != 0) ret = -1; } } ! if (ret == 0) { ! /* ! * Save the wait signal mask. The wait signal ! * mask is independent of the threads signal mask ! * and requires separate storage. ! */ ! _thread_run->data.sigwait = &act.sa_mask; /* Wait for a signal: */ _thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__); *************** *** 92,99 **** /* Return the signal number to the caller: */ *sig = _thread_run->signo; ! /* Restore the signal mask: */ ! _thread_run->sigmask = oset; } /* Restore the sigactions: */ --- 110,120 ---- /* Return the signal number to the caller: */ *sig = _thread_run->signo; ! /* ! * Probably unnecessary, but since it's in a union struct ! * we don't know how it could be used in the future. ! */ ! _thread_run->data.sigwait = NULL; } /* Restore the sigactions: */ --------------446B9B3D2781E494167EB0E7 Content-Type: text/plain; charset=us-ascii; name="sigwait.diffs" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="sigwait.diffs" *** sigwait.c.orig Tue Aug 25 08:35:16 1998 --- sigwait.c Sun Aug 30 22:08:29 1998 *************** *** 12,24 **** * 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 John Birrell. * 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 JOHN BIRRELL 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 --- 12,24 ---- * 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 *************** *** 31,51 **** * */ #include <stdlib.h> - #include <stdio.h> #include <unistd.h> #include <errno.h> #include <pthread.h> #include <signal.h> #include <string.h> ! static int sigcounts[NSIG + 1]; ! static sigset_t wait_mask; static void * sigwaiter (void *arg) { int signo; while (sigcounts[SIGINT] == 0) { if (sigwait (&wait_mask, &signo) != 0) { --- 31,63 ---- * */ #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <pthread.h> #include <signal.h> + #include <stdio.h> #include <string.h> ! #if defined(__FreeBSD__) ! #include <pthread_np.h> ! #endif ! ! 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; + + /* Block SIGHUP */ + sigemptyset (&mask); + sigaddset (&mask, SIGHUP); + sigprocmask (SIG_BLOCK, &mask, NULL); while (sigcounts[SIGINT] == 0) { if (sigwait (&wait_mask, &signo) != 0) { *************** *** 55,60 **** --- 67,76 ---- } sigcounts[signo]++; printf ("Sigwait caught signal %d\n", signo); + + /* Allow the main thread to prevent the sigwait. */ + pthread_mutex_lock (&waiter_mutex); + pthread_mutex_unlock (&waiter_mutex); } pthread_exit (arg); *************** *** 65,71 **** static void sighandler (int signo) { ! printf ("Signal handler caught signal %d\n", signo); if ((signo >= 0) && (signo <= NSIG)) sigcounts[signo]++; --- 81,87 ---- static void sighandler (int signo) { ! printf (" -> Signal handler caught signal %d\n", signo); if ((signo >= 0) && (signo <= NSIG)) sigcounts[signo]++; *************** *** 92,97 **** --- 108,114 ---- int main (int argc, char *argv[]) { + pthread_mutexattr_t mattr; pthread_attr_t pattr; pthread_t tid; void * exit_status; *************** *** 102,119 **** /* Setupt our wait mask. */ sigemptyset (&wait_mask); /* Default action */ - sigaddset (&wait_mask, SIGINT); /* terminate */ sigaddset (&wait_mask, SIGHUP); /* terminate */ sigaddset (&wait_mask, SIGQUIT); /* create core image */ sigaddset (&wait_mask, SIGURG); /* ignore */ sigaddset (&wait_mask, SIGIO); /* ignore */ sigaddset (&wait_mask, SIGUSR1); /* terminate */ ! /* Ignore signal SIGIO. */ sigemptyset (&act.sa_mask); sigaddset (&act.sa_mask, SIGIO); act.sa_handler = SIG_IGN; act.sa_flags = 0; sigaction (SIGIO, &act, NULL); /* Install a signal handler for SIGURG */ --- 119,138 ---- /* 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; + sigaction (SIGHUP, &act, NULL); sigaction (SIGIO, &act, NULL); /* Install a signal handler for SIGURG */ *************** *** 139,159 **** } /* * Create the sigwaiter thread. */ if (pthread_create (&tid, &pattr, sigwaiter, NULL) != 0) { ! printf ("Unable to create thread, errno %d.\n", errno); exit (1); } /* * Verify that an ignored signal doesn't cause a wakeup. * We don't have a handler installed for SIGIO. */ - printf ("Sending pthread_kill SIGIO.\n"); send_thread_signal (tid, SIGIO); sleep (1); - printf ("Sending kill SIGIO.\n"); send_process_signal (SIGIO); sleep (1); if (sigcounts[SIGIO] != 0) --- 158,188 ---- } /* + * Initialize and create a mutex. + */ + if ((pthread_mutexattr_init (&mattr) != 0) || + (pthread_mutex_init (&waiter_mutex, &mattr) != 0)) { + printf ("Unable to create waiter mutex.\n"); + exit (1); + } + + /* * Create the sigwaiter thread. */ if (pthread_create (&tid, &pattr, sigwaiter, NULL) != 0) { ! printf ("Unable to create thread.\n"); exit (1); } + #if defined(__FreeBSD__) + pthread_set_name_np (tid, "sigwaiter"); + #endif /* * Verify that an ignored signal doesn't cause a wakeup. * We don't have a handler installed for SIGIO. */ send_thread_signal (tid, SIGIO); sleep (1); send_process_signal (SIGIO); sleep (1); if (sigcounts[SIGIO] != 0) *************** *** 180,185 **** --- 209,283 ---- 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; + sigaction (SIGHUP, &act, NULL); + + /* Sending SIGHUP should release the sigwait. */ + send_process_signal (SIGHUP); + sleep (1); + send_thread_signal (tid, SIGHUP); + sleep (1); + if (sigcounts[SIGHUP] != 2) + printf ("FAIL: sigwait doesn't wake up for SIGHUP.\n"); + + /* + * 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; + pthread_mutex_lock (&waiter_mutex); + /* Release the waiter from sigwait. */ + send_process_signal (SIGHUP); + sleep (1); + if (sigcounts[SIGHUP] != 1) + printf ("FAIL: sigwait doesn't wake up for SIGHUP.\n"); + /* + * 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. + */ + send_process_signal (SIGHUP); + /* Release the waiter thread and allow him to run. */ + pthread_mutex_unlock (&waiter_mutex); + sleep (1); + if (sigcounts[SIGHUP] != 3) + printf ("FAIL: sigwait doesn't return for pending SIGHUP.\n"); + + /* + * Repeat the above test using pthread_kill and SIGUSR1 + */ + sigcounts[SIGUSR1] = 0; + pthread_mutex_lock (&waiter_mutex); + /* Release the waiter from sigwait. */ + send_thread_signal (tid, SIGUSR1); + sleep (1); + if (sigcounts[SIGUSR1] != 1) + printf ("FAIL: sigwait doesn't wake up for SIGUSR1.\n"); + /* Add SIGHUP to the waiters pending signals. */ + send_thread_signal (tid, SIGUSR1); + /* Release the waiter thread and allow him to run. */ + pthread_mutex_unlock (&waiter_mutex); + sleep (1); + if (sigcounts[SIGUSR1] != 2) + printf ("FAIL: sigwait doesn't return for pending SIGUSR1.\n"); /* * Verify that we can still kill the process for a signal --------------446B9B3D2781E494167EB0E7 Content-Type: text/plain; charset=us-ascii; name="sigsuspend.c" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="sigsuspend.c" /* * 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> #if defined(__FreeBSD__) #include <pthread_np.h> #endif static int sigcounts[NSIG + 1]; static int sigfifo[NSIG + 1]; static int fifo_depth = 0; static sigset_t suspender_mask; static pthread_t suspender_tid; static void * sigsuspender (void *arg) { int save_count, status, i; sigset_t run_mask; /* Run with all signals blocked. */ sigfillset (&run_mask); sigprocmask (SIG_SETMASK, &run_mask, NULL); /* Allow these signals to wake us up during a sigsuspend. */ sigfillset (&suspender_mask); /* Default action */ sigdelset (&suspender_mask, SIGINT); /* terminate */ sigdelset (&suspender_mask, SIGHUP); /* terminate */ sigdelset (&suspender_mask, SIGQUIT); /* create core image */ sigdelset (&suspender_mask, SIGURG); /* ignore */ sigdelset (&suspender_mask, SIGIO); /* ignore */ sigdelset (&suspender_mask, SIGUSR2); /* terminate */ while (sigcounts[SIGINT] == 0) { save_count = sigcounts[SIGUSR2]; status = sigsuspend (&suspender_mask); if ((status == 0) || (errno != EINTR)) { printf ("Unable to suspend for signals, " "errno %d, return value %d\n", errno, status); exit (1); } for (i = 0; i < fifo_depth; i++) printf ("Sigsuspend woke up by signal %d\n", sigfifo[i]); fifo_depth = 0; } pthread_exit (arg); return (NULL); } static void sighandler (int signo) { sigset_t set; pthread_t self; if ((signo >= 0) && (signo <= NSIG)) sigcounts[signo]++; /* * If we are running on behalf of the suspender thread, * ensure that we have the correct mask set. */ self = pthread_self (); if (self == suspender_tid) { sigfifo[fifo_depth] = signo; fifo_depth++; printf (" -> Suspender thread signal handler caught signal %d\n", signo); sigprocmask (SIG_SETMASK, NULL, &set); if (set != suspender_mask) printf (" >>> FAIL: sigsuspender signal handler running " "with incorrect mask.\n"); } else printf (" -> Main thread signal handler caught signal %d\n", signo); } static void send_thread_signal (pthread_t tid, int signo) { if (pthread_kill (tid, signo) != 0) { printf ("Unable to send thread signal, errno %d.\n", errno); exit (1); } } static void send_process_signal (int signo) { if (kill (getpid (), signo) != 0) { printf ("Unable to send process signal, errno %d.\n", errno); exit (1); } } int main (int argc, char *argv[]) { pthread_attr_t pattr; void * exit_status; struct sigaction act; sigset_t oldset; sigset_t newset; /* Initialize our signal counts. */ memset ((void *) sigcounts, 0, NSIG * sizeof (int)); /* Ignore signal SIGIO. */ sigemptyset (&act.sa_mask); sigaddset (&act.sa_mask, SIGIO); act.sa_handler = SIG_IGN; act.sa_flags = 0; 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; sigaction (SIGURG, &act, NULL); /* Install a signal handler for SIGXCPU */ sigemptyset (&act.sa_mask); sigaddset (&act.sa_mask, SIGXCPU); sigaction (SIGXCPU, &act, NULL); /* Get our current signal mask. */ sigprocmask (SIG_SETMASK, NULL, &oldset); /* Mask out SIGUSR1 and SIGUSR2. */ newset = oldset; sigaddset (&newset, SIGUSR1); sigaddset (&newset, SIGUSR2); sigprocmask (SIG_SETMASK, &newset, NULL); /* Install a signal handler for SIGUSR1 and SIGUSR2 */ sigemptyset (&act.sa_mask); sigaddset (&act.sa_mask, SIGUSR1); sigaddset (&act.sa_mask, SIGUSR2); act.sa_handler = sighandler; act.sa_flags = SA_RESTART; sigaction (SIGUSR1, &act, NULL); sigaction (SIGUSR2, &act, NULL); /* * Initialize the thread attribute. */ if ((pthread_attr_init (&pattr) != 0) || (pthread_attr_setdetachstate (&pattr, PTHREAD_CREATE_JOINABLE) != 0)) { printf ("Unable to initialize thread attributes.\n"); exit (1); } /* * Create the sigsuspender thread. */ if (pthread_create (&suspender_tid, &pattr, sigsuspender, NULL) != 0) { printf ("Unable to create thread, errno %d.\n", errno); exit (1); } #if defined(__FreeBSD__) pthread_set_name_np (suspender_tid, "sigsuspender"); #endif /* * Verify that an ignored signal doesn't cause a wakeup. * We don't have a handler installed for SIGIO. */ send_thread_signal (suspender_tid, SIGIO); sleep (1); send_process_signal (SIGIO); sleep (1); if (sigcounts[SIGIO] != 0) printf ("FAIL: sigsuspend wakes up for ignored signal " "SIGIO.\n"); /* * Verify that a signal with a default action of ignore, for * which we have a signal handler installed, will release a * sigsuspend. */ send_thread_signal (suspender_tid, SIGURG); sleep (1); send_process_signal (SIGURG); sleep (1); if (sigcounts[SIGURG] != 3) printf ("FAIL: sigsuspend doesn't wake up for SIGURG.\n"); /* * Verify that a SIGUSR2 signal will release a sigsuspended * thread. */ send_thread_signal (suspender_tid, SIGUSR2); sleep (1); send_process_signal (SIGUSR2); sleep (1); if (sigcounts[SIGUSR2] != 2) printf ("FAIL: sigsuspend doesn't wake up for SIGUSR2.\n"); /* * Verify that a signal, blocked in both the main and * sigsuspender threads, does not cause the signal handler * to be called. */ send_thread_signal (suspender_tid, SIGUSR1); sleep (1); send_process_signal (SIGUSR1); sleep (1); if (sigcounts[SIGUSR1] != 0) printf ("FAIL: signal hander called for SIGUSR1.\n"); /* * Verify that we can still kill the process for a signal * not being waited on by sigwait. */ send_process_signal (SIGPIPE); printf ("FAIL: SIGPIPE did not terminate process.\n"); /* * Wait for the thread to finish. */ pthread_join (suspender_tid, &exit_status); return (0); } --------------446B9B3D2781E494167EB0E7-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199808310150.SAA06643>