[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Traping signals on child processes

Mário Lopes

6/2/2008 2:59:00 PM

Hi,

I currently have a Ruby process that spawns another process through a
system() call in order to run an application from the command line. The
child process should not be aborted by INT signals and therefore the
parent process shall wait for it to finish before exiting.

In order to do so I tried trapping the INT signal but since system runs
in the foreground of the main process it seems that the application
that's being called gets the INT signal nevertheless, despite being
trapped in Ruby. The other approach I took was spawning a process in the
background and then waiting for it to finish but this approach adds a
lot of complexity due to shared code that can't be run twice.

What's the best approach to accomplish this? For the sake of simplicity
I'll leave a very simple example of what I want to do

Start main process
Start system/child process
INT signals can't stop whatever the system call is doing
End system/child process
If INT signal detected, exit, otherwise, continue running
End main process

Any ideas or suggestions to accomplish such are most welcome.

Thanks,

Mário
--
Posted via http://www.ruby-....

12 Answers

ara.t.howard

6/2/2008 4:07:00 PM

0


On Jun 2, 2008, at 8:59 AM, M=E1rio Lopes wrote:

> Hi,
>
> I currently have a Ruby process that spawns another process through a
> system() call in order to run an application from the command line. =20=

> The
> child process should not be aborted by INT signals and therefore the
> parent process shall wait for it to finish before exiting.
>
> In order to do so I tried trapping the INT signal but since system =20
> runs
> in the foreground of the main process it seems that the application
> that's being called gets the INT signal nevertheless, despite being
> trapped in Ruby. The other approach I took was spawning a process in =20=

> the
> background and then waiting for it to finish but this approach adds a
> lot of complexity due to shared code that can't be run twice.
>
> What's the best approach to accomplish this? For the sake of =20
> simplicity
> I'll leave a very simple example of what I want to do
>
> Start main process
> Start system/child process
> INT signals can't stop whatever the system call is doing
> End system/child process
> If INT signal detected, exit, otherwise, continue running
> End main process
>
> Any ideas or suggestions to accomplish such are most welcome.
>
> Thanks,
>
> M=E1rio


trap( :INT ){ warn "can't do that" }

fork { exec command }
Process.wait

if the child installs it's own signal handler you are hosed.

a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being =20
better. simply reflect on that.
h.h. the 14th dalai lama




Mário Lopes

6/2/2008 4:17:00 PM

0

ara.t.howard wrote:
> On Jun 2, 2008, at 8:59 AM, M�rio Lopes wrote:
>
>> in the foreground of the main process it seems that the application
>> Start main process
>> M�rio
> trap( :INT ){ warn "can't do that" }
>
> fork { exec command }
> Process.wait
>
> if the child installs it's own signal handler you are hosed.

Tried that with the following example just for testing..

fork { exec "echo 'start'; sleep 20; echo 'end'" }

And if I issue a SIGINT the warning gets printed but the 'end' never
gets printed meaning that the process ended abruptly. That's what I'm
trying to avoid :-/

Mário
--
Posted via http://www.ruby-....

ara.t.howard

6/2/2008 4:47:00 PM

0




On Jun 2, 2008, at 10:17 AM, M=E1rio Lopes wrote:

>
> Tried that with the following example just for testing..
>
> fork { exec "echo 'start'; sleep 20; echo 'end'" }
>
> And if I issue a SIGINT the warning gets printed but the 'end' never
> gets printed meaning that the process ended abruptly. That's what I'm
> trying to avoid :-/
>
> M=E1rio

you have to avoid races, programs which install their own handlers =20
(like ruby), and confusing the issue by shelling out three child =20
processes in instead of one:

cfp:~ > cat a.rb
ready =3D :ready

pipe =3D IO.pipe

trap('INT'){ STDERR.puts "#{ Process.pid } killed" }

pid =3D fork{
pipe.first.close
pipe =3D pipe.last
pipe.puts ready
sleep
}

trap 'INT', 'DEFAULT'

pipe.last.close
pipe =3D pipe.first
ready =3D pipe.gets

STDERR.puts "parent: #{ Process.pid }"
STDERR.puts "child: #{ pid }"

Process.kill 'INT', pid

Process.waitpid pid, Process::WUNTRACED


cfp:~ > ruby a.rb
parent: 25227
child: 25228
25228 killed



basically ruby is, by default, going to relay the signal to the child, =20=

you need to catch it and do something sensible with it.


a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being =20
better. simply reflect on that.
h.h. the 14th dalai lama




Mário Lopes

6/2/2008 5:37:00 PM

0

> basically ruby is, by default, going to relay the signal to the child,
> you need to catch it and do something sensible with it.

I wonder whether I didn't get your example thoroughly or I just didn't
make myself clear.

What I'm precisely trying to do is trapping the SIGINT signal from
getting to the child so it doesn't abort. I've been unable to do this. I
can get it on the main process though but can't prevent it from being
relayed to the child process.

Thanks.

Mário
--
Posted via http://www.ruby-....

Gary Wright

6/2/2008 6:15:00 PM

0

=20
On Monday, June 02, 2008, at 01:40PM, "M=E1rio Lopes" <mario.lopes@gmail.co=
m> wrote:
>
>What I'm precisely trying to do is trapping the SIGINT signal from=20
>getting to the child so it doesn't abort. I've been unable to do this. I=
=20
>can get it on the main process though but can't prevent it from being=20
>relayed to the child process.

Does this code demonstrate what you are looking for? If
you send an interrupt it should be caught by the main ruby process
and ignored by the child processes.

The code below arranges for the child processes to ignore the INT signal.

If you want to arrange for the child process to not even receive the
signal it gets more complicated. You've got to arrange for the child
process to be within its own process group and you have to make
sure that process group is detached from the terminal (has no
controlling terminal). These concerns typically arise when you are
trying to instantiate a daemon process. Even when you do that
someone can explicitly send the INT signal to your process (assuming
they have permissions).

Anyway, here is the code for the simple case of ignoring the INT signal:

puts "main: #{$$}"
trap('INT') { puts 'int caught by main' }
fork {
trap 'INT', 'IGNORE' # forked process ignores INT
puts "child before sleep: #{$$}"
exec 'echo "exec command"; sleep 10; echo "exec command after sleep" '
puts "child after sleep: #{$$}"
}

puts 'main program after fork'
Process.wait



ara.t.howard

6/2/2008 6:25:00 PM

0


On Jun 2, 2008, at 11:36 AM, M=E1rio Lopes wrote:

> What I'm precisely trying to do is trapping the SIGINT signal from
> getting to the child so it doesn't abort. I've been unable to do =20
> this. I
> can get it on the main process though but can't prevent it from being
> relayed to the child process.

you need interject another process:

#
# Start main process
# Start system/child process
# INT signals can't stop whatever the system call is doing
# End system/child process
# If INT signal detected, exit, otherwise, continue running
# End main process
#

def system_critical command
signaled =3D false
int =3D trap('INT'){ puts "signaled #{ $$ }"; signaled =3D true }
begin
pid =3D fork{ system command }
Process.kill 'INT', pid
Process.waitpid pid
ensure
trap('INT', int)
end
exit 15 if signaled
end


# use thread just so we can run *and* send ourselves a signal

thread =3D Thread.new do
system_critical "ruby -e' sleep 1 and puts :done' "
end

Process.kill 'INT', Process.pid

thread.join

cfp:~ > ruby a.rb
signaled 25656
signaled 25657
done


cfp:~ > ruby a.rb
signaled 25660
signaled 25661
done




this is because you have to no wait to install signal handlers in the =20=

code the system call runs - it can do whatever it wants. what you can =20=

do is cause a child process which *does* ignore INT to run that system =20=

command. the reason you need the second child is that ruby's system =20
call is going to do it's own signal management of INT.



a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being =20
better. simply reflect on that.
h.h. the 14th dalai lama




Mário Lopes

6/2/2008 9:21:00 PM

0

ara.t.howard wrote:
> On Jun 2, 2008, at 11:36 AM, M�rio Lopes wrote:
>
>> What I'm precisely trying to do is trapping the SIGINT signal from
>> getting to the child so it doesn't abort. I've been unable to do
>> this. I
>> can get it on the main process though but can't prevent it from being
>> relayed to the child process.
>
> you need interject another process:
>
> #
> # Start main process
> # Start system/child process
> # INT signals can't stop whatever the system call is doing
> # End system/child process
> # If INT signal detected, exit, otherwise, continue running
> # End main process
> #
>
> def system_critical command
> signaled = false
> int = trap('INT'){ puts "signaled #{ $$ }"; signaled = true }
> begin
> pid = fork{ system command }
> Process.kill 'INT', pid
> Process.waitpid pid
> ensure
> trap('INT', int)
> end
> exit 15 if signaled
> end
>
>
> # use thread just so we can run *and* send ourselves a signal
>
> thread = Thread.new do
> system_critical "ruby -e' sleep 1 and puts :done' "
> end
>
> Process.kill 'INT', Process.pid
>
> thread.join
>
> cfp:~ > ruby a.rb
> signaled 25656
> signaled 25657
> done
>
>
> cfp:~ > ruby a.rb
> signaled 25660
> signaled 25661
> done

This seems to work fine with sleep 10 â?? it waits until the end of the
execution without actually passing the INT signal! But I'm unable to
make it work with an external application like ffmpeg that traps the
SIGINT itself. Any idea on how could I override this behavior without
having to actually recompile ffmpeg and disable myself the handle?

Thanks again for your help.

Mário
--
Posted via http://www.ruby-....

ara.t.howard

6/3/2008 5:43:00 AM

0


On Jun 2, 2008, at 3:20 PM, M=E1rio Lopes wrote:

> This seems to work fine with sleep 10 =97 it waits until the end of =
the
> execution without actually passing the INT signal! But I'm unable to
> make it work with an external application like ffmpeg that traps the
> SIGINT itself. Any idea on how could I override this behavior without
> having to actually recompile ffmpeg and disable myself the handle?

i'm unsure what you mean - you mean when running from the console? if =20=

so try running ffmpeg with a pty.

i have to ask though - *why* do this? what problem are you solving by =20=

trapping INT and handling it differently?

there are good reasons - but i'm wondering ;-)


>
>
> Thanks again for your help.

a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being =20
better. simply reflect on that.
h.h. the 14th dalai lama




Mário Lopes

6/3/2008 10:08:00 AM

0

ara.t.howard wrote:
> On Jun 2, 2008, at 3:20 PM, M�rio Lopes wrote:
>
>> This seems to work fine with sleep 10 � it waits until the end of the
>> execution without actually passing the INT signal! But I'm unable to
>> make it work with an external application like ffmpeg that traps the
>> SIGINT itself. Any idea on how could I override this behavior without
>> having to actually recompile ffmpeg and disable myself the handle?
>
> i'm unsure what you mean - you mean when running from the console? if
> so try running ffmpeg with a pty.

Yes, when being invoked like ruby script.rb

> i have to ask though - *why* do this? what problem are you solving by
> trapping INT and handling it differently?
>
> there are good reasons - but i'm wondering ;-)

Well, ffmpeg should be running and not interrupted until it ends its
job. The exit should be graceful and not end abruptly, otherwise the
conversion will be interrupted.

Which could be the best approach to this issue? Let ffmpeg run in the
background and trap the INT signals in the foreground?

Mário
--
Posted via http://www.ruby-....

ara.t.howard

6/3/2008 3:19:00 PM

0


On Jun 3, 2008, at 4:07 AM, M=E1rio Lopes wrote:

> Which could be the best approach to this issue? Let ffmpeg run in the
> background and trap the INT signals in the foreground?

i believe this is the case - you cannot inject your own signal =20
handlers into ffmpeg (easily) so this seems like the easiest solution.

still i wonder - ffmpeg dies on INT for a reason - it's worth =20
considering: if a user is running from the console then they expect to =20=

be able to kill a process, if they are not then your problem =20
vanishes. by trapping INT you will be forcing users to use something =20=

stronger, like -9, which may not do things like clean up temp files, =20
etc. food for thought.

regards.

a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being =20
better. simply reflect on that.
h.h. the 14th dalai lama