Subject: pthread / signal problem with NetBSD 3
To: None <netbsd-users@netbsd.org>
From: Jukka Salmi <j+nbsd@2007.salmi.ch>
List: netbsd-users
Date: 07/29/2007 13:45:48
--+HP7ph2BbKc20aGI
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi,

while playing with Sendmail milters on a NetBSD 3 system I noticed
that some of them always have errno set to EINVAL on exit. Some
debugging revealed that errno changes while pthread_create(3) is called
even though that call returns success (0).

Attached and [1]here is a slightly modified version of
libmilter/signal.c from Sendmail 8.14.1 to reproduce the problem:

$ uname -sr
NetBSD 3.1_STABLE
$ gcc -Wall -g -lpthread smsig.c
$ ktrace ./a.out
before pthread_create(): errno=0
pthread_create() returned 0, errno=22
$ kdump
[...]
 23165 a.out    CALL  write(2,0xbfbfe2c0,0x21)
 23165 a.out    GIO   fd 2 wrote 33 bytes
       "before pthread_create(): errno=0
       "
 23165 a.out    RET   write 33/0x21
 23165 a.out    CALL  timer_create(0,0xbfbfe830,0xbdbebe64)
 23165 a.out    RET   timer_create 0
 23165 a.out    CALL  __sigaction_sigtramp(1,0,0xbfbfe820,0,0)
 23165 a.out    RET   __sigaction_sigtramp 0
 23165 a.out    CALL  __sigaction_sigtramp(1,0xbfbfe820,0,0xbdb74948,1)
 23165 a.out    RET   __sigaction_sigtramp -1 errno 22 Invalid argument
 23165 a.out    CALL  __sigaction_sigtramp(1,0xbfbfe820,0,0xbdb74928,2)
 23165 a.out    RET   __sigaction_sigtramp 0
 23165 a.out    CALL  __sigaction_sigtramp(2,0,0xbfbfe820,0,0)
 23165 a.out    RET   __sigaction_sigtramp 0
 23165 a.out    CALL  __sigaction_sigtramp(2,0xbfbfe820,0,0xbdb74948,1)
 23165 a.out    RET   __sigaction_sigtramp -1 errno 22 Invalid argument
 23165 a.out    CALL  __sigaction_sigtramp(2,0xbfbfe820,0,0xbdb74928,2)
 23165 a.out    RET   __sigaction_sigtramp 0
[...]
 23165 a.out    CALL  __sigaction_sigtramp(0x3e,0,0xbfbfe820,0,0)
 23165 a.out    RET   __sigaction_sigtramp 0
 23165 a.out    CALL  __sigaction_sigtramp(0x3e,0xbfbfe820,0,0xbdb74948,1)
 23165 a.out    RET   __sigaction_sigtramp -1 errno 22 Invalid argument
 23165 a.out    CALL  __sigaction_sigtramp(0x3e,0xbfbfe820,0,0xbdb74928,2)
 23165 a.out    RET   __sigaction_sigtramp 0
 23165 a.out    CALL  __sigaction_sigtramp(0x3f,0,0xbfbfe820,0,0)
 23165 a.out    RET   __sigaction_sigtramp 0
 23165 a.out    CALL  __sigaction_sigtramp(0x3f,0xbfbfe820,0,0xbdb74948,1)
 23165 a.out    RET   __sigaction_sigtramp -1 errno 22 Invalid argument
 23165 a.out    CALL  __sigaction_sigtramp(0x3f,0xbfbfe820,0,0xbdb74928,2)
 23165 a.out    RET   __sigaction_sigtramp 0
[...]
 23165 a.out    CALL  write(2,0xbfbfe2c0,0x26)
 23165 a.out    GIO   fd 2 wrote 38 bytes
       "pthread_create() returned 0, errno=22
       "
 23165 a.out    RET   write 38/0x26
 23165 a.out    CALL  exit(0)


On a current system this works fine:

$ uname -sr
NetBSD 4.99.25
$ gcc -Wall -g -lpthread smsig.c
$ ./a.out
before pthread_create(): errno=0
pthread_create() returned 0, errno=0


Any hints about what's wrong with NetBSD 3?

TIA, Jukka

[1] http://salmi.ch/~jukka/nbsd/smsig.c

-- 
bashian roulette:
$ ((RANDOM%6)) || rm -rf ~

--+HP7ph2BbKc20aGI
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="smsig.c"

/*
 *  Copyright (c) 1999-2004, 2006 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 *
 */

#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <errno.h>

#define MI_SUCCESS      0
#define MI_FAILURE      (-1)

typedef pthread_t	sthread_t;

# define thread_create(ptid,wr,arg) pthread_create(ptid, NULL, wr, arg)

typedef pthread_mutex_t smutex_t;
# define smutex_init(mp)	(pthread_mutex_init(mp, NULL) == 0)
# define smutex_destroy(mp)	(pthread_mutex_destroy(mp) == 0)
# define smutex_lock(mp)	(pthread_mutex_lock(mp) == 0)
# define smutex_unlock(mp)	(pthread_mutex_unlock(mp) == 0)

#define MAX_FAILS_T	16	/* thread creation */

#define MILTER_CONT	0
#define MILTER_STOP	1
#define MILTER_ABRT	2

/*
#include <sm/gen.h>
SM_RCSID("@(#)$Id: signal.c,v 8.44 2006/03/03 03:42:04 ca Exp $")

#include "libmilter.h"
*/
/*
**  thread to handle signals
*/

static smutex_t M_Mutex;

static int MilterStop = MILTER_CONT;

static void	*mi_signal_thread __P((void *));
static int	 mi_spawn_signal_thread __P((char *));

/*
**  MI_STOP -- return value of MilterStop
**
**	Parameters:
**		none.
**
**	Returns:
**		value of MilterStop
*/

int
mi_stop()
{
	return MilterStop;
}
/*
**  MI_STOP_MILTERS -- set value of MilterStop
**
**	Parameters:
**		v -- new value for MilterStop.
**
**	Returns:
**		none.
*/

void
mi_stop_milters(v)
	int v;
{
	(void) smutex_lock(&M_Mutex);
	if (MilterStop < v)
		MilterStop = v;

	/* close listen socket */
fprintf(stderr, "mi_closener();\n");
	(void) smutex_unlock(&M_Mutex);
}
/*
**  MI_CLEAN_SIGNALS -- clean up signal handler thread
**
**	Parameters:
**		none.
**
**	Returns:
**		none.
*/

void
mi_clean_signals()
{
	(void) smutex_destroy(&M_Mutex);
}
/*
**  MI_SIGNAL_THREAD -- thread to deal with signals
**
**	Parameters:
**		name -- name of milter
**
**	Returns:
**		NULL
*/

static void *
mi_signal_thread(name)
	void *name;
{
	int sig, errs, sigerr;
	sigset_t set;

	(void) sigemptyset(&set);
	(void) sigaddset(&set, SIGHUP);
	(void) sigaddset(&set, SIGTERM);

	/* Handle Ctrl-C gracefully for debugging */
	(void) sigaddset(&set, SIGINT);
	errs = 0;

	for (;;)
	{
		sigerr = sig = 0;
#if defined(SOLARIS) || defined(__svr5__)
		if ((sig = sigwait(&set)) < 0)
#else /* defined(SOLARIS) || defined(__svr5__) */
		if ((sigerr = sigwait(&set, &sig)) != 0)
#endif /* defined(SOLARIS) || defined(__svr5__) */
		{
			/* some OS return -1 and set errno: copy it */
			if (sigerr <= 0)
				sigerr = errno;

			/* this can happen on OSF/1 (at least) */
			if (sigerr == EINTR)
				continue;
			fprintf(stderr,
				"%s: sigwait returned error: %d",
				(char *)name, sigerr);
			if (++errs > MAX_FAILS_T)
			{
				mi_stop_milters(MILTER_ABRT);
				return NULL;
			}
			continue;
		}
		errs = 0;

		switch (sig)
		{
		  case SIGHUP:
		  case SIGTERM:
			mi_stop_milters(MILTER_STOP);
			return NULL;
		  case SIGINT:
			mi_stop_milters(MILTER_ABRT);
			return NULL;
		  default:
			fprintf(stderr,
				"%s: sigwait returned unmasked signal: %d",
				(char *)name, sig);
			break;
		}
	}
	/* NOTREACHED */
}
/*
**  MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals
**
**	Parameters:
**		name -- name of milter
**
**	Returns:
**		MI_SUCCESS/MI_FAILURE
*/

static int
mi_spawn_signal_thread(name)
	char *name;
{
	sthread_t tid;
	int r;
	sigset_t set;

	/* Mask HUP and KILL signals */
	(void) sigemptyset(&set);
	(void) sigaddset(&set, SIGHUP);
	(void) sigaddset(&set, SIGTERM);
	(void) sigaddset(&set, SIGINT);

	if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
	{
		fprintf(stderr,
			"%s: Couldn't mask HUP and KILL signals", name);
		return MI_FAILURE;
	}
	fprintf(stderr, "before pthread_create(): errno=%d\n", errno);
	r = thread_create(&tid, mi_signal_thread, (void *)name);
	fprintf(stderr, "pthread_create() returned %d, errno=%d\n", r, errno);
	if (r != 0)
	{
		fprintf(stderr,
			"%s: Couldn't start signal thread: %d",
			name, r);
		return MI_FAILURE;
	}
	return MI_SUCCESS;
}
/*
**  MI_CONTROL_STARTUP -- startup for thread to handle signals
**
**	Parameters:
**		name -- name of milter
**
**	Returns:
**		MI_SUCCESS/MI_FAILURE
*/

int
/*
mi_control_startup(name)
	char *name;
*/
main(int argc, char *argv[])
{
	char *name = argv[0];

	if (!smutex_init(&M_Mutex))
	{
		fprintf(stderr,
			"%s: Couldn't initialize control pipe mutex", name);
		return MI_FAILURE;
	}

	/*
	**  spawn_signal_thread must happen before other threads are spawned
	**  off so that it can mask the right signals and other threads
	**  will inherit that mask.
	*/
	if (mi_spawn_signal_thread(name) == MI_FAILURE)
	{
		fprintf(stderr,
			"%s: Couldn't spawn signal thread", name);
		(void) smutex_destroy(&M_Mutex);
		return MI_FAILURE;
	}
	return MI_SUCCESS;
}

--+HP7ph2BbKc20aGI--