ruby bug with fork and signals (SIGTERM)

A

Andreas Otto

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

I writing a C-Extension for ruby using "rb_fork(0,0,0,Qnil)" to create a
new process.

Behaviour:

1) before fork a SIGTERM send to the parent terminate the parent
2) after fork a SIGTERM is ignored

Analyze:

SIGTERM is initialized in "Init_signal" using

#ifdef SIGTERM
install_sighandler(SIGTERM, sighandler);
#endif

but the fork code does in "rb_fork_err"

....
for (; before_fork(), (pid = fork()) < 0; prefork()) {
after_fork();
....
after_fork();
....

The problem is the "after_fork" is called for parent and child:

#define after_fork() (GET_THREAD()->thrown_errinfo = 0, after_exec())

#define after_exec() \
(rb_thread_reset_timer_thread(), rb_thread_start_timer_thread(),
forked_child = 0, rb_disable_interrupt())

void
rb_disable_interrupt(void)
{
#if USE_TRAP_MASK
sigset_t mask;
sigfillset(&mask);
sigdelset(&mask, SIGVTALRM);
sigdelset(&mask, SIGSEGV);
pthread_sigmask(SIG_SETMASK, &mask, NULL);
#endif
}

and all signals are blocked except SIGVTALRM and SIGSEGV

after adding

sigdelset(&mask, SIGTERM);

to rb_disable_interrupt the code is working but a real solution should
save the initial mask and later on enable the mask again ...



mfg

Andreas Otto

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJMtAi8AAoJEGTcPijNG3/A2s0H/iRGL+1iWvOyxS6fbuEBsWx5
1I0/4IwGVWy40HpwfS+gQ1vZiAK5y9M30FQQqrtiekD1G/12STT0FSuSKFgAE6Y6
KEyCS8SILpVDlAxdVQRlFEyO+BdVPRunJSfnDhyglyqRKmG5QbTHbDrsX0GtI+2c
Ilh8HlAV9MVRzfTUAsPl6s7kK5pvEC82cxl8suEkdpoL6huhXxnfwzdGDBHx8oKE
gEDWY1knMAxc5KrBY2XO4yKuImCivl8KgRz6knryaVNntrjuiIw2DtVXopRBuxFz
EL6ylWQXNJlxPHihkKAVdVzo67oON+olnK2spC8msfTAz4TNjQpVapJasem8id4=
=YUmn
-----END PGP SIGNATURE-----
 
R

Robert Klemme

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

I writing a C-Extension for ruby using "rb_fork(0,0,0,Qnil)" to create a
new process.

Behaviour:

1) before fork a SIGTERM send to the parent terminate the parent
2) after fork a SIGTERM is ignored

Only in the parent?
Analyze:

SIGTERM is initialized in "Init_signal" using

#ifdef SIGTERM
=A0 =A0install_sighandler(SIGTERM, sighandler);
#endif

but the fork code does in "rb_fork_err"

...
=A0 =A0for (; before_fork(), (pid =3D fork()) < 0; prefork()) {
=A0 =A0 =A0 =A0after_fork();
...
=A0 =A0after_fork();
...

The problem is the "after_fork" is called for parent and child:

#define after_fork() (GET_THREAD()->thrown_errinfo =3D 0, after_exec())

#define after_exec() \
=A0(rb_thread_reset_timer_thread(), rb_thread_start_timer_thread(),
forked_child =3D 0, rb_disable_interrupt())

void
rb_disable_interrupt(void)
{
#if USE_TRAP_MASK
=A0 =A0sigset_t mask;
=A0 =A0sigfillset(&mask);
=A0 =A0sigdelset(&mask, SIGVTALRM);
=A0 =A0sigdelset(&mask, SIGSEGV);
=A0 =A0pthread_sigmask(SIG_SETMASK, &mask, NULL);
#endif
}

and all signals are blocked except SIGVTALRM and SIGSEGV

after adding

sigdelset(&mask, SIGTERM);

to rb_disable_interrupt the code is working but a real solution should
save the initial mask and later on enable the mask again ...

I doubt it is a good idea to use regular signal handling code to do
this. If at all you should probably use Ruby's methods. Note that
you get the old signal handler back when trapping:

irb(main):010:0> Process.kill "INT", $$
=3D> 1
irb(main):011:0> Got signal 2

irb(main):012:0* Signal.trap("INT", &old)
=3D> #<Proc:0x1020e154@(irb):9>
irb(main):013:0> Process.kill "INT", $$
=3D> 1
irb(main):014:0> ^C
irb(main):014:0> Process.kill "INT", $$
=3D> 1
irb(main):015:0> ^C

I don't know your specific requirements but in Ruby you would probably do

fork do
# whatever client code
end

Signal.trap 'TERM' do
$stderr.puts "Ignoring SIGTERM"
end

Does that help?

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
A

Andreas Otto

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Am 12.10.2010 09:32, schrieb Robert Klemme:
Only in the parent?

I just test the parent.
I doubt it is a good idea to use regular signal handling code to do
this. If at all you should probably use Ruby's methods. Note that
you get the old signal handler back when trapping:

irb(main):010:0> Process.kill "INT", $$
=> 1
irb(main):011:0> Got signal 2

irb(main):012:0* Signal.trap("INT", &old)
=> #<Proc:0x1020e154@(irb):9>
irb(main):013:0> Process.kill "INT", $$
=> 1
irb(main):014:0> ^C
irb(main):014:0> Process.kill "INT", $$
=> 1
irb(main):015:0> ^C

I don't know your specific requirements but in Ruby you would probably do

fork do
# whatever client code
end

Signal.trap 'TERM' do
$stderr.puts "Ignoring SIGTERM"
end

Does that help?

My problem is just the opposite

I want that SIGTERM is *not* ignored ...
the original parent does end on SIGTERM
the parent *after* fork does not stop on SIGTERM


mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJMtEKEAAoJEGTcPijNG3/AVBwH/108Gs9xoKoFg92lrIZ0sGQM
EicxDgJ5hzK5M5PAM+agsKaq7Yrq4F3YcbY9TawmoetfTJ8rhyyvBAqAiXXc/jjk
ngR3+Yym7KOSXTZBskGXzwk7eqg5uPM+iufGcv7qVoBT/OhtRIfylbD2M+AMkf5U
U2wO4ZwSwEiI5SxUTm/jffJ4VKkF4MCw6XoDdgImkUsvyZswXjUhqlZy8pyePAl/
BIutY2A0oTprAXEhM3W+JnWsRzaB8Y8cnJu7KTTHKhF0EDW/tdzGetNHa0K08XFV
e/ODkJOQ/id5hDlIuj0LgWkIWpuoKvCNSH3ZixjFweGcV62m2DdPgkTbY0fM22s=
=S+jo
-----END PGP SIGNATURE-----
 

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

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top