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/
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

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 Mon, Mar 31, 2008 at 11:59 AM, ara howard <ara.t.howard@gmail.com> 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:

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, 1:59 pm, ara howard <ara.t.how...@gmail.com> 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:

require 'socket'

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

class IO

windoze = RUBY_PLATFORM.include?('win32')

--
Luis Lavena

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 Mar 31, 2008, at 12:50 PM, Luis Lavena wrote:
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

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.

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...

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.

···

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

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