bin/90334: /bin/sh trap problem
Maxim Konovalov
maxim at macomnet.ru
Tue Dec 13 11:00:19 PST 2005
The following reply was made to PR bin/90334; it has been noted by GNATS.
From: Maxim Konovalov <maxim at macomnet.ru>
To: Dmitriy Kirhlarov <dkirhlarov at oilspace.com>
Cc: bug-followup at freebsd.org, kst at oilspace.com
Subject: Re: bin/90334: /bin/sh trap problem
Date: Tue, 13 Dec 2005 21:51:01 +0300 (MSK)
[...]
> >Description:
> on FreeBSD 5.* and FreeBSD 6.* sh scripts hanging with high
> CPU load, when SIGCHLD used.
> problem not present on 4-STABLE
> >How-To-Repeat:
> run simple script
> ---
> #!/bin/sh
> trap "" 20
> var=`echo anytext | sed 's/text/any/'`
> ---
Yep, SIG_IGN as action for SIGCHLD works differ on RELENG_4 and
post-RELENG_4. On post-RELENG_4 we can safely SIG_IGN SIGCHLD and the
kernel will G/C zombies for us. From signal(3):
% If a process explicitly specifies SIG_IGN as the action for the
% signal SIGCHLD, the system will not create zombie processes when
% children of the calling process exit. As a consequence, the system
% will discard the exit status from the child processes. If the
% calling process subsequently issues a call to wait(2) or equivalent,
% it will block until all of the calling process's children terminate,
% and then return a value of -1 with errno set to ECHILD.
'trap "" 20' sets SIG_IGN signal handler for SIGCHLD and we are
getting ECHILD in jobs.c::waitproc() again and again and fall to the
following endless loop in jobs.c::waitforjob():
%%%
865 while (jp->state == 0)
866 if (dowait(1, jp) == -1)
867 dotrap();
%%%
There are two patches for the problem:
1/ Mine, if user sets an empty trap for SIGCHLD, use the default
signal handler:
Index: trap.c
===================================================================
RCS file: /home/ncvs/src/bin/sh/trap.c,v
retrieving revision 1.31
diff -u -r1.31 trap.c
--- trap.c 8 Dec 2005 20:08:36 -0000 1.31
+++ trap.c 13 Dec 2005 18:18:07 -0000
@@ -238,6 +238,8 @@
action = S_CATCH;
else
action = S_IGN;
+ if (action == S_IGN && signo == SIGCHLD)
+ action = S_DFL;
if (action == S_DFL) {
switch (signo) {
case SIGINT:
%%%
2/ By your co-worker, Konstantin Stepanenkov, break an endless loop if
we get ECHILD:
Index: jobs.c
===================================================================
RCS file: /home/ncvs/src/bin/sh/jobs.c,v
retrieving revision 1.69
diff -u -r1.69 jobs.c
--- jobs.c 5 Sep 2005 17:57:19 -0000 1.69
+++ jobs.c 13 Dec 2005 18:38:26 -0000
@@ -929,6 +929,8 @@
if (pid <= 0)
return -1;
}
+ if (errno == ECHILD)
+ job->state = 1;
if (pid <= 0)
return pid;
INTOFF;
%%%
Not sure they are correct, need to think about the issue a bit more :-)
--
Maxim Konovalov
More information about the freebsd-bugs
mailing list