Start a program, get it's output, then kill it. while "multithreading"

Hi everybody,

i'd like to program a gui for iperf (http://sourceforge.net/projects/
iperf), it should run under windows And *NIX and I'm using fox as my
gui toolkit, I'll use some extra calculations to get the parameters,
that's why I can't use an already existing gui for iperf.
I already designed the gui and I'm now moving to connect the different
widgets to it's functions.
After you set all your parameters (size of packet, bandwith,
time, ...) I want to press a button and it should start iperf and
parallely read the it's output, so I can display some statistics
(running time and, on server side, the packet loss, maybe more).
So what should I program to do this?
I read about multithreading, IO.popen would be perfect, but how can I
kill iperf when I want to quit, before iperf ran out of time?
I think threads could also work (especially because one can kill
threads, if no longer used so the program would be terminated), but
what do I do to start the iperf?
I'm new to this subject and would appreciate any help on this!

Thanks in advance,

Deadolus

First of all killing a thread won't help because the process is in no
way attached to a Ruby thread (btw, this would also be true if Ruby
was using native threads).

You can however use a thread to read output from IO.popen. For
example, you could stuff lines into a Queue which is read from your UI
thread and displayed. Or whatever you want do do with it.

About the killing I am not sure. With a quick check I did not find a
proper way to get the PID of the child process with IO.popen. If
there is no way you could use popen with "-" as command (i.e. start a
child process), have that writ out the current PID (in $$) to stdout
and exec the process you want to start. The parent would then have to
read the child PID first and remember it somewhere.

Kind regards

robert

···

2008/1/18, Deadolus <deadolus@gmail.com>:

i'd like to program a gui for iperf (Best Open Source Mac Software 2024
iperf), it should run under windows And *NIX and I'm using fox as my
gui toolkit, I'll use some extra calculations to get the parameters,
that's why I can't use an already existing gui for iperf.
I already designed the gui and I'm now moving to connect the different
widgets to it's functions.
After you set all your parameters (size of packet, bandwith,
time, ...) I want to press a button and it should start iperf and
parallely read the it's output, so I can display some statistics
(running time and, on server side, the packet loss, maybe more).
So what should I program to do this?
I read about multithreading, IO.popen would be perfect, but how can I
kill iperf when I want to quit, before iperf ran out of time?
I think threads could also work (especially because one can kill
threads, if no longer used so the program would be terminated), but
what do I do to start the iperf?

--
use.inject do |as, often| as.you_can - without end

I think I found the solution, this is a example script:

io = IO.popen("ping google.ch") #open a new io
thread = Thread.new(io) {while !io.closed? do Thread.current["line"] =
io.readline end}#ALWAYS read current line of io
i=0 #example code...
while i<10 do
puts thread["line"]
puts thread.status #puts out "sleep", so it's running...
i+=1
sleep(1)
end
io.close #close io
thread.status #puts out "nil" so it's terminated

Seems like you easily can close a io just by "close".
At least it isn't in my ps aux list any more...
But I just tested under linux so far, so I can't say if this also
works under windows (I currently have some problems with my windows
box).
What do you think about this solution?
If anyone has a better solution, I'm still interested....

···

On 18 Jan., 11:56, Robert Klemme <shortcut...@googlemail.com> wrote:

2008/1/18, Deadolus <deado...@gmail.com>:

> i'd like to program a gui for iperf (Best Open Source Mac Software 2024
> iperf), it should run under windows And *NIX and I'm using fox as my
> gui toolkit, I'll use some extra calculations to get the parameters,
> that's why I can't use an already existing gui for iperf.
> I already designed the gui and I'm now moving to connect the different
> widgets to it's functions.
> After you set all your parameters (size of packet, bandwith,
> time, ...) I want to press a button and it should start iperf and
> parallely read the it's output, so I can display some statistics
> (running time and, on server side, the packet loss, maybe more).
> So what should I program to do this?
> I read about multithreading, IO.popen would be perfect, but how can I
> kill iperf when I want to quit, before iperf ran out of time?
> I think threads could also work (especially because one can kill
> threads, if no longer used so the program would be terminated), but
> what do I do to start the iperf?

First of all killing a thread won't help because the process is in no
way attached to a Ruby thread (btw, this would also be true if Ruby
was using native threads).

You can however use a thread to read output from IO.popen. For
example, you could stuff lines into a Queue which is read from your UI
thread and displayed. Or whatever you want do do with it.

About the killing I am not sure. With a quick check I did not find a
proper way to get the PID of the child process with IO.popen. If
there is no way you could use popen with "-" as command (i.e. start a
child process), have that writ out the current PID (in $$) to stdout
and exec the process you want to start. The parent would then have to
read the child PID first and remember it somewhere.

Kind regards

robert

--
use.inject do |as, often| as.you_can - without end

It's a little hard to find until you already know where it is, but
IO#pid might come in handy here :slight_smile:

···

On Fri, Jan 18, 2008 at 07:56:34PM +0900, Robert Klemme wrote:

2008/1/18, Deadolus <deadolus@gmail.com>:

...
I read about multithreading, IO.popen would be perfect, but how can I
kill iperf when I want to quit, before iperf ran out of time?

...

About the killing I am not sure. With a quick check I did not find
a proper way to get the PID of the child process with IO.popen. If
...

--
Stephen Lewis

Thanks! I use #popen too infrequently and when I use it I do not normally fiddle with the process directly.

Kind regards

  robert

···

On 18.01.2008 21:18, Stephen Lewis wrote:

On Fri, Jan 18, 2008 at 07:56:34PM +0900, Robert Klemme wrote:

2008/1/18, Deadolus <deadolus@gmail.com>:

...
I read about multithreading, IO.popen would be perfect, but how can I
kill iperf when I want to quit, before iperf ran out of time?

...

About the killing I am not sure. With a quick check I did not find
a proper way to get the PID of the child process with IO.popen. If
...

It's a little hard to find until you already know where it is, but
IO#pid might come in handy here :slight_smile:

I wasn't really happy about my solution, so I continued
experimenting.
I now have something, which I'm quite happy about, I'll post it here,
maybe some people have the same problems as I had.
I expanded the normal IO class:

#-------------------File
OwnIO.rb--------------------------------------
module OwnIO

  def killed? #nil if not killed, pid of IO if killed
    #I think we do not need this, please correct me, if I am wrong:
    #if(self.class != IO) then raise "Wrong type of Input variable, is
#{self.class} but should be IO!" end
    begin

      Process.waitpid(self.pid,Process::WNOHANG)
    rescue Errno::ECHILD #rescue if process is already terminated
      self.pid
    end
  end

  def kill #kill a IO (you still have to close it)
  Process.kill("KILL",self.pid)
  end

end

class IO #add my own IO module to the normal IO class
  include OwnIO
end

#---------EOF----------------------------------------------

And here is a short example script (how I'll implement it in my GUI
more or less):

#-------------------test.rb---------------------------------
require "OwnIO.rb"
STDOUT.sync = true
old = nil #old output
i = 0
io = IO.popen("ping google.ch")
io.sync = true

t = Thread.new() {while !io.killed? do Thread.current["line"] =
io.readline end}#first doesn't output all lines (Thread creation too
slow?)
while !io.killed? do
  if t["line"]!=old then#only react to changes of the line
    old = t["line"]
    puts t["line"]#puts the current line
    if i==20 then ##kill the io after 20 lines have been received
      io.kill
    end
    i+=1;
  end
end
puts "Killed"

···

On 19 Jan., 11:42, Robert Klemme <shortcut...@googlemail.com> wrote:

On 18.01.2008 21:18, Stephen Lewis wrote:

> On Fri, Jan 18, 2008 at 07:56:34PM +0900, Robert Klemme wrote:
>> 2008/1/18, Deadolus <deado...@gmail.com>:
>>> ...
>>> I read about multithreading, IO.popen would be perfect, but how can I
>>> kill iperf when I want to quit, before iperf ran out of time?
>> ...

>> About the killing I am not sure. With a quick check I did not find
>> a proper way togetthe PID of the child process with IO.popen. If
>> ...

>It'sa little hard to find until you already know whereitis, but
> IO#pid might come in handy here :slight_smile:

Thanks! I use #popen too infrequently and when I useitI do not
normally fiddle with the process directly.

Kind regards

        robert

#----------------------------
EOF----------------------------------------

The two functions "killed?" and "kill" are self explanatory, and seem
to work nice.
But at least "killed?" could have some improvements...
So if anybody has some improvements/suggestions to the code: go ahead!

Regards, Deadolus

if you care about stderr this won't work on windows or nix. threads, io, and guis will hang you on windows unless you really know what you are doing. for a portable way to start a process, capture it's stdout/stderr, and have a handle on the pid see my systemu lib - it's the only thing that'll work afaikt (read archives)

regards.

a @ http://drawohara.com/

···

On Jan 21, 2008, at 2:59 PM, Deadolus wrote:

So if anybody has some improvements/suggestions to the code: go ahead!

--
sleep is the best meditation.
h.h. the 14th dalai lama