processing misunderstand or bug?

Hi,

I don't understand this, and I wonder could shed some light on the situation?

I have the following experimental program:

use v6;
my $proc = Proc::Async.new($*EXECUTABLE, "-e", "sleep 20000; say 'done'");
$proc.stdout.tap: -> $s { print $s };
my $promise = $proc.start;
await $promise;

If I run this in one terminal and run "ps axuw" in another terminal I
see 2 processes running.
If I press Ctrl-C in the terminal where I launched the program, both
processes are closed.

OTOH If I run "kill PID" with the process ID of the parent process
then only that process is killed. The child process is still waiting
for the prompt.

It does not make any difference if I use kill PID, or kill -2 PID or
kill -3 PID.

I'd understand that "kill PID" leaves the child process but then why
does Ctrl-C kill both? And then how comes "kill -2 PID", which as I
understand must be the same SIGINT as the Ctrl-C, only kills the
parent?


This is Rakudo version 2017.04.3 built on MoarVM version 2017.04-53-g66c6dda
running on OSX.

regards
    Gabor
0
szabgab
7/15/2017 10:50:51 AM
perl.perl6.users 802 articles. 0 followers. Follow

5 Replies
8 Views

Similar Articles

[PageSpeed] 6

--f403045f8efe31d0e905545a6229
Content-Type: text/plain; charset="UTF-8"

On Sat, Jul 15, 2017 at 6:50 AM, Gabor Szabo <szabgab@gmail.com> wrote:

> If I run this in one terminal and run "ps axuw" in another terminal I
> see 2 processes running.
> If I press Ctrl-C in the terminal where I launched the program, both
> processes are closed.
>
> OTOH If I run "kill PID" with the process ID of the parent process
> then only that process is killed. The child process is still waiting
> for the prompt.
>
> It does not make any difference if I use kill PID, or kill -2 PID or
> kill -3 PID.
>
> I'd understand that "kill PID" leaves the child process but then why
> does Ctrl-C kill both? And then how comes "kill -2 PID", which as I
> understand must be the same SIGINT as the Ctrl-C, only kills the
> parent?
>

Ctrl-C sends SIGINT to all processes in the terminal's foreground process
group. There is no concept of "current process" on a terminal; Unixlike
systems are multitasking, and all processes in the process group have
access to the terminal, and there is no way for the OS to consider one of
them to be "the current process". (Indeed, it is possible, if unfortunate,
for multiple processes to be reading from the terminal at the same time.)
That only one such process can be considered by users to be "current" is
merely convention, and one that is easy to violate.

(Shells make it more difficult by forcing command pipelines into separate
process groups, and controlling them by sending signals to the process
group; if running in the foreground, it will be assigned as the terminal's
current process group. If a process in such process group *not* in the
terminal's foreground process group tries to read from the terminal, it
gets SIGTTIN; if it tries to write, it gets SIGTTOU. If these are not
specifically handled by the process, they turn into SIGSTOP. This allows
shells to maintain the illusion that there is a "current process", provided
that only the first process in a pipeline reads from the terminal.)

"ps -ej" shows processes by their process id, process group id, and session
id (a session being a collection of process groups; all process groups
created by a given interactive shell are in the same session). Typically
"kill" (both shell and API) with a negative "process id" treats that as a
negated process group id instead and sends the signal to the entire process
group.

I don't think Rakudo currently exposes any access to the process group or
session, because this is POSIX-specific (Windows has its own mechanisms,
which can be just as surprising). Proc::Async always runs things in its
current process group.

In short: Rakudo is not doing anything special here, you are seeing normal
POSIX behavior.

-- 
brandon s allbery kf8nh                               sine nomine associates
allbery.b@gmail.com                                  ballbery@sinenomine.net
unix, openafs, kerberos, infrastructure, xmonad        http://sinenomine.net

--f403045f8efe31d0e905545a6229
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On S=
at, Jul 15, 2017 at 6:50 AM, Gabor Szabo <span dir=3D"ltr">&lt;<a href=3D"m=
ailto:szabgab@gmail.com" target=3D"_blank">szabgab@gmail.com</a>&gt;</span>=
 wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bor=
der-left:1px #ccc solid;padding-left:1ex">If I run this in one terminal and=
 run &quot;ps axuw&quot; in another terminal I<br>
see 2 processes running.<br>
If I press Ctrl-C in the terminal where I launched the program, both<br>
processes are closed.<br>
<br>
OTOH If I run &quot;kill PID&quot; with the process ID of the parent proces=
s<br>
then only that process is killed. The child process is still waiting<br>
for the prompt.<br>
<br>
It does not make any difference if I use kill PID, or kill -2 PID or<br>
kill -3 PID.<br>
<br>
I&#39;d understand that &quot;kill PID&quot; leaves the child process but t=
hen why<br>
does Ctrl-C kill both? And then how comes &quot;kill -2 PID&quot;, which as=
 I<br>
understand must be the same SIGINT as the Ctrl-C, only kills the<br>
parent?<br></blockquote><div><br></div><div>Ctrl-C sends SIGINT to all proc=
esses in the terminal&#39;s foreground process group. There is no concept o=
f &quot;current process&quot; on a terminal; Unixlike systems are multitask=
ing, and all processes in the process group have access to the terminal, an=
d there is no way for the OS to consider one of them to be &quot;the curren=
t process&quot;. (Indeed, it is possible, if unfortunate, for multiple proc=
esses to be reading from the terminal at the same time.) That only one such=
 process can be considered by users to be &quot;current&quot; is merely con=
vention, and one that is easy to violate.</div><div><br></div><div>(Shells =
make it more difficult by forcing command pipelines into separate process g=
roups, and controlling them by sending signals to the process group; if run=
ning in the foreground, it will be assigned as the terminal&#39;s current p=
rocess group. If a process in such process group *not* in the terminal&#39;=
s foreground process group tries to read from the terminal, it gets SIGTTIN=
; if it tries to write, it gets SIGTTOU. If these are not specifically hand=
led by the process, they turn into SIGSTOP. This allows shells to maintain =
the illusion that there is a &quot;current process&quot;, provided that onl=
y the first process in a pipeline reads from the terminal.)<br></div></div>=
<div><br></div><div>&quot;ps -ej&quot; shows processes by their process id,=
 process group id, and session id (a session being a collection of process =
groups; all process groups created by a given interactive shell are in the =
same session). Typically &quot;kill&quot; (both shell and API) with a negat=
ive &quot;process id&quot; treats that as a negated process group id instea=
d and sends the signal to the entire process group.</div><div><br></div><di=
v>I don&#39;t think Rakudo currently exposes any access to the process grou=
p or session, because this is POSIX-specific (Windows has its own mechanism=
s, which can be just as surprising). Proc::Async always runs things in its =
current process group.</div><div><br></div><div>In short: Rakudo is not doi=
ng anything special here, you are seeing normal POSIX behavior.</div><div><=
br></div>-- <br><div class=3D"gmail_signature" data-smartmail=3D"gmail_sign=
ature"><div dir=3D"ltr"><div>brandon s allbery kf8nh =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 sine nomine associates</div><div><a href=3D"mailto:allbery.b@gma=
il.com" target=3D"_blank">allbery.b@gmail.com</a> =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0<a href=3D"mailto:ballbery@sinenomine.net" target=3D"_b=
lank">ballbery@sinenomine.net</a></div><div>unix, openafs, kerberos, infras=
tructure, xmonad =C2=A0 =C2=A0 =C2=A0 =C2=A0<a href=3D"http://sinenomine.ne=
t" target=3D"_blank">http://sinenomine.net</a></div></div></div>
</div></div>

--f403045f8efe31d0e905545a6229--
0
allbery
7/15/2017 12:34:13 PM
--001a114e84cc19811305545aa67c
Content-Type: text/plain; charset="UTF-8"

On Sat, Jul 15, 2017 at 8:34 AM, Brandon Allbery <allbery.b@gmail.com>
wrote:

> Ctrl-C sends SIGINT to all processes in the terminal's foreground process
> group. There is no concept of "current process" on a terminal; Unixlike
> systems are multitasking, and all processes in the process group have
> access to the terminal, and there is no way for the OS to consider one of
> them to be "the current process". (Indeed, it is possible, if unfortunate,
> for multiple processes to be reading from the terminal at the same time.)
> That only one such process can be considered by users to be "current" is
> merely convention, and one that is easy to violate.
>
> (Shells make it more difficult by forcing command pipelines into separate
> process groups, and controlling them by sending signals to the process
> group; if running in the foreground, it will be assigned as the terminal's
> current process group. If a process in such process group *not* in the
> terminal's foreground process group tries to read from the terminal, it
> gets SIGTTIN; if it tries to write, it gets SIGTTOU. If these are not
> specifically handled by the process, they turn into SIGSTOP. This allows
> shells to maintain the illusion that there is a "current process", provided
> that only the first process in a pipeline reads from the terminal.)
>

If you want to find out about this in even more gory detail, you can look
up the arguments about supporting SIGSTAT (Ctrl-T, as supported on *BSD and
OS X) on Linux. It involves a number of gory hacks to maintain the pretense
that there is a "current process", all of which are unreliable, fragile,
and require quite a lot of ugliness in the kernel.

AFAIK there's no convenient way to look up the terminal's foreground
process group; you need to dig around in kernel memory to find the tty
structure. "who -u" makes a guess though.

-- 
brandon s allbery kf8nh                               sine nomine associates
allbery.b@gmail.com                                  ballbery@sinenomine.net
unix, openafs, kerberos, infrastructure, xmonad        http://sinenomine.net

--001a114e84cc19811305545aa67c
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On S=
at, Jul 15, 2017 at 8:34 AM, Brandon Allbery <span dir=3D"ltr">&lt;<a href=
=3D"mailto:allbery.b@gmail.com" target=3D"_blank">allbery.b@gmail.com</a>&g=
t;</span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0=
 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div cl=
ass=3D"gmail_extra"><div class=3D"gmail_quote"><div>Ctrl-C sends SIGINT to =
all processes in the terminal&#39;s foreground process group. There is no c=
oncept of &quot;current process&quot; on a terminal; Unixlike systems are m=
ultitasking, and all processes in the process group have access to the term=
inal, and there is no way for the OS to consider one of them to be &quot;th=
e current process&quot;. (Indeed, it is possible, if unfortunate, for multi=
ple processes to be reading from the terminal at the same time.) That only =
one such process can be considered by users to be &quot;current&quot; is me=
rely convention, and one that is easy to violate.</div><div><br></div><div>=
(Shells make it more difficult by forcing command pipelines into separate p=
rocess groups, and controlling them by sending signals to the process group=
; if running in the foreground, it will be assigned as the terminal&#39;s c=
urrent process group. If a process in such process group *not* in the termi=
nal&#39;s foreground process group tries to read from the terminal, it gets=
 SIGTTIN; if it tries to write, it gets SIGTTOU. If these are not specifica=
lly handled by the process, they turn into SIGSTOP. This allows shells to m=
aintain the illusion that there is a &quot;current process&quot;, provided =
that only the first process in a pipeline reads from the terminal.)</div></=
div></div></div></blockquote></div><div class=3D"gmail_extra"><br></div>If =
you want to find out about this in even more gory detail, you can look up t=
he arguments about supporting SIGSTAT (Ctrl-T, as supported on *BSD and OS =
X) on Linux. It involves a number of gory hacks to maintain the pretense th=
at there is a &quot;current process&quot;, all of which are unreliable, fra=
gile, and require quite a lot of ugliness in the kernel.</div><div class=3D=
"gmail_extra"><br></div><div class=3D"gmail_extra">AFAIK there&#39;s no con=
venient way to look up the terminal&#39;s foreground process group; you nee=
d to dig around in kernel memory to find the tty structure. &quot;who -u&qu=
ot; makes a guess though.<br clear=3D"all"><div><br></div>-- <br><div class=
=3D"gmail_signature" data-smartmail=3D"gmail_signature"><div dir=3D"ltr"><d=
iv>brandon s allbery kf8nh =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sine nomine associ=
ates</div><div><a href=3D"mailto:allbery.b@gmail.com" target=3D"_blank">all=
bery.b@gmail.com</a> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0<a href=
=3D"mailto:ballbery@sinenomine.net" target=3D"_blank">ballbery@sinenomine.n=
et</a></div><div>unix, openafs, kerberos, infrastructure, xmonad =C2=A0 =C2=
=A0 =C2=A0 =C2=A0<a href=3D"http://sinenomine.net" target=3D"_blank">http:/=
/sinenomine.net</a></div></div></div>
</div></div>

--001a114e84cc19811305545aa67c--
0
allbery
7/15/2017 12:53:13 PM
Hi,

Brandon, thanks for the explanation.

If I understand correctly, then this means Ctrl-C sends a SIGINT to
both the main process I ran and the child process I created using
Proc::Async.  When I run kill -2 PID it only sends the SIGINT to the
process I mentioned with PID.
(Which in my case was the process I ran.)

Then here is the problem which is closer to our original problem. I
have another script that uses Proc::Async to launch the previous
process. So now I have a main process, that has a child process which
has a child process.

use v6;
my $proc = Proc::Async.new($*EXECUTABLE, "async.pl6");
$proc.stdout.tap: -> $s { print $s };
my $promise = $proc.start;
sleep 10;
$proc.kill;

The "kill" there kill the immediate child but leaves the grandchild running.

Is there a way to send a signal to all the processes created by that
Proc::Async.new and to their children as well?

What I came up now is that changed the previous script (called
async.pl6) and added a line:

signal(SIGINT).tap( { say "Thank you for your attention"; $proc.kill } );

as below:

use v6;
my $proc = Proc::Async.new($*EXECUTABLE, "-e", "sleep 20000; say 'done'");
$proc.stdout.tap: -> $s { print $s };
my $promise = $proc.start;
signal(SIGINT).tap( { say "Thank you for your attention"; $proc.kill } );
await $promise;

Gabor
0
szabgab
7/15/2017 2:23:24 PM
--94eb2c040602a0487705545c4034
Content-Type: text/plain; charset="UTF-8"

On Sat, Jul 15, 2017 at 10:23 AM, Gabor Szabo <szabgab@gmail.com> wrote:

> If I understand correctly, then this means Ctrl-C sends a SIGINT to
> both the main process I ran and the child process I created using
> Proc::Async.  When I run kill -2 PID it only sends the SIGINT to the
> process I mentioned with PID.
> (Which in my case was the process I ran.)
>

Yes.


> Then here is the problem which is closer to our original problem. I
> have another script that uses Proc::Async to launch the previous
> process. So now I have a main process, that has a child process which
> has a child process.
>
> use v6;
> my $proc = Proc::Async.new($*EXECUTABLE, "async.pl6");
> $proc.stdout.tap: -> $s { print $s };
> my $promise = $proc.start;
> sleep 10;
> $proc.kill;
>
> The "kill" there kill the immediate child but leaves the grandchild
> running.
>
> Is there a way to send a signal to all the processes created by that
> Proc::Async.new and to their children as well?
>

Not currently; Proc::Async would need to expose process group
functionality, so you could put the child in a new process group, let the
grandchild inherit that process group, and use a variant of the 'kill'
method to signal the whole process group instead of just the one child.

You *might* be able to simulate this by using NativeCall to invoke
setpgrp() in the child, and to invoke C's kill() in the parent with the
negated process ID of the child (thus indicating its associates process
group). You will also need to arrange to find out the child's pid, which
also doesn't appear to be available via Proc::Async (sigh) so you may well
need to have the child print that (again, if necessary, using NativeCall to
access C's getpid()).

This will all necessarily be POSIX specific; no chance of it working on
Windows.

-- 
brandon s allbery kf8nh                               sine nomine associates
allbery.b@gmail.com                                  ballbery@sinenomine.net
unix, openafs, kerberos, infrastructure, xmonad        http://sinenomine.net

--94eb2c040602a0487705545c4034
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On S=
at, Jul 15, 2017 at 10:23 AM, Gabor Szabo <span dir=3D"ltr">&lt;<a href=3D"=
mailto:szabgab@gmail.com" target=3D"_blank">szabgab@gmail.com</a>&gt;</span=
> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bo=
rder-left:1px #ccc solid;padding-left:1ex">If I understand correctly, then =
this means Ctrl-C sends a SIGINT to<br>
both the main process I ran and the child process I created using<br>
Proc::Async.=C2=A0 When I run kill -2 PID it only sends the SIGINT to the<b=
r>
process I mentioned with PID.<br>
(Which in my case was the process I ran.)<br></blockquote><div><br></div><d=
iv>Yes.</div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Then here is the problem which is closer to our original problem. I<br>
have another script that uses Proc::Async to launch the previous<br>
process. So now I have a main process, that has a child process which<br>
has a child process.<br>
<br>
use v6;<br>
my $proc =3D Proc::Async.new($*EXECUTABLE, &quot;async.pl6&quot;);<br>
<span class=3D"">$proc.stdout.tap: -&gt; $s { print $s };<br>
my $promise =3D $proc.start;<br>
</span>sleep 10;<br>
$proc.kill;<br>
<br>
The &quot;kill&quot; there kill the immediate child but leaves the grandchi=
ld running.<br>
<br>
Is there a way to send a signal to all the processes created by that<br>
Proc::Async.new and to their children as well?<br></blockquote><div><br></d=
iv><div>Not currently; Proc::Async would need to expose process group funct=
ionality, so you could put the child in a new process group, let the grandc=
hild inherit that process group, and use a variant of the &#39;kill&#39; me=
thod to signal the whole process group instead of just the one child.</div>=
<div><br></div><div>You *might* be able to simulate this by using NativeCal=
l to invoke setpgrp() in the child, and to invoke C&#39;s kill() in the par=
ent with the negated process ID of the child (thus indicating its associate=
s process group). You will also need to arrange to find out the child&#39;s=
 pid, which also doesn&#39;t appear to be available via Proc::Async (sigh) =
so you may well need to have the child print that (again, if necessary, usi=
ng NativeCall to access C&#39;s getpid()).</div><div><br></div></div>This w=
ill all necessarily be POSIX specific; no chance of it working on Windows.<=
br clear=3D"all"><div><br></div>-- <br><div class=3D"gmail_signature" data-=
smartmail=3D"gmail_signature"><div dir=3D"ltr"><div>brandon s allbery kf8nh=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sine nomine associates</div><div><a href=3D=
"mailto:allbery.b@gmail.com" target=3D"_blank">allbery.b@gmail.com</a> =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0<a href=3D"mailto:ballbery@sinenom=
ine.net" target=3D"_blank">ballbery@sinenomine.net</a></div><div>unix, open=
afs, kerberos, infrastructure, xmonad =C2=A0 =C2=A0 =C2=A0 =C2=A0<a href=3D=
"http://sinenomine.net" target=3D"_blank">http://sinenomine.net</a></div></=
div></div>
</div></div>

--94eb2c040602a0487705545c4034--
0
allbery
7/15/2017 2:48:00 PM
Thank you!
This helped us solve a major headache we had with processes hanging
around after the tests have finished:

https://github.com/Bailador/Bailador/issues/194

regards
    Gabor
0
szabgab
7/15/2017 8:53:10 PM
Reply: