Getting process id of started process

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

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.

···

On Wed, 30 Mar 2005 14:57:51 -0800, Joe Van Dyk <joevandyk@gmail.com> wrote:

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

Wrote Joe Van Dyk <joevandyk@gmail.com>, on Thu, Mar 31, 2005 at 07:58:11AM +0900:

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

···

--
Sam Roberts <sroberts@certicom.com>

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

···

On 2005-03-30, Joe Van Dyk <joevandyk@gmail.com> wrote:

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?

Joe Van Dyk wrote:

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.

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?

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

···

On Wed, 30 Mar 2005 14:57:51 -0800, Joe Van Dyk <joevandyk@gmail.com> wrote:

In data 3/31/2005, "Joe Van Dyk" <joevandyk@gmail.com> ha scritto:

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.

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?

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.

Thanks,
Joe

E

···

On Wed, 30 Mar 2005 14:57:51 -0800, Joe Van Dyk <joevandyk@gmail.com> wrote:

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.

···

On Thu, Mar 31, 2005 at 09:02:02AM +0900, Joe Van Dyk wrote:

On Wed, 30 Mar 2005 14:57:51 -0800, Joe Van Dyk <joevandyk@gmail.com> wrote:
> 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?