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.
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
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama
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 :-/
you have to avoid races, programs which install their own handlers (like ruby), and confusing the issue by shelling out three child processes in instead of one:
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
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama
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.
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
···
On Monday, June 02, 2008, at 01:40PM, "Mário Lopes" <mario.lopes@gmail.com> 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.
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.
#
# 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
this is because you have to no wait to install signal handlers in the code the system call runs - it can do whatever it wants. what you can do is cause a child process which *does* ignore INT to run that system command. the reason you need the second child is that ruby's system call is going to do it's own signal management of INT.
a @ http://codeforpeople.com/
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama
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
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?
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.
i have to ask though - *why* do this? what problem are you solving by trapping INT and handling it differently?
On Jun 2, 2008, at 3:20 PM, Mário Lopes wrote:
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama
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?
i believe this is the case - you cannot inject your own signal handlers into ffmpeg (easily) so this seems like the easiest solution.
still i wonder - ffmpeg dies on INT for a reason - it's worth considering: if a user is running from the console then they expect to be able to kill a process, if they are not then your problem vanishes. by trapping INT you will be forcing users to use something stronger, like -9, which may not do things like clean up temp files, etc. food for thought.
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
handlers into ffmpeg (easily) so this seems like the easiest solution.
still i wonder - ffmpeg dies on INT for a reason - it's worth
considering: if a user is running from the console then they expect to
be able to kill a process, if they are not then your problem
vanishes. by trapping INT you will be forcing users to use something
stronger, like -9, which may not do things like clean up temp files,
etc. food for thought.
Quite indeed.
But it won't be run by a normal user. We just want to make sure that the
process doesn't get killed and it gracefully quits and finishes whatever
it has to do.
I'm currently trying to use the Daemons gem to detach the process and
run it in the background. It seems to be working fine lest having to
hang on a while cycle and sleep until it ends. No chance of running it
concurrently though.
I'm currently trying to use the Daemons gem to detach the process and
run it in the background. It seems to be working fine lest having to
hang on a while cycle and sleep until it ends. No chance of running it
concurrently though.
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama