Thread control

I am trying to write a ruby script (Ruby 1.7.2 mswin32) which does the
following:

  1. Spawn a few threads (say 3, for the time being) each of which invokes an
    external program using the backquotes.
  2. Let the main thread continue till either all the threads are done
    executing OR some external event occurs (like deletion of a file by another
    program).

I cannot seem to make it work (may be because thread implementation in Ruby
is not “native” ?).
Please help. TIA,
– Shanko

Here is my broken script:

------------------------------------------------------

cmds = [
“ping 10.0.0.0 -n 30 -w 1000 > NUL”,
“ping 10.0.0.0 -n 60 -w 1000 > NUL”,
“ping 10.0.0.0 -n 90 -w 1000 > NUL”
]

out = []
threads = []

for c in cmds
threads << Thread.new© { |myCmd|
puts "#{myCmd}"
out << #{myCmd}
}
end

puts threads.length.to_s + ’ threads running’

begin
i = 0
threads.each { |t| i += 1 if t.stop? }
puts echo %TIME%
b = File.exists?(“C:\junk\tmp_0.txt”)
puts i.to_s + ‘:’ + File.mtime(“C:\junk\tmp_0.txt”).to_s if $DEBUG
and b
$stdout.flush
end until (i == threads.length) && (not b)
puts out if $DEBUG

------------------------------------------------------

You may not need threads.
Have you tried using fork, wait2 and redirect?

I am refactoring some code right now that does this.
I’ll post it after I clean it up a little if you
want to see it.

Jim

···

On Tue, Aug 20, 2002 at 11:29:23AM +0900, Shashank Date wrote:

I am trying to write a ruby script (Ruby 1.7.2 mswin32) which does the
following:

  1. Spawn a few threads (say 3, for the time being) each of which invokes an
    external program using the backquotes.
  2. Let the main thread continue till either all the threads are done
    executing OR some external event occurs (like deletion of a file by another
    program).

I cannot seem to make it work (may be because thread implementation in Ruby
is not “native” ?).
Please help. TIA,
– Shanko


Jim Freeze
If only I had something clever to say for my comment…
~

Sorry for the mistake,

the second last line in the script should be changed from:
end until (i == threads.length) && (not b)
to:
end until (i == threads.length) || (not b)

“Shashank Date” ADATE@kc.rr.com wrote in message
news:%zh89.14824$Hf.497645@twister.kc.rr.com…

I am trying to write a ruby script (Ruby 1.7.2 mswin32) which does the
following:

  1. Spawn a few threads (say 3, for the time being) each of which invokes
    an
    external program using the backquotes.
  2. Let the main thread continue till either all the threads are done
    executing OR some external event occurs (like deletion of a file by
    another
    program).

I cannot seem to make it work (may be because thread implementation in
Ruby

···

is not “native” ?).
Please help. TIA,
– Shanko

Here is my broken script:

------------------------------------------------------

cmds = [
“ping 10.0.0.0 -n 30 -w 1000 > NUL”,
“ping 10.0.0.0 -n 60 -w 1000 > NUL”,
“ping 10.0.0.0 -n 90 -w 1000 > NUL”
]

out =
threads =

for c in cmds
threads << Thread.new(c) { |myCmd|
puts “#{myCmd}”
out << #{myCmd}
}
end

puts threads.length.to_s + ’ threads running’

begin
i = 0
threads.each { |t| i += 1 if t.stop? }
puts echo %TIME%
b = File.exists?(“C:\junk\tmp_0.txt”)
puts i.to_s + ‘:’ + File.mtime(“C:\junk\tmp_0.txt”).to_s if $DEBUG
and b
$stdout.flush
end until (i == threads.length) && (not b)
puts out if $DEBUG

------------------------------------------------------

Hi,

“Shashank Date” ADATE@kc.rr.com wrote in message
news:%zh89.14824$Hf.497645@twister.kc.rr.com…

I am trying to write a ruby script (Ruby 1.7.2 mswin32) which does the
following:

  1. Spawn a few threads (say 3, for the time being) each of which invokes
    an
    external program using the backquotes.
  2. Let the main thread continue till either all the threads are done
    executing OR some external event occurs (like deletion of a file by
    another
    program).

I cannot seem to make it work (may be because thread implementation in
Ruby
is not “native” ?).
Please help. TIA,
– Shanko

Here is my broken script:

Replace

     "ping 10.0.0.0 -n 30 -w 1000 > NUL",
     "ping 10.0.0.0 -n 60 -w 1000 > NUL",
     "ping 10.0.0.0 -n 90 -w 1000 > NUL"

with

     "ping 10.0.0.0 -n 30 -w 1000 ",
     "ping 10.0.0.0 -n 60 -w 1000 ",
     "ping 10.0.0.0 -n 90 -w 1000 "

Park Heesob

Hi,

“Shashank Date” ADATE@kc.rr.com wrote in message
news:%zh89.14824$Hf.497645@twister.kc.rr.com…

I am trying to write a ruby script (Ruby 1.7.2 mswin32) which does the
following:

  1. Spawn a few threads (say 3, for the time being) each of which invokes
    an
    external program using the backquotes.
  2. Let the main thread continue till either all the threads are done
    executing OR some external event occurs (like deletion of a file by
    another
    program).

I cannot seem to make it work (may be because thread implementation in
Ruby
is not “native” ?).
Please help. TIA,
– Shanko

Here is my broken script:

------------------------------------------------------

cmds = [
“ping 10.0.0.0 -n 30 -w 1000 > NUL”,
“ping 10.0.0.0 -n 60 -w 1000 > NUL”,
“ping 10.0.0.0 -n 90 -w 1000 > NUL”
]

out =
threads =

for c in cmds
threads << Thread.new(c) { |myCmd|
puts “#{myCmd}”
out << #{myCmd}
}
end

puts threads.length.to_s + ’ threads running’

begin
i = 0
threads.each { |t| i += 1 if t.stop? }
puts echo %TIME%
b = File.exists?(“C:\junk\tmp_0.txt”)
puts i.to_s + ‘:’ + File.mtime(“C:\junk\tmp_0.txt”).to_s if $DEBUG
and b
$stdout.flush
end until (i == threads.length) && (not b)
puts out if $DEBUG

------------------------------------------------------

Try this

···

#=================================================
require ‘Win32API’

OpenProcess = Win32API.new(“kernel32”,“OpenProcess”,[‘L’,‘L’,‘L’],‘L’)
TerminateProcess = Win32API.new(“kernel32”,“TerminateProcess”,[‘L’,‘L’],‘L’)

puts 'Start: ’ + echo %TIME%
cmds = [
"ping 10.0.0.0 -n 30 -w 1000 ",
"ping 10.0.0.0 -n 60 -w 1000 ",
"ping 10.0.0.0 -n 90 -w 1000 "
]

out =
threads =

for c in cmds
threads << Thread.new(c) { |myCmd|
puts “#{myCmd}”
f = IO.popen(myCmd)
Thread.current[‘pid’] = f.pid
while not f.eof?
out << f.gets
end
}
end

puts threads.length.to_s + ’ threads running’

begin
i = 0
threads.each { |t| i += 1 if t.stop? }
puts echo %TIME%
b = File.exists?(“C:junkj0.txt”)
puts i.to_s + ‘:’ + File.mtime(“C:junkj0.txt”).to_s if $DEBUG and b
$stdout.flush
end until (i == threads.length) || (not b)

puts 'Mid: ’ + echo %TIME%
threads.each { |t|
TerminateProcess.Call(OpenProcess.Call(1,0,t[‘pid’]),0) if t.alive?
}

puts 'Stop: ’ + echo %TIME%
puts out if $DEBUG
#=============================================================

Park Heesob.

It is my understanding that fork/wait2 is not supported on Windows
(mswin32).

“Jim Freeze” jfreeze@freebsdportal.com wrote in message
news:20020819223909.A12645@freebsdportal.com

I am trying to write a ruby script (Ruby 1.7.2 mswin32) which does the
following:

  1. Spawn a few threads (say 3, for the time being) each of which invokes
    an
    external program using the backquotes.
  2. Let the main thread continue till either all the threads are done
    executing OR some external event occurs (like deletion of a file by
    another
    program).

I cannot seem to make it work (may be because thread implementation in
Ruby

···

On Tue, Aug 20, 2002 at 11:29:23AM +0900, Shashank Date wrote:

is not “native” ?).
Please help. TIA,
– Shanko

You may not need threads.
Have you tried using fork, wait2 and redirect?

I am refactoring some code right now that does this.
I’ll post it after I clean it up a little if you
want to see it.

Jim


Jim Freeze
If only I had something clever to say for my comment…
~

Hi Park,

Replace

     "ping 10.0.0.0 -n 30 -w 1000 > NUL",
     "ping 10.0.0.0 -n 60 -w 1000 > NUL",
     "ping 10.0.0.0 -n 90 -w 1000 > NUL"

with

     "ping 10.0.0.0 -n 30 -w 1000 ",
     "ping 10.0.0.0 -n 60 -w 1000 ",
     "ping 10.0.0.0 -n 90 -w 1000 "

That does seem to make a difference … the main program does end as I
expected it to.

But what if I want to collect the partial output of my threads (in this case
“ping” commands) say in a file or something.
The array out that I have used does not seem to get it.

And the ping processes are still running … how do I get rid of them.

(I realize that this is a different issue now ;-)).

Thanks for the suggestion, though.

– Shanko

Hi Park,

Thanks again !

This comes very close to what I want since it not only kills the threads but
also the “ping” processes which were, in the earlier versions, still running
in the background.

Now my final stumbling block is that in the real case the “ping” commands
will be replaced by other commands which do not produce any output and hence
the control never transfers to the main thread. (Which is why I had “ping
10.0.0.0 -n 10 -w 1000 > NUL” in the first place to simulate long running
processes with no output.)

If only we could force control back to the main thread, we would be thru !
Very eager to hear from you …
– Shanko

“Park Heesob” phasis@kornet.net wrote in message
news:B6D89.2$J5.96@news.hananet.net

Hi,

“Shashank Date” ADATE@kc.rr.com wrote in message
news:%zh89.14824$Hf.497645@twister.kc.rr.com…

I am trying to write a ruby script (Ruby 1.7.2 mswin32) which does the
following:

  1. Spawn a few threads (say 3, for the time being) each of which invokes
    an
    external program using the backquotes.
  2. Let the main thread continue till either all the threads are done
    executing OR some external event occurs (like deletion of a file by
    another
    program).

I cannot seem to make it work (may be because thread implementation in
Ruby
is not “native” ?).
Please help. TIA,
– Shanko

Here is my broken script:

------------------------------------------------------

cmds = [
“ping 10.0.0.0 -n 30 -w 1000 > NUL”,
“ping 10.0.0.0 -n 60 -w 1000 > NUL”,
“ping 10.0.0.0 -n 90 -w 1000 > NUL”
]

out =
threads =

for c in cmds
threads << Thread.new(c) { |myCmd|
puts “#{myCmd}”
out << #{myCmd}
}
end

puts threads.length.to_s + ’ threads running’

begin
i = 0
threads.each { |t| i += 1 if t.stop? }
puts echo %TIME%
b = File.exists?(“C:\junk\tmp_0.txt”)
puts i.to_s + ‘:’ + File.mtime(“C:\junk\tmp_0.txt”).to_s if
$DEBUG
and b
$stdout.flush
end until (i == threads.length) && (not b)
puts out if $DEBUG

------------------------------------------------------

Try this

#=================================================
require ‘Win32API’

OpenProcess = Win32API.new(“kernel32”,“OpenProcess”,[‘L’,‘L’,‘L’],‘L’)
TerminateProcess =
Win32API.new(“kernel32”,“TerminateProcess”,[‘L’,‘L’],‘L’)

···

puts 'Start: ’ + echo %TIME%
cmds = [
"ping 10.0.0.0 -n 30 -w 1000 ",
"ping 10.0.0.0 -n 60 -w 1000 ",
"ping 10.0.0.0 -n 90 -w 1000 "
]

out =
threads =

for c in cmds
threads << Thread.new(c) { |myCmd|
puts “#{myCmd}”
f = IO.popen(myCmd)
Thread.current[‘pid’] = f.pid
while not f.eof?
out << f.gets
end
}
end

puts threads.length.to_s + ’ threads running’

begin
i = 0
threads.each { |t| i += 1 if t.stop? }
puts echo %TIME%
b = File.exists?(“C:junkj0.txt”)
puts i.to_s + ‘:’ + File.mtime(“C:junkj0.txt”).to_s if $DEBUG and b
$stdout.flush
end until (i == threads.length) || (not b)

puts 'Mid: ’ + echo %TIME%
threads.each { |t|
TerminateProcess.Call(OpenProcess.Call(1,0,t[‘pid’]),0) if t.alive?
}

puts 'Stop: ’ + echo %TIME%
puts out if $DEBUG
#=============================================================

Park Heesob.

Hi,

···

At Wed, 21 Aug 2002 11:51:31 +0900, Park Heesob wrote:

threads.each { |t|
TerminateProcess.Call(OpenProcess.Call(1,0,t[‘pid’]),0) if t.alive?
}

This wouldn’t work in 1.7 under Windows 9x, since pid is
negated. Use Process.kill instead, it does same thing and
error checks, and is even portable.

Process.kill(:INT, *threads.collect {|t| t[‘pid’]})


Nobu Nakada

Hi,

“Shashank Date” ADATE@kc.rr.com wrote in message
news:oqr89.15682$Hf.526056@twister.kc.rr.com

Hi Park,

That does seem to make a difference … the main program does end as I
expected it to.

But what if I want to collect the partial output of my threads (in this
case
“ping” commands) say in a file or something.
The array out that I have used does not seem to get it.

And the ping processes are still running … how do I get rid of them.

(I realize that this is a different issue now ;-)).

Thanks for the suggestion, though.

– Shanko

How about this modified version?

------------------------------------------------------

cmds = [
"ping 10.0.0.0 -n 30 -w 1000 ",
"ping 10.0.0.0 -n 60 -w 1000 ",
"ping 10.0.0.0 -n 90 -w 1000 "
]

out =
threads =

for c in cmds
threads << Thread.new(c) { |myCmd|
puts “#{myCmd}”
f = IO.popen(myCmd)
Thread.current[“f”] = f
while not f.eof?
out << f.gets
end
}
end

puts threads.length.to_s + ’ threads running’

begin
i = 0
threads.each { |t| i += 1 if t.stop? }
puts echo %TIME%
b = File.exists?(“C:\junk\tmp_0.txt”)
puts i.to_s + ‘:’ + File.mtime(“C:\junk\tmp_0.txt”).to_s if $DEBUG
and b
$stdout.flush
end until (i == threads.length) || (not b)

threads.each { |t|
if t.alive?
t[“f”].close
t.exit
end
}

puts out if $DEBUG

------------------------------------------------------

Park Heesob

Hi,

“Shashank Date” ADATE@kc.rr.com wrote in message
news:7NE89.43554$mj7.805851@twister.rdc-kc.rr.com

Hi Park,

Thanks again !

This comes very close to what I want since it not only kills the threads
but
also the “ping” processes which were, in the earlier versions, still
running
in the background.

Now my final stumbling block is that in the real case the “ping” commands
will be replaced by other commands which do not produce any output and
hence
the control never transfers to the main thread. (Which is why I had “ping
10.0.0.0 -n 10 -w 1000 > NUL” in the first place to simulate long running
processes with no output.)

If only we could force control back to the main thread, we would be thru !
Very eager to hear from you …

Sorry, I can’t understand what you mean.
Can you explain with some psedo-code?

– Shanko

Park Heesob.

Hi,
nobu.nokada@softhome.net wrote in message
news:200208210542.g7L5gnP30363@sharui.nakada.kanuma.tochigi.jp…

Hi,

threads.each { |t|
TerminateProcess.Call(OpenProcess.Call(1,0,t[‘pid’]),0) if t.alive?
}

This wouldn’t work in 1.7 under Windows 9x, since pid is
negated. Use Process.kill instead, it does same thing and
error checks, and is even portable.

Process.kill(:INT, *threads.collect {|t| t[‘pid’]})

Thanks, but it fails with Errno::E087 in Windows XP.


Nobu Nakada

Park Heesob.

···

At Wed, 21 Aug 2002 11:51:31 +0900, > Park Heesob wrote:

Hi,

Thanks for the prompt response… and for staying with me in difficult times
:wink:

Sorry, I can’t understand what you mean.
Can you explain with some psedo-code?

Well, if you change the code back to it’s first version where:

cmds = [
“ping 10.0.0.0 -n 30 -w 1000 > NUL”,
“ping 10.0.0.0 -n 60 -w 1000 > NUL”,
“ping 10.0.0.0 -n 90 -w 1000 > NUL”
]

you will see that the threads are run sequentially and the program ends
after (30 + 60 + 90) seconds.
This is probably because the f.gets in the “while not f.eof?” loop for each
thread stalls.

See what I mean ?
– Shanko

Hi,

···

At Wed, 21 Aug 2002 16:12:19 +0900, Park Heesob wrote:

threads.each { |t|
TerminateProcess.Call(OpenProcess.Call(1,0,t[‘pid’]),0) if t.alive?
}

This wouldn’t work in 1.7 under Windows 9x, since pid is
negated. Use Process.kill instead, it does same thing and
error checks, and is even portable.

Process.kill(:INT, *threads.collect {|t| t[‘pid’]})

Thanks, but it fails with Errno::E087 in Windows XP.

Apparently, there’re some bugs. What’s your ruby version and
release date?


Nobu Nakada

Hi,

“Shashank Date” ADATE@kc.rr.com wrote in message
news:XCF89.44011$mj7.808228@twister.rdc-kc.rr.com

Well, if you change the code back to it’s first version where:

cmds = [
“ping 10.0.0.0 -n 30 -w 1000 > NUL”,
“ping 10.0.0.0 -n 60 -w 1000 > NUL”,
“ping 10.0.0.0 -n 90 -w 1000 > NUL”
]

you will see that the threads are run sequentially and the program ends
after (30 + 60 + 90) seconds.
This is probably because the f.gets in the “while not f.eof?” loop for
each
thread stalls.

See what I mean ?
Yes, I see.

Here is new version.
Caution: Do not use redirection like “ping 10.0.0.0 -n 30 -w 1000 > NUL”.

···

#========================================================
require ‘Win32API’

OpenProcess = Win32API.new(“kernel32”,“OpenProcess”,[‘L’,‘L’,‘L’],‘L’)
TerminateProcess = Win32API.new(“kernel32”,“TerminateProcess”,[‘L’,‘L’],‘L’)
WaitForSingleObject =
Win32API.new(“kernel32”,“WaitForSingleObject”,[‘L’,‘L’],‘L’)

puts 'Start: ’ + echo %TIME%
cmds = [
“ruby -e ‘sleep 30’”, # long running processes with no output
“ruby -e ‘sleep 60’”, # long running processes with no output
“ruby -e ‘sleep 90’” # long running processes with no output
]

out =
threads =

for c in cmds
threads << Thread.new(c) { |myCmd|
puts “#{myCmd}”
f = IO.popen(myCmd)
hProcess = OpenProcess.Call(0x100001, 1 ,f.pid)
Thread.current[‘pid’] = hProcess
while true
a = WaitForSingleObject.Call( hProcess, 0);
break if a==0
end
}
end

puts threads.length.to_s + ’ threads running’

begin
i = 0
threads.each { |t| i += 1 if t.stop? }
puts echo %TIME%
b = File.exists?(“C:junkj0.txt”)
puts i.to_s + ‘:’ + File.mtime(“C:junkj0.txt”).to_s if $DEBUG and b
$stdout.flush
end until (i == threads.length) || (not b)
puts 'Mid: ’ + echo %TIME%
threads.each { |t|
TerminateProcess.Call(t[‘pid’],0) if t.alive?
}

puts 'Stop: ’ + echo %TIME%
puts out if $DEBUG
#===========================================

Park Heesob.

Hi,

nobu.nokada@softhome.net wrote in message
news:200208242349.g7ONnYP24335@sharui.nakada.kanuma.tochigi.jp…

Hi,

threads.each { |t|
TerminateProcess.Call(OpenProcess.Call(1,0,t[‘pid’]),0) if
t.alive?
}

This wouldn’t work in 1.7 under Windows 9x, since pid is
negated. Use Process.kill instead, it does same thing and
error checks, and is even portable.

Process.kill(:INT, *threads.collect {|t| t[‘pid’]})

Thanks, but it fails with Errno::E087 in Windows XP.

Apparently, there’re some bugs. What’s your ruby version and
release date?

D:\work>ruby -v
ruby 1.7.2 (2002-07-02) [i386-mswin32]


Nobu Nakada

Park Heesob

···

At Wed, 21 Aug 2002 16:12:19 +0900, > Park Heesob wrote:

That does it ! You ought to be in the “Ruby’s Hall of Fame”.
Thank you very much for the continuous support …hopefully someday I will
be able to reciprocate the efforts.
Have a nice one :smiley:

– Shanko

P.S> I still do not understand why the redirection on ping does not work
though.

“Park Heesob” phasis@kornet.net wrote in message
news:dsY89.77$J5.62@news.hananet.net

Hi,

“Shashank Date” ADATE@kc.rr.com wrote in message
news:XCF89.44011$mj7.808228@twister.rdc-kc.rr.com

Well, if you change the code back to it’s first version where:

cmds = [
“ping 10.0.0.0 -n 30 -w 1000 > NUL”,
“ping 10.0.0.0 -n 60 -w 1000 > NUL”,
“ping 10.0.0.0 -n 90 -w 1000 > NUL”
]

you will see that the threads are run sequentially and the program ends
after (30 + 60 + 90) seconds.
This is probably because the f.gets in the “while not f.eof?” loop for
each
thread stalls.

See what I mean ?
Yes, I see.

Here is new version.
Caution: Do not use redirection like “ping 10.0.0.0 -n 30 -w 1000 > NUL”.

#========================================================
require ‘Win32API’

OpenProcess = Win32API.new(“kernel32”,“OpenProcess”,[‘L’,‘L’,‘L’],‘L’)
TerminateProcess =
Win32API.new(“kernel32”,“TerminateProcess”,[‘L’,‘L’],‘L’)

···

WaitForSingleObject =
Win32API.new(“kernel32”,“WaitForSingleObject”,[‘L’,‘L’],‘L’)

puts 'Start: ’ + echo %TIME%
cmds = [
“ruby -e ‘sleep 30’”, # long running processes with no output
“ruby -e ‘sleep 60’”, # long running processes with no output
“ruby -e ‘sleep 90’” # long running processes with no output
]

out =
threads =

for c in cmds
threads << Thread.new(c) { |myCmd|
puts “#{myCmd}”
f = IO.popen(myCmd)
hProcess = OpenProcess.Call(0x100001, 1 ,f.pid)
Thread.current[‘pid’] = hProcess
while true
a = WaitForSingleObject.Call( hProcess, 0);
break if a==0
end
}
end

puts threads.length.to_s + ’ threads running’

begin
i = 0
threads.each { |t| i += 1 if t.stop? }
puts echo %TIME%
b = File.exists?(“C:junkj0.txt”)
puts i.to_s + ‘:’ + File.mtime(“C:junkj0.txt”).to_s if $DEBUG and b
$stdout.flush
end until (i == threads.length) || (not b)
puts 'Mid: ’ + echo %TIME%
threads.each { |t|
TerminateProcess.Call(t[‘pid’],0) if t.alive?
}

puts 'Stop: ’ + echo %TIME%
puts out if $DEBUG
#===========================================

Park Heesob.

Hi,

“Shashank Date” ADATE@kc.rr.com wrote in message
news:XVZ89.50893$mj7.854713@twister.rdc-kc.rr.com

That does it ! You ought to be in the “Ruby’s Hall of Fame”.
Thank you very much for the continuous support …hopefully someday I will
be able to reciprocate the efforts.
Have a nice one :smiley:

Oh, no, not at all. It’s my pleasure.

– Shanko

P.S> I still do not understand why the redirection on ping does not work
though.

If you use command “ping 10.0.0.0 -n 90 -w 1000 > NUL”,
it creates two processes ‘cmd.exe’ and ‘ping.exe’.
I can get pid of ‘cmd.exe’, but not pid of ‘ping.exe’.
If you can find pid of ‘ping.exe’, there’s no problem.
It’s your chance to finish this program perfectly.

Park Heesob.

Hi Park,

If you use command “ping 10.0.0.0 -n 90 -w 1000 > NUL”,
it creates two processes ‘cmd.exe’ and ‘ping.exe’.
I can get pid of ‘cmd.exe’, but not pid of ‘ping.exe’.

If you download pstools from:

http://www.sysinternals.com/ntw2k/freeware/pstools.shtml

and run “pslist -t” it shows you the process tree.
(There is also a Win2K ResourceKit utility “ptree” which I believe does the
same thing).

Which tells me that there is Windows API which exposes the parent-child
relationship of processes.
May be that is what is needed to finish it off.

If you can find pid of ‘ping.exe’, there’s no problem.
It’s your chance to finish this program perfectly.

Assuming I get hold of the pid for “ping”, I guess, I will have to replace
the following line of your modification:

hProcess = OpenProcess.Call(0x100001, 1 , f.pid)
^^^^
with:

hProcess = OpenProcess.Call(0x100001, 1 , ping_pid)

Right ?

I will try … but I am not as comfortable with Windows API as you are …so
I might call for help again :wink:

Park Heesob.

Thanks a lot, again, Park.

– Shanko

Hi,

“Shashank Date” ADATE@kc.rr.com wrote in message
news:q1599.19624$Hf.636502@twister.kc.rr.com

Hi Park,

If you use command “ping 10.0.0.0 -n 90 -w 1000 > NUL”,
it creates two processes ‘cmd.exe’ and ‘ping.exe’.
I can get pid of ‘cmd.exe’, but not pid of ‘ping.exe’.

If you download pstools from:

http://www.sysinternals.com/ntw2k/freeware/pstools.shtml

and run “pslist -t” it shows you the process tree.
(There is also a Win2K ResourceKit utility “ptree” which I believe does
the
same thing).

Which tells me that there is Windows API which exposes the parent-child
relationship of processes.
May be that is what is needed to finish it off.

If you can find pid of ‘ping.exe’, there’s no problem.
It’s your chance to finish this program perfectly.

Assuming I get hold of the pid for “ping”, I guess, I will have to replace
the following line of your modification:

hProcess = OpenProcess.Call(0x100001, 1 , f.pid)
^^^^
with:

hProcess = OpenProcess.Call(0x100001, 1 , ping_pid)

Right ?

I will try … but I am not as comfortable with Windows API as you are
…so
I might call for help again :wink:

Thanks for your information.
Here is my final version.

···

#===========================================================================

require ‘Win32API’

OpenProcess = Win32API.new(“kernel32”,“OpenProcess”,[‘L’,‘L’,‘L’],‘L’)
TerminateProcess = Win32API.new(“kernel32”,“TerminateProcess”,[‘L’,‘L’],‘L’)
WaitForSingleObject =
Win32API.new(“kernel32”,“WaitForSingleObject”,[‘L’,‘L’],‘L’)
RegCloseKey = Win32API.new(“advapi32”,“RegCloseKey”,[‘L’],‘L’)
RegOpenKeyEx =
Win32API.new(“advapi32”,“RegOpenKeyEx”,[‘L’,‘P’,‘L’,‘L’,‘P’],‘L’)
RegQueryValueEx =
Win32API.new(“advapi32”,“RegQueryValueEx”,[‘L’,‘P’,‘L’,‘P’,‘P’,‘P’],‘L’)

INITIAL_SIZE = 51200
EXTEND_SIZE = 25600
REGKEY_PERF = “software\microsoft\windows
nt\currentversion\perflib\009”
REGSUBKEY_COUNTERS = “Counters”
KEY_READ = 0x20019;
ERROR_MORE_DATA = 234
HKEY_LOCAL_MACHINE = 0x80000002
HKEY_PERFORMANCE_DATA = 0x80000004

return hash key : parent pids, value : array of child pids

def getpids()

result = Hash.new

hKeyNames = “\0”*4
rc = RegOpenKeyEx.Call(
HKEY_LOCAL_MACHINE,REGKEY_PERF,0,KEY_READ,hKeyNames)
hKeyNames = hKeyNames.unpack(‘L’)[0]
dwSize = “\0”*4
rc = RegQueryValueEx.Call( hKeyNames,REGSUBKEY_COUNTERS,0,0,0,dwSize)
dwSize2 = dwSize.unpack(‘L’)[0]
buf = “\0” * dwSize2
rc = RegQueryValueEx.Call( hKeyNames,REGSUBKEY_COUNTERS,0,0,buf,dwSize)

buf2 = Hash[*buf.split(“\0”)]

proidx = buf2.index(“Process”).to_i
pididx = buf2.index(“ID Process”).to_i
ppididx = buf2.index(“Creating Process ID”).to_i

buf = “\0” * INITIAL_SIZE
szSubKey = proidx.to_s
dwSize = [INITIAL_SIZE]

while true
dwSize2 = dwSize.pack(‘L’)
rc = RegQueryValueEx.Call( HKEY_PERFORMANCE_DATA,szSubKey,0,0,buf,dwSize2)

break if rc==0

if rc == ERROR_MORE_DATA
dwSize[0] += EXTEND_SIZE;
buf = “\0” * dwSize[0]
else
exit
end
end

pObj = buf[buf[24,4].unpack(‘L’)[0] … -1]

pCounterDef = pObj[pObj[8,4].unpack(‘L’)[0] … -1]
numCounters = pObj[32,4].unpack(‘L’)[0]

for i in 0 … numCounters
counterNameTitleIndex = pCounterDef[4,4].unpack(‘L’)[0]
if counterNameTitleIndex == pididx
pidcounter = pCounterDef[36,4].unpack(‘L’)[0]
end
if counterNameTitleIndex == ppididx
ppidcounter = pCounterDef[36,4].unpack(‘L’)[0]
end
pCounterDef = pCounterDef[40…-1]
end

dwNumTasks = pObj[40,4].unpack(‘L’)[0]

pInst = pObj[pObj[4,4].unpack(‘L’)[0] … -1]

for i in 0 … dwNumTasks
pCounter = pInst[pInst[0,4].unpack(‘L’)[0] … -1]
pid = pCounter[pidcounter,4].unpack(‘L’)[0]
ppid = pCounter[ppidcounter,4].unpack(‘L’)[0]

if ppid>0
if result[ppid] == nil
result[ppid] = [pid]
else
result[ppid].push(pid)
end
end

pInst = pCounter[pCounter[0,4].unpack(‘L’)[0] … -1]
end

RegCloseKey.Call( hKeyNames )
RegCloseKey.Call( HKEY_PERFORMANCE_DATA )
result

end

puts 'Start: ’ + echo %TIME%
cmds = [
“ping 10.0.0.0 -n 30 -w 1000 >NUL”,
“ping 10.0.0.0 -n 60 -w 1000 >NUL”,
“ping 10.0.0.0 -n 90 -w 1000 >NUL”
]

out =
threads =

for c in cmds
threads << Thread.new(c) { |myCmd|
puts “#{myCmd}”
f = IO.popen(myCmd)
hProcess = OpenProcess.Call(0x00100001, 0 ,f.pid)
Thread.current[‘pid’] = f.pid
Thread.current[‘hProcess’] = hProcess
while true
a = WaitForSingleObject.Call( hProcess, 0 );
break if a==0
end
}
end

puts threads.length.to_s + ’ threads running’

begin
i = 0
threads.each { |t| i += 1 if t.stop? }
puts echo %TIME%
b = File.exists?(“C:junkj0.txt”)
puts i.to_s + ‘:’ + File.mtime(“C:junkj0.txt”).to_s if $DEBUG and b
$stdout.flush
end until (i == threads.length) || (not b)

pids = getpids

puts 'Mid: ’ + echo %TIME%
threads.each { |t|
if t.alive?
pids[t[‘pid’]].each {|pid|
TerminateProcess.Call(OpenProcess.Call(0x00100001, 0 ,pid),0) }
TerminateProcess.Call(t[‘hProcess’],0)
end

}

puts 'Stop: ’ + echo %TIME%
puts out if $DEBUG
#=================================================================

Park Heesob