[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Exececuting another application from within ruby

Nigel Wilkinson

7/4/2005 9:44:00 PM

Hi folks

I have a smell application from which I wish to display a file using an
external helper programme.

Lets say
app = the external programme
file = the file to be displayed

I've tried

system(app, file)

This works but it blocks my application. How can I fire up the helper
application in the background?

Cheers
Nigel


9 Answers

Ara.T.Howard

7/4/2005 10:04:00 PM

0

Joel VanderWerf

7/4/2005 11:25:00 PM

0

Nigel Wilkinson wrote:
> Hi folks
>
> I have a smell application from which I wish to display a file using an
> external helper programme.
>
> Lets say
> app = the external programme
> file = the file to be displayed
>
> I've tried
>
> system(app, file)
>
> This works but it blocks my application. How can I fire up the helper
> application in the background?

Thread.new {system(app, file)}

if all you want to do is start the process and you don't care about the
output or return value. Otherwise, see Ara's solutions.


Ara.T.Howard

7/5/2005 1:02:00 AM

0

Brian Candler

7/5/2005 9:01:00 AM

0

On Tue, Jul 05, 2005 at 08:24:51AM +0900, Joel VanderWerf wrote:
> > I have a smell application from which I wish to display a file using an
> > external helper programme.
> >
> > Lets say
> > app = the external programme
> > file = the file to be displayed
> >
> > I've tried
> >
> > system(app, file)
> >
> > This works but it blocks my application. How can I fire up the helper
> > application in the background?
>
> Thread.new {system(app, file)}
>
> if all you want to do is start the process and you don't care about the
> output or return value. Otherwise, see Ara's solutions.

It's worth mentioning that all that the system() call does is:

1. fork
2. exec (in child)
3. wait for child to terminate (in parent)

So a lower-level way to get what you want, without using Ruby threads, is:

pid = Process.fork do
exec(app, file)
end

and later on, you may wish to do

Process.waitpid(pid)

to reap the child and get its exit status. If it dies before then, it will
remain in the process table as a 'zombie' until you reap it or the parent
terminates. The Ruby thread solution effectively cleans up the child
automatically at the end for you.

If you want app to run as a daemon and never worry about when it terminates
(even if the Ruby program terminates first), then you can fork twice, run
the application in the grandchild, and the child terminates immediately:

pid = Process.fork do
Process.fork do
# normally you would redirect STDIN/STDOUT/STDERR here
exec(app, file)
end
exit
end
Process.waitpid(pid)
... continue here

I like being in full control like this, because system() hides the fact that
it is doing a fork, and fork can result in wierdness. For example, any
'atexit' script you've previously defined will run in both parent and child.
'teardown' scripts in Test::Unit can end up being called in both parent and
child. And so on.

Regards,

Brian.


Nakada, Nobuyoshi

7/5/2005 9:21:00 AM

0

Hi,

At Tue, 5 Jul 2005 18:01:28 +0900,
Brian Candler wrote in [ruby-talk:147202]:
> If you want app to run as a daemon and never worry about when it terminates
> (even if the Ruby program terminates first), then you can fork twice, run

If the parent program terminates before the child, you don't
have to worry if the child becomes a zombie. Instead, It will
be adopted by the init process.

> 'atexit' script you've previously defined will run in both parent and child.

No, system nor exec don't invoke at_exit handlers.

$ ruby -e 'at_exit{puts "#$$ exiting"}; system("echo foo")'
foo
1020 exiting

$ ruby -e 'at_exit{puts "#$$ exiting"}; Process.waitpid(fork {exec("echo foo")})'
foo
1772 exiting

$ ruby -e 'at_exit{puts "#$$ exiting"}; Process.waitpid(fork {puts "foo"})'
foo
2228 exiting
2108 exiting

--
Nobu Nakada


Ara.T.Howard

7/5/2005 2:15:00 PM

0

Joel VanderWerf

7/5/2005 5:03:00 PM

0

Brian Candler wrote:
> It's worth mentioning that all that the system() call does is:
>
> 1. fork
> 2. exec (in child)
> 3. wait for child to terminate (in parent)

Not on windows. There's no fork(), so ruby uses CreateProcess to
implement #system.


Nigel Wilkinson

7/5/2005 9:48:00 PM

0

--On Wednesday, July 06, 2005 02:03:07 +0900 Joel VanderWerf
<vjoel@path.berkeley.edu> wrote:

> Brian Candler wrote:
>> It's worth mentioning that all that the system() call does is:
>>
>> 1. fork
>> 2. exec (in child)
>> 3. wait for child to terminate (in parent)
>
> Not on windows. There's no fork(), so ruby uses CreateProcess to
> implement #system.
>

Thanks everyone, I'll have a play when I get a bit of time.

Cheers
Nigel




Brian Candler

7/6/2005 9:27:00 AM

0

On Tue, Jul 05, 2005 at 06:20:38PM +0900, nobuyoshi nakada wrote:
> > 'atexit' script you've previously defined will run in both parent and child.
>
> No, system nor exec don't invoke at_exit handlers.
>
> $ ruby -e 'at_exit{puts "#$$ exiting"}; system("echo foo")'
> foo
> 1020 exiting

It's clear that if the exec succeeds then no at_exit handler can possibly be
called; more interesting is the case if it fails. It looks like the at_exit
handler is not called there - I hadn't tested it before.

$ ruby -e 'at_exit{puts "#$$ exiting"}; system("zxcvzxcv"); p $?'
#<Process::Status: pid=31775,exited(127)>
31774 exiting
$

However:

$ ruby -e 'at_exit{puts "#$$ exiting"}; Process.waitpid(fork {exec("zxcvzxcv")}); p $?'
44096 exiting
-e:1:in `exec': No such file or directory - zxcvzxcv (Errno::ENOENT)
from -e:1
from -e:1:in `fork'
from -e:1
#<Process::Status: pid=44096,exited(1)>
44095 exiting

which is what I was expecting. Anyway, it's a useful mental note to keep :-)

Cheers,

Brian.