Subject: Re: kern/5504: signal handler does not get called again after execve
To: None <mouse@Rodents.Montreal.QC.CA>
From: John Kohl <jtk@kolvir.arlington.ma.us>
List: netbsd-bugs
Date: 05/28/1998 08:55:04
This seems related to a bug I ran into on SunOS, which is present in
NetBSD as well. Solaris and Digital UNIX do not have this bug.
Signal delivery masks (the sigmasks installed while a signal is handled)
should be cleared at exec() time, but they are not. Here is a pair of
sample programs that illuminate the problem. sethandler installs a
handler for a signal, and then execs showsigmask to display all the
signals and their disposition.
>From my internal records on this bug at work:
When a new image is exec()ed on UNIX, the system cleans out all
the previous signal handlers. On OSF/1 and Solaris, it also cleans out
the signal delivery masks (it's held in sigvec.sv_mask). On SunOS, it
removes the previous handler but leaves sv_mask set. Now, most programs
don't give a hoot--if they install a new signal handler, they ignore the
existing sv_mask and set their own. ksh, however, examines the existing
sv_mask and (apparently) ORs it into the sv_mask it sets.
sethandler.c:
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
void handler()
{
printf("handled\n");
return;
}
main()
{
int i;
sigset_t sm;
struct sigaction sv, sv2;
sigset_t MASK;
sigemptyset(&MASK);
sigaddset(&MASK, SIGINT);
sigaddset(&MASK, SIGTERM);
sigaddset(&MASK, SIGHUP);
sv.sa_handler = handler;
sv.sa_mask = MASK;
sv.sa_flags = 0;
if (sigaction(2, &sv, 0) == -1)
perror("sigaction");
printf("set signal 2 mask to %x\n", sv.sa_mask);
if (sigaction(2, 0, &sv2) == 0)
printf("signal %d handler=%lx, mask=%lx, flags=%lx\n",
2, sv2.sa_handler,
sv2.sa_mask,
sv2.sa_flags);
else
perror("sigaction");
sleep(3);
system("./showsigmask");
exit(1);
}
showsigmask.c:
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
void
handler()
{
printf("handled\n");
return;
}
int
main(int argc, char *argv[])
{
int i;
sigset_t sm;
struct sigaction sv, sv2;
/* sigsetmask(1<<15);*/
sigprocmask(0, NULL, &sm);
printf("%s: sigmask is %lx\n", argv[0], sm);
for (i = 1; i < 32; i++) {
if (sigismember(&sm, i))
printf("signal %d blocked\n", i);
memset(&sv, 0, sizeof(sv));
memset(&sv2, 0, sizeof(sv2));
if (sigaction(i, &sv, &sv2) == 0)
printf("signal %d handler=%lx, mask=%lx, flags=%lx\n",
i, sv2.sa_handler,
sv2.sa_mask,
sv2.sa_flags);
else
perror("sigaction");
sigaction(i, &sv2, 0); /* restore */
}
signal(2, SIG_DFL);
if (sigaction(2, &sv, &sv2) == 0)
printf("signal %d handler=%lx, mask=%lx, flags=%lx\n",
2, sv2.sa_handler,
sv2.sa_mask,
sv2.sa_flags);
else
perror("sigaction");
signal(2, handler);
if (sigaction(2, &sv, &sv2) == 0)
printf("signal %d handler=%lx, mask=%lx, flags=%lx\n",
2, sv2.sa_handler,
sv2.sa_mask,
sv2.sa_flags);
else
perror("sigaction");
exit(0);
}