sigprocmask and fork
Kostik Belousov
konstantin.belousov at zoral.com.ua
Mon Apr 18 02:20:04 PDT 2005
Hi,
I come across the following problem:
after fork(), the 5-STABLE system sets the child process
blocked signal mask to 0 (let us account single-threaded processes only).
I was under impression that signal mask
shall be inherited by the child process (according to SUSv3 and
man fork). Inheritance _was_ the behaviour of 4-STABLE (there, p_sigmask belongs to struct proc and placed in the copied-on-fork part
of the structure) and also seen on other UNIXes (e.g. Solaris).
After googling, I found the comment by Dong Xuezhang in
http://lists.freebsd.org/pipermail/freebsd-threads/2005-February/002899.html
where he said that "Actually fork() do not copy the properties of signal mask".
I confirm that fork does not copy mask, but why ? Attached is the program that
illustrates this issue on
pooma% uname -a ~/work/bsd/sigmask
FreeBSD pooma.home 5.4-STABLE FreeBSD 5.4-STABLE #32: Fri Apr 15 22:16:43 EEST 2005 root at pooma.home:/usr/obj/usr/src/sys/POOMA i386
On unpatched 5-STABLE, the child process reports SIGUSR2 immediately after
start, despite parent blocked SIGUSR2 before forking.
It seems that needs of thread_schedule_upcall() to zero sigmask interfere
with the needs of the fork1().
I propose the trivial patch (against 5-STABLE) to fix the problems. It handles
td_sigmask in the way similar to td_sigstk, that is also zeroed on _upcall(),
as was done by davidxu at kern/kern_fork.c:1.209 rev.
Index: kern/kern_fork.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/kern/kern_fork.c,v
retrieving revision 1.234.2.8
diff -U5 -r1.234.2.8 kern_fork.c
--- kern/kern_fork.c 27 Feb 2005 02:36:39 -0000 1.234.2.8
+++ kern/kern_fork.c 18 Apr 2005 08:58:50 -0000
@@ -470,10 +470,11 @@
__rangeof(struct thread, td_startcopy, td_endcopy));
bcopy(&td->td_ksegrp->kg_startcopy, &kg2->kg_startcopy,
__rangeof(struct ksegrp, kg_startcopy, kg_endcopy));
td2->td_sigstk = td->td_sigstk;
+ td2->td_sigmask = td->td_sigmask;
/*
* Duplicate sub-structures as needed.
* Increase reference counts on shared objects.
*/
Thanks for attention,
Kostik Belousov.
-------------- next part --------------
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <stdio.h>
extern "C" void
sigusr2_handler(int signo)
{
static const char msg[] = "SIGUSR2\n";
write(2, msg, sizeof(msg) - 1);
_exit(0);
}
int
main(int argc, char *argv[])
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigusr2_handler;
sigaction(SIGUSR2, &sa, NULL);
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR2);
sigprocmask(SIG_BLOCK, &mask, NULL);
pid_t child = fork();
if (child == 0)
{
raise(SIGUSR2);
printf("sleeping\n");
sleep(10);
printf("enabling SIGUSR2\n");
sigprocmask(SIG_UNBLOCK, &mask, NULL);
while (true)
;
}
int status;
wait(&status);
return 0;
}
More information about the freebsd-hackers
mailing list