From nobody  Wed Jun 24 00:03:36 1998
Received: (from nobody@localhost)
          by hub.freebsd.org (8.8.8/8.8.8) id AAA19621;
          Wed, 24 Jun 1998 00:03:36 -0700 (PDT)
          (envelope-from nobody)
Message-Id: <199806240703.AAA19621@hub.freebsd.org>
Date: Wed, 24 Jun 1998 00:03:36 -0700 (PDT)
From: cts@internetcds.com
To: freebsd-gnats-submit@freebsd.org
Subject: sigwait doesn't init the return value.
X-Send-Pr-Version: www-1.0

>Number:         7039
>Category:       misc
>Synopsis:       sigwait doesn't init the return value.
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    jb
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jun 24 00:10:01 PDT 1998
>Closed-Date:    Tue Aug 25 05:22:51 PDT 1998
>Last-Modified:  Tue Aug 25 05:25:09 PDT 1998
>Originator:     Craig Spannring
>Release:        2.2.6 and 3.0
>Organization:
InternetCDS
>Environment:
FreeBSD backmaster.cdsnet.net 3.0-CURRENT FreeBSD 3.0-CURRENT #2: Tue May  5 20:30:34 PDT 1998     root@backmaster.cdsnet.net:/n/FreeBSD/3.0-back2/src/sys/compile/BACK2  i386

FreeBSD bangkok.office.cdsnet.net 2.2.6-STABLE FreeBSD 2.2.6-STABLE #1: Tue Apr\
 28 16:38:57 PDT 1998     root@bangkok.office.cdsnet.net:/usr/src/sys/compile/B\
ANGKOK  i386

>Description:
As you can see from the source code below the uthread_sigwait function
never assigns a value to 'ret'.



int
sigwait(const sigset_t * set, int *sig)
{
        int ret;
        int status;
        sigset_t oset;

        /* Block signals: */
        _thread_kern_sig_block(&status);

        /* 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__);

        /* Block signals again: */
        _thread_kern_sig_block(NULL);

        /* Return the signal number to the caller: */
        *sig = _thread_run->signo;

        /* Restore the signal mask: */
        _thread_run->sigmask = oset;

        /* Unblock signals: */
        _thread_kern_sig_unblock(status);

        /* Return the completion status: */
        return (ret);
}

>How-To-Repeat:

>Fix:
I don't have a copy of the posix standard
so I don't know what the proper return value
should be.

Sorry.
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->jb 
Responsible-Changed-By: phk 
Responsible-Changed-When: Wed Jun 24 00:44:49 PDT 1998 
Responsible-Changed-Why:  
-> mr threads 

From: "Daniel M. Eischen" <eischen@vigrid.com>
To: freebsd-gnats-submit@freebsd.org, cts@internetcds.com
Cc: jb@freebsd.org
Subject: Re: misc/7039: sigwait doesn't init the return value.
Date: Mon, 24 Aug 1998 12:18:38 -0400

 This is a multi-part message in MIME format.
 
 --------------446B9B3D2781E494167EB0E7
 Content-Type: text/plain; charset=us-ascii
 Content-Transfer-Encoding: 7bit
 
 I've got a patch to libc_r that implements sigwait.  This
 fixes this PR and should also partially fix PR kern/7586
 (the reported MySQL pthread problem).
 
 I just this MySQL bug report, and it looks like sigsuspend
 can be fixed in a similar fashion as sigwait.  I can take
 a crack at it if needed.
 
 Please note the comments in the patch.  I don't have the
 POSIX spec, but what information I do have (from Solaris
 2.5 sigwait functionality/manpage and Programming with
 POSIX threads), indicates that sigwait should work for
 signals that do not have signal handlers installed (SIG_DFL).
 
 The patch also places the burden of installing and uninstalling
 signal handlers for SIG_DFL signals in the waiting mask.  It
 might be a better idea to install a dummy handler at init
 time, and then if there are no threads in sigwait/sigsuspend
 at the time of the signal, the dummy handler could uninstall
 the handler and resignal the process.  This would also force
 the threads implementation to be knowledgeable about what the
 default action for each signal is.  IOW, it shouldn't propagate
 the signal to the process if the default action for a signal
 is to discard it.
 
 Dan Eischen
 eischen@vigrid.com
 
 --------------446B9B3D2781E494167EB0E7
 Content-Type: text/plain; charset=us-ascii; name="libc_r.diff"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline; filename="libc_r.diff"
 
 *** uthread/uthread_kill.c.orig	Sun Jun 21 23:09:20 1998
 --- uthread/uthread_kill.c	Fri Aug 21 11:28:29 1998
 ***************
 *** 47,55 ****
   		ret = EINVAL;
   
   	/* Find the thread in the list of active threads: */
 ! 	else if ((ret = _find_thread(pthread)) == 0)
 ! 		/* Increment the pending signal count: */
 ! 		sigaddset(&pthread->sigpend,sig);
   
   	/* Return the completion status: */
   	return (ret);
 --- 47,64 ----
   		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: */
   	return (ret);
 *** uthread/uthread_sig.c.orig	Tue Jun 30 21:52:11 1998
 --- uthread/uthread_sig.c	Mon Aug 24 11:29:35 1998
 ***************
 *** 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->sigmask, 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)
   			/*
 ***************
 *** 259,264 ****
 --- 284,290 ----
   	case PS_RUNNING:
   	case PS_STATE_MAX:
   	case PS_SIGTHREAD:
 + 	case PS_SIGWAIT:
   	case PS_SUSPENDED:
   		/* Nothing to do here. */
   		break;
 ***************
 *** 290,296 ****
   	case PS_FDR_WAIT:
   	case PS_FDW_WAIT:
   	case PS_SLEEP_WAIT:
 - 	case PS_SIGWAIT:
   	case PS_SELECT_WAIT:
   		if (sig != SIGCHLD ||
   		    _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
 --- 316,321 ----
 *** uthread/uthread_sigwait.c.orig	Sun Jun 21 23:09:24 1998
 --- uthread/uthread_sigwait.c	Sun Aug 23 20:46:55 1998
 ***************
 *** 39,62 ****
   int
   sigwait(const sigset_t * set, int *sig)
   {
 ! 	int ret;
 ! 	int status;
 ! 	sigset_t oset;
   
 ! 	/* 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__);
   
 ! 	/* Return the signal number to the caller: */
 ! 	*sig = _thread_run->signo;
   
 ! 	/* Restore the signal mask: */
 ! 	_thread_run->sigmask = oset;
   
   	/* Return the completion status: */
   	return (ret);
 --- 39,110 ----
   int
   sigwait(const sigset_t * set, int *sig)
   {
 ! 	int		ret = 0;
 ! 	int		i;
 ! 	sigset_t	oset;
 ! 	struct sigaction act;
 ! 	
 ! 	/*
 ! 	 * Specify the thread kernel signal handler.
 ! 	 */
 ! 	act.sa_handler = (void (*) ()) _thread_sig_handler;
 ! 	act.sa_flags = SA_RESTART;
 ! 	act.sa_mask = *set;
   
 ! 	/*
 ! 	 * These signals can't be waited on.
 ! 	 */
 ! 	sigdelset(&act.sa_mask, SIGKILL);
 ! 	sigdelset(&act.sa_mask, SIGSTOP);
 ! 	sigdelset(&act.sa_mask, SIGVTALRM);
 ! 	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__);
 ! 
 ! 		/* Return the signal number to the caller: */
 ! 		*sig = _thread_run->signo;
 ! 
 ! 		/* Restore the signal mask: */
 ! 		_thread_run->sigmask = oset;
 ! 	}
 ! 
 ! 	/* Restore the sigactions: */
 ! 	act.sa_handler = SIG_DFL;
 ! 	for (i = 1; i < NSIG; i++) {
 ! 		if (sigismember(&act.sa_mask, i) &&
 ! 		    (_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
 ! 			if (_thread_sys_sigaction(i,&act,NULL) != 0)
 ! 				ret = -1;
 ! 		}
 ! 	}
   
   	/* Return the completion status: */
   	return (ret);
 
 --------------446B9B3D2781E494167EB0E7
 Content-Type: text/plain; charset=us-ascii; name="sigtest1.c"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline; filename="sigtest1.c"
 
 #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;
 
 /* Why isn't this in pthread.h??? */
 extern int sigwait (sigset_t *, int *);
 
 static void *
 sigwaiter (void *arg)
 {
 	int signo;
 
 	while (sigcounts[SIGINT] == 0) {
 		if (sigwait (&wait_mask, &signo) != 0) {
 			printf ("Unable to wait for signal, errno %d\n",
 				errno);
 			exit (1);
 		}
 		sigcounts[signo]++;
 		printf ("Sigwait caught signal %d\n", signo);
 	}
 
 	pthread_exit (arg);
 	return (NULL);
 }
 
 
 static void
 sighandler (int signo)
 {
 	printf ("Signal handler caught signal %d\n", signo);
 
 	if ((signo >= 0) && (signo <= NSIG))
 		sigcounts[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;
 	pthread_t	tid;
 	void *		exit_status;
 	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, 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 */
 	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);
 
 	/*
 	 * 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 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)
 		printf ("FAIL: sigwait 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 sigwait.
 	 */
 	send_thread_signal (tid, SIGURG);
 	sleep (1);
 	send_process_signal (SIGURG);
 	sleep (1);
 	if (sigcounts[SIGURG] != 2)
 		printf ("FAIL: sigwait doesn't wake up for SIGURG.\n");
 
 	/*
 	 * Verify that a signal with a default action that terminates
 	 * the process will release a sigwait.
 	 */
 	send_thread_signal (tid, SIGUSR1);
 	sleep (1);
 	send_process_signal (SIGUSR1);
 	sleep (1);
 	if (sigcounts[SIGUSR1] != 2)
 		printf ("FAIL: sigwait doesn't wake up 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 (tid, &exit_status);
 
 	return (0);
 }
 
 --------------446B9B3D2781E494167EB0E7--
 

From: "Daniel M. Eischen" <eischen@vigrid.com>
To: freebsd-gnats-submit@freebsd.org
Cc: jb@freebsd.org
Subject: Re: misc/7039: sigwait doesn't init the return value.
Date: Mon, 24 Aug 1998 19:10:08 -0400

 I should always proof read my mail before sending it.
 
 > I just this MySQL bug report, and it looks like sigsuspend
         ^ noticed
 > can be fixed in a similar fashion as sigwait.  I can take
 > a crack at it if needed.
 
 > The patch also places the burden of installing and uninstalling
 > signal handlers for SIG_DFL signals in the waiting mask.  It
                            sigwaiting thread ^^^^^^^^^^^^^
 
 Dan Eischen
 eischen@vigrid.com
State-Changed-From-To: open->closed 
State-Changed-By: jb 
State-Changed-When: Tue Aug 25 05:22:51 PDT 1998 
State-Changed-Why:  
Patches committed, thanks. 
>Unformatted:
