From nik@iii.co.uk  Wed Aug 12 01:44:43 1998
Received: from tyree.iii.co.uk (tyree.iii.co.uk [195.89.149.230])
          by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id BAA21470
          for <FreeBSD-gnats-submit@freebsd.org>; Wed, 12 Aug 1998 01:44:42 -0700 (PDT)
          (envelope-from nik@iii.co.uk)
Received: from carrig.strand.iii.co.uk (carrig.strand.iii.co.uk [192.168.7.25])
	by tyree.iii.co.uk (8.8.8/8.8.8) with ESMTP id JAA00902
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 12 Aug 1998 09:44:17 +0100 (BST)
Received: (from nik@localhost)
	by carrig.strand.iii.co.uk (8.8.8/8.8.7) id JAA13453;
	Wed, 12 Aug 1998 09:43:33 +0100 (BST)
Message-Id: <199808120843.JAA13453@carrig.strand.iii.co.uk>
Date: Wed, 12 Aug 1998 09:43:33 +0100 (BST)
From: Nik Clayton <nik@iii.co.uk>
Reply-To: nik@iii.co.uk
To: FreeBSD-gnats-submit@freebsd.org
Subject: Threads bug in libc_r preventing MySQL from shutting down
X-Send-Pr-Version: 3.2

>Number:         7586
>Category:       kern
>Synopsis:       [PATCH] Threads bug in libc_r preventing MySQL from shutting down
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Aug 12 01:50:00 PDT 1998
>Closed-Date:    Fri Nov 6 15:18:04 PST 1998
>Last-Modified:  Fri Nov  6 15:18:27 PST 1998
>Originator:     Nik Clayton
>Release:        FreeBSD 2.2.6-STABLE i386
>Organization:
Dazed and confused
>Environment:

There's a thread in the -stable mailing list at the moment about a problem
with threads in -current that prevents MySQL from shutting down.

I don't understand the problem. However, Michael Gile <gilem@wsg.net> in
message-id <199808112043.NAA00879@hub.freebsd.org> has just reposted a
message that was sent by the MySQL developer <monty@analytikerna.se> that
contains a description of the problem and patches. 

I see no reason why this message won't also sit in someone's mail queue
and slowly rot, so I'm submitting it as a PR so that at least it gets
stuck in the system, 'officially' :-)

THIS PR INCLUDES PATCHES! However, I'm not in a position to test them
(or even understand them much).

>Description:

   Date: Tue, 11 Aug 1998 16:19:23 -0400
   To: Mike Smith <mike@smith.net.au>
   From: "Michael R. Gile" <gilem@wsg.net>
   Subject: Re: threads bug [and mysql] (large)

At 03:44 PM 8/10/98 -0700, Mike Smith wrote:
>How-To-Repeat:


>Fix:
	

>Release-Note:
>Audit-Trail:

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--
 

From: "Daniel M. Eischen" <eischen@vigrid.com>
To: freebsd-gnats-submit@freebsd.org, nik@iii.co.uk
Cc: jb@cimlogic.com.au
Subject: Re: kern/7586: [PATCH] Threads bug in libc_r preventing MySQL from shutting down
Date: Mon, 31 Aug 1998 03:09:00 -0400

 Oops, forgot to fix uthread_info for the addition of another
 state.  Here is the fix for that.
 
 Dan Eischen
 eischen@vigrid.com
 
 *** ../uthread.orig/uthread_info.c	Tue Jun 30 14:00:11 1998
 --- uthread_info.c	Mon Aug 31 02:58:27 1998
 ***************
 *** 57,63 ****
   	{PS_SELECT_WAIT	, "Waiting on select"},
   	{PS_SLEEP_WAIT	, "Sleeping"},
   	{PS_WAIT_WAIT	, "Waiting process"},
 ! 	{PS_SIGWAIT	, "Waiting for a signal"},
   	{PS_JOIN	, "Waiting to join"},
   	{PS_SUSPENDED	, "Suspended"},
   	{PS_DEAD	, "Dead"},
 --- 57,64 ----
   	{PS_SELECT_WAIT	, "Waiting on select"},
   	{PS_SLEEP_WAIT	, "Sleeping"},
   	{PS_WAIT_WAIT	, "Waiting process"},
 ! 	{PS_SIGSUSPEND	, "Waiting (sigsuspend) for a signal"},
 ! 	{PS_SIGWAIT	, "Waiting (sigwait) for a signal"},
   	{PS_JOIN	, "Waiting to join"},
   	{PS_SUSPENDED	, "Suspended"},
   	{PS_DEAD	, "Dead"},
State-Changed-From-To: open->closed 
State-Changed-By: msmith 
State-Changed-When: Fri Nov 6 15:18:04 PST 1998 
State-Changed-Why:  
Patch committed by jb 
>Unformatted:
 >> At 12:29 PM 8/10/98 -0700, Tom wrote:
 >> >
 >> >On Sun, 9 Aug 1998, Michael R. Gile wrote:
 >> >
 >> >> There appears to be a recurring bug in libc_r that is causing
 >> >> Mysql not to respond to a shutdown.  The author claims that 
 >> >> he helped the development group fix this bug some time ago, 
 >> >> but that it has recurred.  Any suggestions on where to find this
 >> >> documentation would be helpful.
 >> >
 >> >  I don't believe this bug was ever fixed.  You can look at the cvslogs to
 >> >see all changes to libc_r.
 >> 
 >> i tend to agree, but monty insists that he mailed the necessary fixes
 >> to the freebsd team months ago.
 >
 >To whom?  The correct thing do to would be to file a PR, and then use 
 >the PR when referring to this.  It wouldn't be surprising if the 
 >patches are rotting in someone's inbox where nobody else can get at 
 >them.
 >-- 
 
 i have attached all the relevant documentation that the author had in 
 his sentmail box.  I wouldn't normally post such a large message, but
 i wanted to make sure that this stuff made it into the mail archives.
 If anyone else wants to help me try to sort through it and find what
 the current signal problem with mysql & freebsd, then let me know.
 
 -mike
 
 ==============
 -----------
 To: jb@cimlogic.com.au
 cc: pauls@locust.etext.org
 Subject: Freebsd 3.0 threads
 Reply-To: monty@analytikerna.se
 
 
 Hi.
 
 Sorry to mail you directly, but I got your name from
 pauls@locust.etext.org and he said that you usually answer questions
 about the FreeBSD pthread implementation.
 
 I am the author of MySQL, a 'almost free' SQL implementation.
 MySQL uses Posix threads and is currently running with native threads
 on Solaris, Linux (with Linuxthreads), AIX, IRIX and OSF1.
 
 I also maintain much updated version of MIT threads and with this
 MySQL is known to run on SunOS, FreeBSD 2.0 and BSD 2.#.
 This MIT thread version is distrubted with the MySQL source distribution.
 
 I am now trying to help pauls out on FreeBSD 3.0 but I have now got
 into some trouble and I thought that maybe you can help me on the
 right track.
 
 1) There isn't a sched.h file.  pthread.h have prototypes for some functions
    that uses sched_param but it's a little problem to use them now :)
 
 2) I looked into /usr/src/lib/libc_r/uthread/pthread_priv.h and found
    the following:
 
 ----
 struct sched_param {
         int     prio;   /* Should be named sched_priority */
         void    *no_data;
 };
 
 enum schedparam_policy {
         SCHED_RR,
         SCHED_IO,
         SCHED_FIFO,
         SCHED_OTHER
 };
 ---- 
 
 Shouldn't this be in a sched.h file ?
 It would also be nice if 'prio' would be renamed 'sched_priority'. I
 think this is the standard slot name (at least all other pthread
 implementation uses this)
 
 3) The following functions are not defined:
    pthread_setprio(), pthread_attr_setprio(),pthread_attr_setscope()
 
    When do you think these will be available?
 
 4) I have now fixed workarounds for the above cases. All code compiles
    and links clean but when run a test program, pthread_create doesn't
    start a thread.  Should threads work at all in FreeBSD 3.0 ?
 
 Yours, Monty
 
 ************************************
 
 To: pauls@locust.etext.org
 cc: jb@cimlogic.com.au
 Subject: Info about mysql porting and fixed bugs in the libc_r library
 Reply-To: monty@analytikerna.se
 
 John Birrell hasn't answered my yet about my problems with the pthread
 library (I assume he is very busy like the rest of us).
 
 Because I couldn't get -lpthread to work I compiled the source version
 with -g and some things started to work. I can only assume that the
 libc_r that you have installed isn't the newest one or then something
 has gone wrong in your installation.
 
 I have now started getting some things to work. Here follows a list of
 bugs I have fixed in the pthread library. I really hope that John will
 have time to at least examine them and hopefully add some of them to
 the next distribution.
 
 I haven't yet get everything to work, so there will be more patches.
 
 Yours, Monty
 -------------
 
 Bugs found in the Freebsd 3.0 pthread implementation:
 
 ----------------------------------------
 
 - sigsuspend should replace the callers mask to the given mask, not add
   the given mask to the old mask.
   The signals should also be handled and not as with SIGWAIT where the
   signal function is ignored.
 
 Fix:
 
 uthread_sigsuspend.c:
 
                 /* Save the current sigmal mask: */
                 oset = _thread_run->sigmask;
 
 !               /* Replace the caller's mask with the current one: */
 !               _thread_run->sigmask= *set;     /* Patched by Monty */
 
                 /* Wait for a signal: */
 !               _thread_kern_sched_state(PS_SIGSUSPEND, __FILE__, __LINE__);
 
 
 uthread_kern.c:
 
         case PS_FDR_WAIT:
         case PS_FDW_WAIT:
         case PS_SLEEP_WAIT:
 +       case PS_SIGSUSPEND:
 
 And of course add a definition for PS_SIGSUSPEND.
 
 ----------------------------------------
 
 - Signals that are not waited for with sigwait() should be handled before
   they are returned.
 
 Fix:
 
 - Add a separate 'sigwait_waiting' mask in the thread structure and
   handle the signal in uthread_kern.c for SIGWAIT if the signal isn't in the
   sigwait_waiting mask.
 
 ----------------------------------------
 
 
 - It almost impossible to debug threads because all signals are masked in the
   threads library.
 
 Fix:
 
 uthread_kern.c, line 53
 
 - static sigset_t sig_to_block = 0xffffffff;
 + static sigset_t sig_to_block = ~((1 << 5) | (1 << 6) | (1 << 4));
 
 ----------------------------------------
 
 
 The sigwait function is in the library but it isn't exported.
 
 Fix:
 
 Add uthread_sigwait.c to libc_r/uthread/Makefile.inc
 
 Fix:
 
 Add uthread_sigwait.c to libc_r/uthread/Makefile.inc
 
 ----------------------------------------
 
 sigwait returns 'random' value:
 
 Fix:
 
 uthread_sigwait.c, line 42:
 
 -       int ret;
 +       int ret=EINTR;
 
 ----------------------------------------
 
 *********************************'
 >From monty Sun Aug 10 23:52:21 1997
 Date: Sun, 10 Aug 97 23:52:21 EET DST
 From:  <monty@monty.pp.sci.fi>
 To: Paul Southworth <pauls@locust.etext.org>
 Subject: Re: Info about mysql porting and fixed bugs in the libc_r library
 In-Reply-To: <Pine.NEB.3.95.970810160652.19417A-100000@locust.etext.org>
 References: <199708101719.UAA21091@monty.pp.sci.fi>
         <Pine.NEB.3.95.970810160652.19417A-100000@locust.etext.org>
 Reply-To: monty@analytikerna.se
 
 >>>>> "Paul" == Paul Southworth <pauls@locust.etext.org> writes:
 
 Paul> My mail sent to " jb@cimlogic.com.au" has been bouncing -- timed out.
 Paul> Perhaps there is something wrong with that site.  I took the questions you
 Paul> asked him and sent them to the freebsd-hackers mailing list.
 
 Paul> I can send your patches there as well if that's OK with you.
 
 Here is the 'newest' compleate patch that appears to work: (At least
 sigwait() now works according to Posix and MySQL really neads this):
 
 Please mail a copy of this to the freebsd-hackers list.
 
 This mails ends with a compleat patch that fixes everything except
 the pthread.h problem with struct sched_param, but I was able to
 handle this with configure.
 
 Yours, Monty
 
 -------
 
 Bugs found in Freebsd's pthread implementation:
 
 
 ----------------------------------------
 
 - sigsuspend should replace the callers mask to the given mask, not add
   the given mask to the old mask.
   The signals should also be handled and not as with SIGWAIT where the
   signal function is ignored.
 
 Fix:
 
 uthread_sigsuspend.c:
 
                 /* Save the current sigmal mask: */
                 oset = _thread_run->sigmask;
 
 !               /* Replace the caller's mask with the current one: */
 !               _thread_run->sigmask= *set;     /* Patched by Monty */
 
                 /* Wait for a signal: */
 !               _thread_kern_sched_state(PS_SIGSUSPEND, __FILE__, __LINE__);
 
 
 uthread_kern.c:
 
         case PS_FDR_WAIT:
         case PS_FDW_WAIT:
         case PS_SLEEP_WAIT:
 +       case PS_SIGSUSPEND:
 
 And of course add a definition for PS_SIGSUSPEND.
 
 ----------------------------------------
 
 - It almost impossible to debug threads because all signals are masked in the
   threads library.
 
 Fix:
 
 uthread_kern.c, line 53
 
 - static sigset_t sig_to_block = 0xffffffff;
 + static sigset_t sig_to_block = ~((1 << 5) | (1 << 6) | (1 << 4));
 
 ----------------------------------------
 
 - The sigwait function is in the library but it isn't exported.
 - A signal to a thread in sigwait doesn't set the thread 'runnable'.
   This is because the arguments to sigwait() is put to sigmask which doesn't
   work because the signal must be sent to _thread_signal().
 - Signals that are not waited for with sigwait() should be handled before
   they are returned.
 - sigwait returns 'random' value:
 
 Fix:
 
 Add uthread_sigwait.c to libc_r/uthread/Makefile.inc
 
 Change sigwait to:
 
 
 In pthread_privat.h
 
         PS_DEAD,
 !       PS_STATE_MAX,
 +       PS_SIGSUSPEND
 };
 
 ----
 
         /*
          * Current signal mask and array of pending signals.
          */
 !       sigset_t        sigmask,sigwaitmask;
         int             sigpend[NSIG];
 
 
 uthread_kern.c:
 
 Change:
 
         /* Waiting on a signal: */
         case PS_SIGWAIT:
                 /* Change the state of the thread to run: */
                 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
 
                 /* Return the signal number: */
                 pthread->signo = sig;
 
                 /* Flag the signal as dealt with: */
                 done = 1;
                 break;
         }
 
 to
 
         /* Waiting on a signal: */
         case PS_SIGWAIT:
                 /* Change the state of the thread to run: */
                 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
 
                 if (sigismember(&pthread->sigwaitmask, sig))
                 {
                   /* Return the signal number: */
                   pthread->signo = sig;
 
                   /* Flag the signal as dealt with: */
                   done = 1;
                 }
                 break;
 
 
 ----------------------------------------
 
 Because one needs to access the struct sched_param slots this must be
 defined when one includes pthread.h.  One should also change the slot name
 from 'prior' to 'sched_priority' according to Posix.
 
 Fix:
 
 Move definition of structs sched_param from pthread_private.h to 
 pthread.h.
 
 Change:
 
 struct sched_param {
         int     prio;
         void    *no_data;
 };
 
 to
 
 struct sched_param {
         int     sched_priority;
         void    *no_data;
 };
 
 
 Empty definition of the schedparam functions would also be nice..
 
 
 
 *******************************************************************************
 
 Complete patch of the above with some small additions for sigsuspend:
 
 
 
 
 diff of Makefile.inc in /usr/src/lib/libc_r/uthread/ and .
 85a86
 >       uthread_sigwait.c \
 diff of pthread_private.h in /usr/src/lib/libc_r/uthread/ and .
 243c243,244
 <       PS_STATE_MAX
 ---
 >       PS_STATE_MAX,
 >       PS_SIGSUSPEND
 344c345
 <       sigset_t        sigmask;
 ---
 >       sigset_t        sigmask,sigwaitmask;
 diff of uthread_kern.c in /usr/src/lib/libc_r/uthread/ and .
 53c53,54
 < static sigset_t sig_to_block = 0xffffffff;
 ---
 > /* Changed by monty for easy debugging of pthreads with gdb */
 > static sigset_t sig_to_block = ~((1 << 5) | (1 << 6) | (1 << 4));
 893a895
 >       case PS_SIGSUSPEND:
 909a912,913
 >               if (sigismember(&pthread->sigwaitmask, sig))
 >               {
 914a919
 >               }
 1100a1106
 >               case PS_SIGSUSPEND:
 1449a1456
 >                       case PS_SIGSUSPEND:
 diff of uthread_sigsuspend.c in /usr/src/lib/libc_r/uthread/ and .
 50,51c50,51
 <               /* Combine the caller's mask with the current one: */
 <               _thread_run->sigmask |= *set;
 ---
 >               /* Replace the caller's mask with the current one: */
 >               _thread_run->sigmask= *set;/* Patched by Monty */
 54c54
 <               _thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
 ---
 >               _thread_kern_sched_state(PS_SIGSUSPEND, __FILE__, __LINE__);
 diff of uthread_sigwait.c in /usr/src/lib/libc_r/uthread/ and .
 38a39,40
 > /* This version of sigwait is modifed by monty@tcx.se to work properly */
 > 
 42c44
 <       int ret;
 ---
 >       int ret=0;
 49,51d50
 <       /* Save the current sigmal mask: */
 <       oset = _thread_run->sigmask;
 < 
 53c52,56
 <       _thread_run->sigmask |= *set;
 ---
 >       _thread_run->sigmask &=  ~*set;
 >       _thread_run->sigwaitmask = *set;
 > 
 >       /* Clear for easy error check */
 >       _thread_run->signo=0;
 62a66,68
 > 
 >       /* Reset the sigwait mask for debugging */
 >       _thread_run->sigwaitmask = 0;
 
 
 ****************************************************************
 
 From: John Birrell  <jb@cimlogic.com.au>
 To: edmond@shaman.lycaeum.org (Andrew N. Edmond)
 Cc: jb@cimlogic.com.au, monty@tcx.se, ross@flyingcroc.com
 Subject: Re: is libc_r broken in 980520-SNAP?
 Date: Wed, 17 Jun 1998 15:22:39 +1000 (EST)
 
 Andrew N. Edmond wrote:
 > We are specifically looking for something for monty to be able to put in
 > his INSTALL-SOURCE doc on how to compile MySQL 3.22.1-alpha and beyond on
 > FreeBSD 3.0-current past march or so... (including optimizing it with 
 > egcc -O6).  Monty also has assembler code for i386 platforms for the
 > string functions that we are trying to compile in here as well...
 > (--enable-assembler) 
 > 
 > ... you'd be willing to help with this? 
 
 MySQL was one of the packages mentioned when people complained about
 performance differences between libc_r and MIT pthreads. An attempt has
 been made to address those issues, but nobody has commented on any
 performance change.
 
 Since I'm also working on FreeBSD/Alpha, I'm choosing packages to checkout
 with that too. MySQL might be worth trying provided that the tests are
 good enough to indicate if the package actually works.
 
 Is the FreeBSD i386 asm code for the string functions no good?
 
 
 ***************************'
 
 From: John Birrell  <jb@cimlogic.com.au>
 To: tom@uniserve.com (Tom)
 Cc: jb@cimlogic.com.au, edmond@shaman.lycaeum.org, stable@FreeBSD.ORG,
         monty@tcx.se
 Subject: Re: is libc_r broken in 980520-SNAP (and stable?)?
 Date: Thu, 18 Jun 1998 07:55:55 +1000 (EST)
 
 Tom wrote:
 >   One thing that confuses me is that how does libc_r from 2.2.6-stable and
 > -current compare these days?  They used to be identical, but now that
 > -current is getting kernel support for threads and alpha stuff, I assume
 > that they must be quite different now.  Primarily, is libc_r from
 > 2.2.6-stable just as usable as libc_r from current?  Highwind Software
 > (www.highwind.com) has a beta version of their news software that it is
 > statically linked to a libc_r with fixes they say they got from you.
 > Would this be a -stable libc_r or a -current libc_r that they are using?
 
 Highwind are only using 2.2.6 with libc_r built from the RELENG_2_2 branch.
 The -current libc_r differs substantially from the -stable implementation
 because it supports just the POSIX style of signal handling where there
 are one set of signal handlers declared for the threaded process, not
 one set per thread. This allows -current to avoid blocking signals as
 part of it's scheduler. This is what drains performance for some
 applications.
 
 The version of libc_r in the RELENG_2_2 contains fixes for all bugs that
 people have reported. In Highwind's case, they have code that did things
 like read/write with zero bytes; and write to a read only file. These
 caused libc_r to hang waiting on a file descriptor to become ready when
 it never would. Most software doesn't do this sort of thing. It seems
 to come from C++ code. 8-)
 
 Kernel threads in 3.0 actually have nothing to do with libc_r. They require
 a libpthread and a thread-aware libc. The -current libc_r implementation
 works on FreeBSD/Alpha.
 
 **************************
 
 From: John Birrell  <jb@cimlogic.com.au>
 To: tom@uniserve.com (Tom)
 Cc: jb@cimlogic.com.au, edmond@shaman.lycaeum.org, stable@FreeBSD.ORG,
         monty@tcx.se
 Subject: Re: is libc_r broken in 980520-SNAP (and stable?)?
 Date: Thu, 18 Jun 1998 08:27:37 +1000 (EST)
 
 Tom wrote:
 >   Are you aware of the problems with MySQL?  I have 2.2.6-stable of May
 > 21, and a signal/alarm test program (thr_alarm) hangs.
 
 No, I wasn't aware of that.
 
 >   Also, how should -stable threaded applications be compiled and linked?
 > You mentioned before that "-pthread" should be used rather than linking
 > with libc_r?  Does that apply to -stable too?  I think -stable thread apps
 > need to be compiled with "-D_THREAD_SAFE" and linked with "-lc_r" but I'm
 > not sure anymore.
 
 -stable thread apps need to be compiled with -D_THREAD_SAFE to get a
 thread-safe errno. -current does not require that.
 
 Linking both -current and -stable uses -pthread to get the right libraries
 because people don't seem to be able to use -nostdlib.
 
 I'm going to try building MySQL on -current this morning.
 
 -- 
 John Birrell - jb@cimlogic.com.au; jb@freebsd.org http://www.cimlogic.com.au/
 
 *******************************************'
 
 
 After this I haven't got anything from 'jb@cimlogic.com.au'.
 
 I suspect that the new alarm handling that he mentions in the second last
 mail has breaked something.
 
 Regards,
 Monty
 
 ======================================================
 Michael Gile                             gilem@wsg.net
 President                                (518)435-0682
 Web Services Group                 http://www.wsg.net/
 
 To Unsubscribe: send mail to majordomo@FreeBSD.org
 with "unsubscribe freebsd-stable" in the body of the message
 
