Skip site navigation (1)Skip section navigation (2)
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>