Processes and Portability

N

Name Name

I would like to run a process concurrently (thus if the process goes to
sleep or runs forever, I can still run other code from my main process)
and have all standard out of that process be put into a text file. I
would also like this code to be portable. And finally, I would like to
be able to kill this process at any time (So I will need the pid)

This thus eliminates the use of fork. Also, I have tried:

a=IO.popen("program > logfile"), but on Windows this creates two
processes, cmd.exe and program. a.pid only gives the pid of cmd.exe.
And the behavior on *nix seems to be just the program (although I can be
wrong).

So I require portability in that sense.

Is this possible?

thanks
 
A

ara.t.howard

I would like to run a process concurrently (thus if the process goes to
sleep or runs forever, I can still run other code from my main process) and
have all standard out of that process be put into a text file. I would also
like this code to be portable. And finally, I would like to be able to kill
this process at any time (So I will need the pid)

This thus eliminates the use of fork. Also, I have tried:

a=IO.popen("program > logfile"), but on Windows this creates two
processes, cmd.exe and program. a.pid only gives the pid of cmd.exe.
And the behavior on *nix seems to be just the program (although I can be
wrong).

So I require portability in that sense.

Is this possible?

thanks

try this - i haven't tested on windows but it can certainly be made to work:


harp:~ > cat a.rb
#!/usr/bin/env ruby

require 'rbconfig'
require 'thread'

class Spawn
CONFIG = Config::CONFIG

RUBY =
if system('ruby -e 42') # ruby is in our path
'ruby'
else # guess from rbconfig
File.join CONFIG['bindir'], CONFIG['ruby_install_name']
end

PROGRAM = "p $$;STDOUT.flush;STDERR.reopen(STDOUT);exec(*ARGV)"

ATTRIBUTES = %w[
mutex
out
exitstatus
exitstatus_q
cmd
pipe
pid
thread
]

ATTRIBUTES.each{|a| attr_accessor a}

def initialize *argv
@mutex = Mutex.new
@out = ''
@exitstatus = nil
@exitstatus_q = Queue.new
@cmd = "#{ RUBY } -e '#{ PROGRAM }' #{ argv.join(' ') }"
@pipe = IO.popen @cmd
@pid = @pipe.gets.to_i
at_exit{ Process.kill -9, @pid rescue nil }
@thread = Thread.new{
begin
while((line = @pipe.gets))
@mutex.synchronize{ @out << line }
end
ensure
@pipe.close rescue nil
exitstatus = $?.exitstatus
@exitstatus_q.push exitstatus
end
}
end

def out
@mutex.synchronize{ @out }
end

def exitstatus non_block = false
@exitstatus ||= @exitstatus_q.pop(non_block)
end

class << self; alias [] new; end
end


require 'yaml'

cmd = ARGV.join ' '

spawn = Spawn[ cmd ]

y 'spawn.cmd' => spawn.cmd
y 'spawn.pid' => spawn.pid
y 'spawn.exitstatus' => spawn.exitstatus
y 'spawn.out' => spawn.out



harp:~ > ruby a.rb date
spawn.cmd: ruby -e 'p $$;STDOUT.flush;STDERR.reopen(STDOUT);exec(*ARGV)' date
spawn.pid: 27232
spawn.exitstatus: 0
spawn.out: |
Tue Jul 11 10:31:22 MDT 2006


harp:~ > ruby a.rb no-exist
spawn.cmd: ruby -e 'p $$;STDOUT.flush;STDERR.reopen(STDOUT);exec(*ARGV)' no-exist
spawn.pid: 27235
spawn.exitstatus: 1
spawn.out: |
-e:1:in `exec': No such file or directory - no-exist (Errno::ENOENT)
from -e:1


regards.

-a
 
K

khaines

I would like to run a process concurrently (thus if the process goes to
sleep or runs forever, I can still run other code from my main process)
and have all standard out of that process be put into a text file. I
would also like this code to be portable. And finally, I would like to
be able to kill this process at any time (So I will need the pid)

This thus eliminates the use of fork. Also, I have tried:

If you are doing the equivalent of fork/exec, here's some code that is in
my IOWA package that will help. It depends on Daniel Berger's
win32-process library, which can be found at RubyForge:

http://rubyforge.org/projects/win32utils

It, in turn, is dependent on window-pr, found at the same URL.

This code has been tested on Linux and WinXP. You should be able to adapt
it to your purposes.



module IWATestSupport
def self.create_process(args)
@fork_ok = true unless @fork_ok == false
pid = nil
begin
raise NotImplementedError unless @fork_ok
unless pid = fork
Dir.chdir args[:dir]
exec(*args[:cmd])
end
rescue NotImplementedError
@fork_ok = false

begin
require 'rubygems'
rescue LoadError
end

begin
require 'win32/process'
rescue LoadError
raise "Please install win32-process."
end

cwd = Dir.pwd
Dir.chdir args[:dir]
pid = Process.create:)app_name => args[:cmd].join(' '))
Dir.chdir cwd
end
pid
end
end


Kirk Haines
 
N

Name Name

I know this sounds nieve, but is there a way to do what I want without
requiring an external gem, and without that extremely long code on the
secnod post. I would really prefer just to use native ruby.

Be able to concurrently run a process (that could potentially block
forever or run forever) written in another language and having the
ability to stop it at anytime.

a=IO.popen (program_name)
Process.kill(9,a.pid)

works, but it won't log to a file

a=IO.popen(program_name > logfile)
Process.kill(9, a.pid)

spawns two processes and does not kill both.

I need something to be able to do the latter.

thanks
 
N

Name Name

Is there a command in ruby that when given the pid , it will terminate
all children processes of that pid including itself.

thanks
 
N

Name Name

Joel, if you do t.status after you thread off the system, you'll notice
that it says sleeping instead of running. Pretty much the thread will
make the system call and then wait on that system call to return. So
that thread is owning that process in some respects, but killing that
thread will in no means kill the process, since that process is on its
own now.

On an unrelated note, does anyone know how to kill all children pids
including itself when one is given a pid? If that question is answered,
I think my post will be answered.
 
A

ara.t.howard

Joel, if you do t.status after you thread off the system, you'll notice
that it says sleeping instead of running. Pretty much the thread will
make the system call and then wait on that system call to return. So
that thread is owning that process in some respects, but killing that
thread will in no means kill the process, since that process is on its
own now.

On an unrelated note, does anyone know how to kill all children pids
including itself when one is given a pid? If that question is answered,
I think my post will be answered.

harp:~ > cat a.rb
Thread.new{ system 'sleep 60' }
sleep 1
system 'ps'
Process.kill -9, Process.pid

harp:~ > ruby a.rb
PID TTY TIME CMD
15149 pts/2 00:00:00 bash
6308 pts/2 00:00:00 ruby
6309 pts/2 00:00:00 sleep
6310 pts/2 00:00:00 ps
Killed

harp:~ > ps
PID TTY TIME CMD
15149 pts/2 00:00:00 bash
6311 pts/2 00:00:00 ps



-a
 
J

Joel VanderWerf

Name said:
Joel, if you do t.status after you thread off the system, you'll notice
that it says sleeping instead of running. Pretty much the thread will
make the system call and then wait on that system call to return. So
that thread is owning that process in some respects, but killing that
thread will in no means kill the process, since that process is on its
own now.

Sure, that's why the Process.wait call hangs the program until you
interrupt it.

The thread owns the process in one sense: the thread continues (and in
this case finishes) when the process exits. I'm just wondering whether
it would make sense for the thread to be more closely associated with
the process. Maybe killing the thread should not kill the process, but
instead there should be an additional status result that tells you
whether the thread is sleeping waiting for an external process and if so
the command line and the pid.
 

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

Forum statistics

Threads
474,208
Messages
2,571,082
Members
47,683
Latest member
AustinFairchild

Latest Threads

Top