How do I trap Ctrl-C so it doesn't reach spawned threads?

J

Jens Carlberg

Hi!

I'm having trouble trapping Ctrl-C. I have a CLI that spawns processes I wo=
uld like to survive the CLI, but if I press Ctrl-C the spawns dies along wi=
th the CLI. I have experimented with trap(INT), and have boiled down the pr=
oblem into a small example program. I run this on Linux.

First, the program:
-------- 8< --------
#!/usr/bin/jruby

require 'readline'

keep_at_it =3D true

trap("INT") { puts "\nCtrl-C!" ; keep_at_it =3D false }

while (keep_at_it) do
line =3D Readline.readline("Enter for new xeyes, anything else to quit: "=
, true)
if (line.length =3D=3D 0 && keep_at_it =3D=3D true)
Thread.new { system("xeyes") }
else
keep_at_it =3D false
end
end
-------- 8< --------

Now, the behaviour:

When using jruby (1.6.0):
* Quitting leaves spawned processes running
* Ctrl-C kills all spawned processes, writes "Ctrl-C!" and quits after next=
return. I have used strace to verify that the xeyes actually gets a SIGINT=
, not a SIGHUP.

When using ruby (1.8.7):
* Quitting leaves spawned processes running
* First time Ctrl-C is pressed, the first started xeyes dies.
* Second time Ctrl-C is pressed "Ctrl-C!" is written and the program exists=
after next return, leaving remaining spawned processes alive.


I don't understand the behaviour. The jruby version feels more consistent, =
but is far away from what I need. The ruby version feels strange, but I cou=
ld handle my needs by spawning a dummy process if I didn't need jmx4r (whic=
h as far as I understand requires jruby).

1. How is trapping of SIGINT supposed to work? How is the passing of SIGINT=
supposed to work?
2. Why does it differs between ruby and jruby?
3. Anyone with a suggestion how to spawn processes not affected by a SIGINT=
?


///BR, Jens Carlberg
 
B

Brian Candler

3. Anyone with a suggestion how to spawn processes not affected by a

Try replacing

Thread.new { system("...") }

with:

fork { Process.setsid; exec("...") }

This also has the advantages of:
- not using threads
- the pid of the child is the return value from fork

Regards,

Brian.
 
C

Charles Oliver Nutter

Hi!

I'm having trouble trapping Ctrl-C. I have a CLI that spawns processes I =
would like to survive the CLI, but if I press Ctrl-C the spawns dies along =
with the CLI. I have experimented with trap(INT), and have boiled down the =
problem into a small example program. I run this on Linux.
...
I don't understand the behaviour. The jruby version feels more consistent=
, but is far away from what I need. The ruby version feels strange, but I c=
ould handle my needs by spawning a dummy process if I didn't need jmx4r (wh=
ich as far as I understand requires jruby).
1. How is trapping of SIGINT supposed to work? How is the passing of SIGI= NT supposed to work?
2. Why does it differs between ruby and jruby?
3. Anyone with a suggestion how to spawn processes not affected by a SIGI=
NT?

In MRI, I *believe* SIGINT is sent to the process that currently
controls the TTY, so in the case of system() it's sent to your program
that's running.

In JRuby, child processes don't usually share the TTY streams (JVM
isolates child process streams from the parent using pipes), so Ctrl-C
is sent to JRuby (the JVM itself, really, since we don't trap INT in
JRuby and allow JVM to handle it) and it shuts down taking the active
child process with it.

Perhaps you can try to use posix_spawn or 1.9's "spawn"?

- Charlie
 
C

Charles Oliver Nutter

At this point you might want to take this to a JRuby bug
(http://bugs.jruby.org) and we can sort out what you need and what
we're not doing right. I will note that we've been making various
fixes for process management recently, so this is very timely.

- Charlie

I have now tried both fork and spawn, and my confusion have reached new
levels. :)

Fork and ruby
=============
Worked as a charm. Too bad I need to use jruby due to JMX dependencies.


Fork and jruby
==============
Fork seems to be considered dangerous when used in jruby. I have found info
about enabling it, but are having very limited success in doing that.

I have started jirb two ways:

1. jirb -J-Djruby.fork.enabled=true

Results in "IRB::UnrecognizedSwitch: Unrecognized switch:
-J-Djruby.fork.enabled=true"

2. jruby -J-Djruby.fork.enabled=true -S jirb

Results in "NotImplementedError: fork is not available on this platform".

The jruby.fork.enabled property isn't listed when I do jruby --properties
either. Has it been removed?


Spawn and jruby
===============
1. Process.spawn("xeyes")
Do not protect the spawned process from Ctrl-C.

2. Process.spawn("xeyes", :pgroup=>true)
Gives the xeyes usage message; the option is used as a part of the command.
How do jruby separates options for the command and options for
Process.spawn?

Just to test that I read the Rdoc page for Process right:

3. spawn({"FOO"=>"BAR", "BAZ"=>nil}, "xeyes")
Errno::ENOENT: No such file or directory - {"FOO"=>"BAR", "BAZ"=>nil}


///Best regards, Jens Carlberg

-----Original Message-----
From: Charles Oliver Nutter [mailto:[email protected]]
Sent: den 11 april 2011 01:32
To: (e-mail address removed)
Cc: Jens Carlberg
Subject: Re: How do I trap Ctrl-C so it doesn't reach spawned threads?

Hi!

I'm having trouble trapping Ctrl-C. I have a CLI that spawns processes I
would like to survive the CLI, but if I press Ctrl-C the spawns dies along
with the CLI. I have experimented with trap(INT), and have boiled down the
problem into a small example program. I run this on Linux.
...
I don't understand the behaviour. The jruby version feels more consistent,
but is far away from what I need. The ruby version feels strange, but I
could handle my needs by spawning a dummy process if I didn't need jmx4r
(which as far as I understand requires jruby).
1. How is trapping of SIGINT supposed to work? How is the passing of SIGINT supposed to work?
2. Why does it differs between ruby and jruby?
3. Anyone with a suggestion how to spawn processes not affected by a
SIGINT?

In MRI, I *believe* SIGINT is sent to the process that currently controls
the TTY, so in the case of system() it's sent to your program that's
running.

In JRuby, child processes don't usually share the TTY streams (JVM isolates
child process streams from the parent using pipes), so Ctrl-C is sent to
JRuby (the JVM itself, really, since we don't trap INT in JRuby and allow
JVM to handle it) and it shuts down taking the active child process with it.

Perhaps you can try to use posix_spawn or 1.9's "spawn"?

- Charlie
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top