Discussion:
[ast-developers] Why does kill(1) in ksh93 always send SIGCONT after a signal ?
Roland Mainz
2013-07-01 00:43:53 UTC
Permalink
Hi!

----

Erm... why does ksh93's kill(1) implementation always send SIGCONT
after sending the requested signal ?

The following code...
-- snip --
1210 if(pid>=0)
1211 {
1212 if(qflag)
1213 {
1214 if(pid==0)
1215 goto no_sigqueue;
1216 r = sigqueue(pid,sig,sig_val);
1217 }
1218 else
1219 r = kill(pid,sig);
1220 if(r>=0 && !stopsig)
1221 {
1222 if(pw->p_flag&P_STOPPED)
1223 pw->p_flag &=
~(P_STOPPED|P_SIGNALLED);
1224 if(sig)
1225 kill(pid,SIGCONT);
1226 }
1227 }
-- snip --
... always sends SIGCONT when the original signal delivery was
successfull... but why is this neccesary ? Technically signals are
queued anyway if the child is stopped and maybe the user _wants_ the
child to continue in the stopped state.

The issue came up when debugging Solaris's kernel vs. SIGRTMIN&&co.
and someone noticed that actually twice the number of signals is
generated for each kill(1) usage than expected... which quickly
becomes a serious issue if SIGQUEUE_MAX is very low.

Cedric also pointed out that it doesn't seem to be required per
http://pubs.opengroup.org/onlinepubs/009695399/utilities/kill.html and
that neither bash, dash or GNU kill behave that way...

----

Bye,
Roland
--
__ . . __
(o.\ \/ /.o) roland.mainz at nrubsig.org
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 3992797
(;O/ \/ \O;)
Irek Szczesniak
2013-07-01 07:53:55 UTC
Permalink
Post by Roland Mainz
Hi!
----
Erm... why does ksh93's kill(1) implementation always send SIGCONT
after sending the requested signal ?
The following code...
-- snip --
1210 if(pid>=0)
1211 {
1212 if(qflag)
1213 {
1214 if(pid==0)
1215 goto no_sigqueue;
1216 r = sigqueue(pid,sig,sig_val);
1217 }
1218 else
1219 r = kill(pid,sig);
1220 if(r>=0 && !stopsig)
1221 {
1222 if(pw->p_flag&P_STOPPED)
1223 pw->p_flag &=
~(P_STOPPED|P_SIGNALLED);
1224 if(sig)
1225 kill(pid,SIGCONT);
1226 }
1227 }
-- snip --
... always sends SIGCONT when the original signal delivery was
successfull... but why is this neccesary ? Technically signals are
queued anyway if the child is stopped and maybe the user _wants_ the
child to continue in the stopped state.
I may have been a good intention to wake the target process up to
guarantee it consumes the signal but IMHO its still a standard
violation.
It clearly says "The kill utility shall send a signal to the process
or processes specified by each pid operand.". It does not say "a
SIGCONT signal is send with each signal to ensure the target process
is listening".

Irek
Irek Szczesniak
2013-07-05 18:07:16 UTC
Permalink
Post by Irek Szczesniak
Post by Roland Mainz
Hi!
----
Erm... why does ksh93's kill(1) implementation always send SIGCONT
after sending the requested signal ?
The following code...
-- snip --
1210 if(pid>=0)
1211 {
1212 if(qflag)
1213 {
1214 if(pid==0)
1215 goto no_sigqueue;
1216 r = sigqueue(pid,sig,sig_val);
1217 }
1218 else
1219 r = kill(pid,sig);
1220 if(r>=0 && !stopsig)
1221 {
1222 if(pw->p_flag&P_STOPPED)
1223 pw->p_flag &=
~(P_STOPPED|P_SIGNALLED);
1224 if(sig)
1225 kill(pid,SIGCONT);
1226 }
1227 }
-- snip --
... always sends SIGCONT when the original signal delivery was
successfull... but why is this neccesary ? Technically signals are
queued anyway if the child is stopped and maybe the user _wants_ the
child to continue in the stopped state.
I may have been a good intention to wake the target process up to
guarantee it consumes the signal but IMHO its still a standard
violation.
It clearly says "The kill utility shall send a signal to the process
or processes specified by each pid operand.". It does not say "a
SIGCONT signal is send with each signal to ensure the target process
is listening".
I tried it with bash:
strace ~/bin/ksh -c 'trap "print xCONTx" CONT ; trap ":" RTMIN ; bash
-c "kill -RTMIN $$" ; true' 2>&1 | egrep 'SIG(CONT|RT)'
rt_sigaction(SIGCONT, {0x41410c, [], SA_RESTORER|SA_SIGINFO,
0x7f359c717450}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGRT_2, {0x41410c, [], SA_RESTORER|SA_SIGINFO,
0x7f359c717450}, {SIG_DFL, [], 0}, 8) = 0
--- SIGRT_2 {si_signo=SIGRT_2, si_code=SI_USER, si_pid=20359, si_uid=1000} ---

bash (4.2.42(1)-release) only sends SIGRTMIN in this example.

What I do see is that bash has code to wake up a child process of the
current shell *after* kill was used. But it doesn't legalize (POSIX)
sending SIGCONT for every kill(1) use. No other shell besides ksh93
does it. Sun patched the feature away since it broke the SUSv3 test
suite, pdksh doesn't do it, dash doesn't do it and bash only sends
SIGCONT for processes which are marked 'stopped' by jobs -l.

I think sending SIGCONT after every kill(1) usage is a blatant
violation of the POSIX standard.

Irek
Cyrille Lefevre
2013-07-05 18:41:31 UTC
Permalink
Le 05/07/2013 20:07, Irek Szczesniak a ?crit :
<snip>
Post by Irek Szczesniak
strace ~/bin/ksh -c 'trap "print xCONTx" CONT ; trap ":" RTMIN ; bash
FYI, useless trap since SIGCONT is an untrappable signal as SIGSTOP and
SIGKILL are.


Regards,

Cyrille Lefevre
--
mailto:Cyrille.Lefevre-lists at laposte.net
Irek Szczesniak
2013-07-05 18:52:18 UTC
Permalink
On Fri, Jul 5, 2013 at 8:41 PM, Cyrille Lefevre
Post by Cyrille Lefevre
<snip>
Post by Irek Szczesniak
strace ~/bin/ksh -c 'trap "print xCONTx" CONT ; trap ":" RTMIN ; bash
FYI, useless trap since SIGCONT is an untrappable signal as SIGSTOP and
SIGKILL are.
ksh -c 'trap "print xCONT" CONT ; trap "print xRTMIN" RTMIN ; kill
-RTMIN $$ ; true'
xRTMIN
xCONT

SIGCONT is trapable. Even SIGKILL is trapable if you have multiple threads.

Irek
Roland Mainz
2013-07-05 21:22:47 UTC
Permalink
Post by Irek Szczesniak
Post by Irek Szczesniak
Post by Roland Mainz
Erm... why does ksh93's kill(1) implementation always send SIGCONT
after sending the requested signal ?
The following code...
-- snip --
1210 if(pid>=0)
1211 {
1212 if(qflag)
1213 {
1214 if(pid==0)
1215 goto no_sigqueue;
1216 r = sigqueue(pid,sig,sig_val);
1217 }
1218 else
1219 r = kill(pid,sig);
1220 if(r>=0 && !stopsig)
1221 {
1222 if(pw->p_flag&P_STOPPED)
1223 pw->p_flag &=
~(P_STOPPED|P_SIGNALLED);
1224 if(sig)
1225 kill(pid,SIGCONT);
1226 }
1227 }
-- snip --
... always sends SIGCONT when the original signal delivery was
successfull... but why is this neccesary ? Technically signals are
queued anyway if the child is stopped and maybe the user _wants_ the
child to continue in the stopped state.
I may have been a good intention to wake the target process up to
guarantee it consumes the signal but IMHO its still a standard
violation.
It clearly says "The kill utility shall send a signal to the process
or processes specified by each pid operand.". It does not say "a
SIGCONT signal is send with each signal to ensure the target process
is listening".
strace ~/bin/ksh -c 'trap "print xCONTx" CONT ; trap ":" RTMIN ; bash
-c "kill -RTMIN $$" ; true' 2>&1 | egrep 'SIG(CONT|RT)'
rt_sigaction(SIGCONT, {0x41410c, [], SA_RESTORER|SA_SIGINFO,
0x7f359c717450}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGRT_2, {0x41410c, [], SA_RESTORER|SA_SIGINFO,
0x7f359c717450}, {SIG_DFL, [], 0}, 8) = 0
--- SIGRT_2 {si_signo=SIGRT_2, si_code=SI_USER, si_pid=20359, si_uid=1000} ---
bash (4.2.42(1)-release) only sends SIGRTMIN in this example.
What I do see is that bash has code to wake up a child process of the
current shell *after* kill was used. But it doesn't legalize (POSIX)
sending SIGCONT for every kill(1) use. No other shell besides ksh93
does it. Sun patched the feature away since it broke the SUSv3 test
suite,
[snip]

Erm... actually the original patch for this added a check whether
kill(1)'s target process is a child of this shell (e.g. listed by $
jobs -l #) and whether it's in the stopped state. SIGCONT would only
be send if both conditions are true.

My proposal for ksh93 would be to do the same... but with the "twist"
of adding a -j option to explicitly enable/disable the job control
functionality in kill(1) ... since IMO it may be usefull (and legal)
to send signals (e.g. SIGUSR1, SIGUSR2, SIGRTMIN-SIGRTMAX etc.) to
stopped shell and wake it up later to process the queued signals...
... David: What do you think ?

----

Bye,
Roland
--
__ . . __
(o.\ \/ /.o) roland.mainz at nrubsig.org
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 3992797
(;O/ \/ \O;)
Roland Mainz
2013-07-05 23:10:17 UTC
Permalink
Post by Roland Mainz
Post by Irek Szczesniak
Post by Irek Szczesniak
Post by Roland Mainz
Erm... why does ksh93's kill(1) implementation always send SIGCONT
after sending the requested signal ?
The following code...
-- snip --
1210 if(pid>=0)
1211 {
1212 if(qflag)
1213 {
1214 if(pid==0)
1215 goto no_sigqueue;
1216 r = sigqueue(pid,sig,sig_val);
1217 }
1218 else
1219 r = kill(pid,sig);
1220 if(r>=0 && !stopsig)
1221 {
1222 if(pw->p_flag&P_STOPPED)
1223 pw->p_flag &=
~(P_STOPPED|P_SIGNALLED);
1224 if(sig)
1225 kill(pid,SIGCONT);
1226 }
1227 }
-- snip --
... always sends SIGCONT when the original signal delivery was
successfull... but why is this neccesary ? Technically signals are
queued anyway if the child is stopped and maybe the user _wants_ the
child to continue in the stopped state.
I may have been a good intention to wake the target process up to
guarantee it consumes the signal but IMHO its still a standard
violation.
It clearly says "The kill utility shall send a signal to the process
or processes specified by each pid operand.". It does not say "a
SIGCONT signal is send with each signal to ensure the target process
is listening".
strace ~/bin/ksh -c 'trap "print xCONTx" CONT ; trap ":" RTMIN ; bash
-c "kill -RTMIN $$" ; true' 2>&1 | egrep 'SIG(CONT|RT)'
rt_sigaction(SIGCONT, {0x41410c, [], SA_RESTORER|SA_SIGINFO,
0x7f359c717450}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGRT_2, {0x41410c, [], SA_RESTORER|SA_SIGINFO,
0x7f359c717450}, {SIG_DFL, [], 0}, 8) = 0
--- SIGRT_2 {si_signo=SIGRT_2, si_code=SI_USER, si_pid=20359, si_uid=1000} ---
bash (4.2.42(1)-release) only sends SIGRTMIN in this example.
What I do see is that bash has code to wake up a child process of the
current shell *after* kill was used. But it doesn't legalize (POSIX)
sending SIGCONT for every kill(1) use. No other shell besides ksh93
does it. Sun patched the feature away since it broke the SUSv3 test
suite,
[snip]
Erm... actually the original patch for this added a check whether
kill(1)'s target process is a child of this shell (e.g. listed by $
jobs -l #) and whether it's in the stopped state. SIGCONT would only
be send if both conditions are true.
My proposal for ksh93 would be to do the same... but with the "twist"
of adding a -j option to explicitly enable/disable the job control
functionality in kill(1) ... since IMO it may be usefull (and legal)
to send signals (e.g. SIGUSR1, SIGUSR2, SIGRTMIN-SIGRTMAX etc.) to
stopped shell and wake it up later to process the queued signals...
... David: What do you think ?
Here is an (unfished) prototype patch for the issues... but the code
raises a few more questions which I'll ask in a seperate email:
-- snip --
diff -r -u build_i386_64bit_debug/src/cmd/ksh93/sh/jobs.c
build_i386_64bit_kill_sigjobcont/src/cmd/ksh93/sh/jobs.c
--- src/cmd/ksh93/sh/jobs.c 2013-06-14 22:55:44.000000000 +0200
+++ src/cmd/ksh93/sh/jobs.c 2013-07-06 00:47:08.867238765 +0200
@@ -1219,10 +1219,11 @@
r = kill(pid,sig);
if(r>=0 && !stopsig)
{
- if(pw->p_flag&P_STOPPED)
+ if(sig && pw->p_flag&P_STOPPED)
+ {
pw->p_flag &=
~(P_STOPPED|P_SIGNALLED);
- if(sig)
kill(pid,SIGCONT);
+ }
}
}
else
@@ -1231,9 +1232,15 @@
goto no_sigqueue;
if((r = killpg(-pid,sig))>=0 && !stopsig)
{
- job_unstop(job_bypid(pw->p_pid));
if(sig)
- killpg(-pid,SIGCONT);
+ {
+ /*
+ * job_unstop() will
send SIGCONT to the
+ * group if there are
stopped child
+ * processes in it
+ */
+
job_unstop(job_bypid(pw->p_pid));
+ }
}
}
}
-- snip --

----

Bye,
Roland
--
__ . . __
(o.\ \/ /.o) roland.mainz at nrubsig.org
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 3992797
(;O/ \/ \O;)
Loading...