From: Lloyd Zusman Date: 2004-10-10T15:21:17+09:00 Subject: Re: How to exit properly with a signal? Charles Mills writes: > 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.) >> > > 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? > ---- 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.