Sockets, windoze, and threads

this works on *nix and might on windoze - i don’t have a box near so
cannot test… can someone give it a whirl and/or patch it to work?
it should simply run forever:

require ‘socket’

STDIN.sync = STDOUT.sync = STDERR.sync = true

class IO

windoze = RUBY_PLATFORM.include?(‘win32’)

unless windoze

def IO.socketpair(sync=true)
one, two = UNIXSocket.socketpair
one.sync = two.sync = true if sync
[one, two]
end

def IO.spawn cmd, options = {}
stdin = IO.socketpair
stdout = IO.socketpair
stderr = IO.socketpair

 if cid = fork
   stdin.last.close
   stdout.last.close
   stderr.last.close
 else
   STDIN.reopen stdin.last
   STDOUT.reopen stdout.last
   STDERR.reopen stderr.last
   exec cmd
 end

 at_exit do
   Process.kill(15, cid) rescue nil
   Process.kill(-9, cid) rescue nil
 end

 [ cid, stdin.first, stdout.first, stderr.first ]

end

else

def IO.socketpair(sync=true)
tcp = TCPServer.new(‘127.0.0.1’, 0)
one = TCPSocket.new(‘127.0.0.1’, tcp.addr[1])
two = tcp.accept and tcp.close
one.sync = two.sync = true if sync
[one, two]
end

def IO.spawn cmd, options = {}
stdin = IO.socketpair
stdout = IO.socketpair
stderr = IO.socketpair

 require 'win32/process'

 child = Process.create(
   'app_name' => "cmd /k #{cmd}", # the "/k" keeps the process

around when it’s done
‘process_inherit’ => true, # not yet sure if this one is
actually needed
‘thread_inherit’ => true, # not yet sure if this one is
actually needed
‘startup_info’ => {
‘stdin’ => stdin.last,
‘stdout’ => stdout.last,
‘stderr’ => stderr.last,
}
)

 at_exit do
   Process.TerminateProcess(child.process_handle,

child.process_id) rescue nil
Process.CloseHandle(child.process_handle) rescue nil
Process.kill(-9, child.process_id) rescue nil
end

 stdin.last.close
 stdout.last.close
 stderr.last.close

 [ child.process_id, stdin.first, stdout.first, stderr.first ]

end

end

end

try to clog the pipes

cid, i, o, e = IO.spawn ’ ruby -e"
loop{ STDOUT.puts(Time.now.to_f); STDERR.puts(Time.now.to_f) }" ’

a = Thread.new do
loop{ STDOUT.puts o.gets }
end

b = Thread.new do
loop{ STDOUT.puts e.gets }
end

sleep

a @ http://codeforpeople.com/

On Mon, Mar 31, 2008 at 11:59 AM, ara howard [email protected]
wrote:

this works on *nix and might on windoze - i don’t have a box near so
cannot test… can someone give it a whirl and/or patch it to work?
it should simply run forever:

It works with win32-process-0.5.7. I tested with 0.5.6 first, and
there was a bug with the startup_info hash.

hth,

Gordon

On Mar 31, 1:59 pm, ara howard [email protected] wrote:

windoze = RUBY_PLATFORM.include?(‘win32’)

Ara, didn’t test the code yep, but you should move away from win32 as
platform matcher for Windows, at least, if you plan your code work
with the upcoming one-click installer:

http://blog.mmediasys.com/2008/03/29/progress-of-one-click-installer-rubyinstaller/

Will test it later and get back to you :wink:

On Mar 31, 2008, at 12:50 PM, Luis L. wrote:

Ara, didn’t test the code yep, but you should move away from win32 as
platform matcher for Windows, at least, if you plan your code work
with the upcoming one-click installer:

yeah this is just toy code at this point. still a valid point - what
would have us do to be rock solid

has_fork = fork{ exit! } rescue nil

??

http://blog.mmediasys.com/2008/03/29/progress-of-one-click-installer-rubyinstaller/

this is really great - my thoughts on the topic are well documented in
the archives :wink:

Will test it later and get back to you :wink:

so far it’s rock solid - what this means is that i’ll be able to
provide a cross platform open4 impl whereby client code can have
handles on pid, stdin, stdout, stderr for the child process in a
thread safe fashion - very cool. the sockets idea is from steve
shreeve btw…

cheers.

a @ http://codeforpeople.com/

On 31 Mar 2008, at 22:06, ara.t.howard wrote:

On Mar 31, 2008, at 12:50 PM, Luis L. wrote:

Ara, didn’t test the code yep, but you should move away from win32 as
platform matcher for Windows, at least, if you plan your code work
with the upcoming one-click installer:

yeah this is just toy code at this point. still a valid point -
what would have us do to be rock solid

Luis is will know better than I, but these are the two methods I’ve
been using:

Gem.win_platform? on RubyGems > 0.9.5 (or was it .4?)

or

RUBY_PLATFORM =~ /(cyg|ms)win|mingw/

Although it is worth noting that cygwin acts somewhat like unix
(although there have been past warnings regarding the lack of security
inherent in unix sockets under cygwin), so may need tailoring out for
some platform specific codes.

A more open regex would be:

RUBY_PLATFORM =~ /win|min/ unless RUBY_PLATFORM =~ /darwin/

For these purposes, I might be tempted to do something like the
following (which I know is verbose :frowning: )

non_unix_platform = Gem.win_platform? rescue RUBY_PLATFORM =~ /mswin|
mingw/

N.B. the rescue covers if rubygems is not loaded, as a fallback.

As you will be able to fork and use unix sockets (for what they’re
worth) under cygwin.

handles on pid, stdin, stdout, stderr for the child process in a
thread safe fashion - very cool. the sockets idea is from steve
shreeve btw…

It may be possible to use named pipes?

I will test this when I get to the office,

cheers.

same to you :slight_smile:

james / raggi.