ruby bug with fork and signals (SIGTERM)

Discussion in 'Ruby' started by Andreas Otto, Oct 12, 2010.

  1. Andreas Otto

    Andreas Otto Guest

    -----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-----
     
    Andreas Otto, Oct 12, 2010
    #1
    1. Advertising

  2. On Tue, Oct 12, 2010 at 9:10 AM, Andreas Otto
    <> wrote:
    > -----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/
     
    Robert Klemme, Oct 12, 2010
    #2
    1. Advertising

  3. Andreas Otto

    Andreas Otto Guest

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

    Am 12.10.2010 09:32, schrieb Robert Klemme:
    > On Tue, Oct 12, 2010 at 9:10 AM, Andreas Otto
    > <> wrote:
    >> -----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?


    I just test the parent.

    >
    >> 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 ...

    >
    > 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-----
     
    Andreas Otto, Oct 12, 2010
    #3
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Teresa
    Replies:
    2
    Views:
    659
    Rob Thorpe
    Apr 6, 2004
  2. Zoran Bosnjak

    popen3,4 and SIGTERM

    Zoran Bosnjak, Oct 15, 2003, in forum: Python
    Replies:
    0
    Views:
    424
    Zoran Bosnjak
    Oct 15, 2003
  3. Eric Snow

    os.fork and pty.fork

    Eric Snow, Jan 8, 2009, in forum: Python
    Replies:
    0
    Views:
    602
    Eric Snow
    Jan 8, 2009
  4. Elliott Hird

    Segfaults, other signals, fork, etc.

    Elliott Hird, Apr 21, 2007, in forum: Ruby
    Replies:
    3
    Views:
    111
    Nobuyoshi Nakada
    Apr 22, 2007
  5. Luca Boero
    Replies:
    2
    Views:
    250
    Arne Juul
    Feb 22, 2008
Loading...

Share This Page