How to exit properly with a signal?

How are signals properly handled in ruby? (I am new to ruby but
experienced with C, sh and perl.)

Run, then interrupt it while it is in the sleep:

  sh -c 'sleep 10' ; echo $?

  130

However, this same script in ruby is trapped by the ruby default
signal handler.

  ruby -e 'sleep 10' ; echo $?
  -e:1:in `sleep': Interrupt from -e:1
  1

How may I have ruby's program exit code properly reflect to the caller
that it was terminated on a signal? And also how may I prevent the
default handler from printing extraneous information?

The perl version behaves as desired here similar to the shell version.

  perl -e 'sleep 10' ; echo $?

  130

I want to replace some existing programs with ruby equivalents.
I am using ruby 1.8.2 from Debian sid/unstable.

Thanks
Bob

Bob Proulx ha scritto:

How are signals properly handled in ruby? (I am new to ruby but
experienced with C, sh and perl.)

Run, then interrupt it while it is in the sleep:

  sh -c 'sleep 10' ; echo $?

  130

However, this same script in ruby is trapped by the ruby default
signal handler.

  ruby -e 'sleep 10' ; echo $?
  -e:1:in `sleep': Interrupt from -e:1
  1

I guess you want:
trap("INT") { puts "interrupted" }

Here is a stab in the dark... how about this:
$ ruby -e 'trap("INT") { |s| exit(s) }; sleep 10'; echo $?
^C2
$
or this:
$ ruby -e 'trap("INT") { |s| exit(128 + s) }; sleep 10'; echo $?
^C130
$

Works like bash, seems to be what you want...
---- taken from bash man page:
        For the shell's purposes, a command which exits with a zero exit status
        has succeeded. An exit status of zero indicates success. A non-zero
        exit status indicates failure. When a command terminates on a fatal
        signal N, bash uses the value of 128+N as the exit status.

···

On Oct 9, 2004, at 5:45 PM, Bob Proulx wrote:

How are signals properly handled in ruby? (I am new to ruby but
experienced with C, sh and perl.)

-----------------------------------------

-Charlie

Run, then interrupt it while it is in the sleep:

  sh -c 'sleep 10' ; echo $?

  130

However, this same script in ruby is trapped by the ruby default
signal handler.

  ruby -e 'sleep 10' ; echo $?
  -e:1:in `sleep': Interrupt from -e:1
  1

How may I have ruby's program exit code properly reflect to the caller
that it was terminated on a signal? And also how may I prevent the
default handler from printing extraneous information?

The perl version behaves as desired here similar to the shell version.

  perl -e 'sleep 10' ; echo $?

  130

gabriele renzi wrote:

Bob Proulx ha scritto:
> ruby -e 'sleep 10' ; echo $?
> -e:1:in `sleep': Interrupt from -e:1
> 1

I guess you want:
trap("INT") { puts "interrupted" }

Thank you for your reply. Unfortunately that does not work either.
Run, then interrupt:

  ruby -e 'trap("INT") { } ; sleep 10' ; echo $?
  0

The return code is now zero indicating a successful program
completion. Of course I can exit with an error in the handler such as
in the following example.

  ruby -e 'trap("INT") { exit 1 } ; sleep 10' ; echo $?
  1

But again, this does not return the proper wait(2) status to the
caller. The caller can't tell that the child process was terminated
with a signal.

In perl one does the following:

    $SIG{$sig} = 'DEFAULT';
    kill($sig,$$);

In C one does the following:

  act.sa_flags = 0;
  act.sa_handler = SIG_DFL;
  sigaction(sig,&act,0);
  raise(sig);

I tried doing in ruby what I would do in perl. Basically the
following.

    trap sig, "DEFAULT"
    Process.kill sig, $$

But no joy. Again my efforts were not able to produce the required
results.

  ruby ./signals.rb ; echo $?
  starting program
  signal INT received, cleaning up
  ./signals.rb:5:in `sighandler': Interrupt from ./signals.rb:7
          from ./signals.rb:7:in `call'
          from ./signals.rb:9:in `sleep'
          from ./signals.rb:9
  1

How can I exit with the same wait(2) status as if the program was
terminated on a signal? Hopefully someone will know the solution to
this problem.

Thanks
Bob

Charles Mills <cmills@freeshell.org> writes:

How are signals properly handled in ruby? (I am new to ruby but
experienced with C, sh and perl.)

Here is a stab in the dark... how about this:
$ ruby -e 'trap("INT") { |s| exit(s) }; sleep 10'; echo $?
^C2
$
or this:
$ ruby -e 'trap("INT") { |s| exit(128 + s) }; sleep 10'; echo $?
^C130
$

Works like bash, seems to be what you want...

This works, but is it possible within the signal handler to get a
Process::Status object for the current program? If so, we could
return the status in the Posix-compliant way that 'sh' and 'perl'
do so.

The following comes from the Process::Status documentation:

  Process::Status encapsulates the information on the status of a
  running or terminated system process. The built-in variable $? is
  either nil or a Process::Status object.

    fork { exit 99 } #=> 26557
    Process.wait #=> 26557
    $?.class #=> Process::Status
    $?.to_i #=> 25344
    $? >> 8 #=> 99
    $?.stopped? #=> false
    $?.exited? #=> true
    $?.exitstatus #=> 99

  Posix systems record information on processes using a 16-bit
  integer. The lower bits record the process status (stopped, exited,
  signaled) and the upper bits possibly contain additional information
  (for example the program's return code in the case of exited
  processes). Pre Ruby 1.8, these bits were exposed directly to the Ruby
  program. Ruby now encapsulates these in a Process::Status object. To
  maximize compatibility, however, these objects retain a bit-oriented
  interface. In the descriptions that follow, when we talk about the
  integer value of stat, we're referring to this 16 bit value.

If we could interrogate the `$?' object (i.e., a Process::Status
instance) within a signal handler, we could do this:

  ruby -e 'trap("INT") { |s| exit($?.to_i) }; sleep 10'; echo $?

It would return 130.

However, in this case, `$?' is set to nil within the signal trap. In a
signal handler, is there a way to cause it to be set to the current
process's status? Or does it only get set after the return of a
Process.wait call that catches the exit of another forked process?

···

On Oct 9, 2004, at 5:45 PM, Bob Proulx wrote:

---- taken from bash man page:
        For the shell's purposes, a command which exits with a zero exit
status
        has succeeded. An exit status of zero indicates success. A
non-zero
        exit status indicates failure. When a command terminates on a
fatal
        signal N, bash uses the value of 128+N as the exit status.
-----------------------------------------

-Charlie

Run, then interrupt it while it is in the sleep:

  sh -c 'sleep 10' ; echo $?

  130

However, this same script in ruby is trapped by the ruby default
signal handler.

  ruby -e 'sleep 10' ; echo $?
  -e:1:in `sleep': Interrupt from -e:1
  1

How may I have ruby's program exit code properly reflect to the caller
that it was terminated on a signal? And also how may I prevent the
default handler from printing extraneous information?

The perl version behaves as desired here similar to the shell version.

  perl -e 'sleep 10' ; echo $?

  130

--
Lloyd Zusman
ljz@asfast.com
God bless you.