Getting process id of started process

J

Joe Van Dyk

Say I want to start a long running shell process (and monitor that process).


def start_process
@process_id = fork do
Kernel.system "cat /dev/zero > /dev/null"
end
end

However, @process_id doesn't contain the pid of the cat process. How
can I capture the pid of that process?

Thanks,
Joe
 
B

Ben Giddings

Joe said:
I've attatched code and test code at
http://rafb.net/paste/results/2Rj4rb87.html , if someone wants to take
a look. Hopefully it's clear about what I want to do.

I think what you need is "$?", which is "The status of the last executed
child process."

You might want to look at the docs here:

http://www.ruby-doc.org/core/classes/Kernel.html#M001773

It says that in block form, fork returns zero, but it might set $?, I'm
not sure.

In any case, you might need to use the non-block form of fork to do what
you want. That way you'll either get the process ID or nil:

def start_process
@process_id = fork
if @process_id
# We're in the parent
else
system("cat /dev/zero > /dev/null")
Process.exit!(0)
end

@process_id
end

Anyhow, the Process documentation seems to be pretty good:

http://www.ruby-doc.org/core/classes/Process.html

Ben
 
S

Saynatkari

In data 3/31/2005 said:
I've attatched code and test code at
http://rafb.net/paste/results/2Rj4rb87.html , if someone wants to take
a look. Hopefully it's clear about what I want to do.

Kernel#fork returns twice, once in the child (return value of
nil), once in the parent (returns the pid). Try a if/else block
and see if it works?

Re: $?, I think that is the only way to get the Process::Status
object. I do not think Process#wait(pid) returns immediately
though I may be wrong.

E
 
S

Sam Roberts

Say I want to start a long running shell process (and monitor that process).


def start_process
@process_id = fork do
Kernel.system "cat /dev/zero > /dev/null"
end
end

However, @process_id doesn't contain the pid of the cat process. How
can I capture the pid of that process?

You can't, not like this anyhow. You aren't running cat directly, you
are calling the shell, /bin/sh, which is processing the redirect command
(>/dev/null). Only the shell knows the pid of cat. You actually have

ruby --fork()--> ruby --system()--> /bin/sh --fork()/exec()--> /bin/cat

So there are 3 processes inherited from your main ruby executable.

Kernel.fork/exec/system are fairly thin wrappers around the C
equivalents, so a unix prog manual should cover whats happening, as well
as ways of doing whatever you are trying to do.

Sam
 
B

Brian Candler

It won't, because Kernel.system also does a fork, runs the 'cat' as a child,
waits for it to finish, and then continues.

You will get the pid of the cat process if you change Kernel.system "cat..."
to
exec "cat ..."

But then, the child Ruby process *becomes* cat at that point, and so when
cat terminates, the child terminates.

If you want to capture the pid of the 'cat' then you can reimplement
Kernel.system yourself - which is basically just fork and exec anyway.

It depends what you want to do with the variable @process_id later. If you
just want the child to run cat and then terminate, then 'exec' is what you
want.

In fact, I can't see what else you would want. Suppose I wrote:

def start_process
@process_id = fork do
Kernel.system "cat /dev/zero > /dev/null"
Kernel.system "cat /dev/null > /dev/null"
Kernel.system "cat /dev/zero > /dev/null"
end
end

which process ID would you want returned in @process_id ? You currently get
the (child) Ruby process, which then runs three grandchildren one after
another. I can't see how else it would usefully work, unless you get the pid
of each of the three grandchildren and communicate it back to the parent
somehow (e.g. over a socket). The pid for each grandchild won't be known
until that particular grandchild is started, of course.

Regards,

Brian.
 
C

Csaba Henk

Say I want to start a long running shell process (and monitor that process).


def start_process
@process_id = fork do
Kernel.system "cat /dev/zero > /dev/null"
end
end

However, @process_id doesn't contain the pid of the cat process. How
can I capture the pid of that process?

To ensure that the called program really runs as the child of the main
process (and not a further descendent), you have to code it in a
relatively low-level way; in the above case it would look like

def start_process
@process_id = fork do
File.reopen $stdin, File.open("/dev/null","w")
exec %w(cat /dev/zero)
end
end

(In this case, 'exec "cat /dev/zero"' would do as well. Ruby's exec is a
bastardized one, not just an interface to the posix exec* calls: it
tries to find out by itself whether to exec the program directly or to
do it via shell. In general, passing an array to exec protects from
shell expansion.)

I'm working on a lib which makes it easier, eg. you could do with it:

def start_process
po = Pope.new
po.do(%w(cat /dev/zero), 1 => "/dev/null").end
@process_id = po.actors[0].child
end

Csaba
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top