Daniel Berger
2008-Mar-27 23:03 UTC
[Win32utils-devel] IO.socketpair addition -- very helpful!
Steve, Thanks for this. May I recommend joining the win32utils-devel mailing list? You would be most welcome with ideas like this! Regards, Dan On Thu, Mar 27, 2008 at 9:52 AM, Steve Shreeve <steve.shreeve at gmail.com> wrote:> > > Dan, > > I had nearly pulled my hair out over the past week trying to figure out why > I couldn''t spawn a process on Windows and communicate with it. A few things > I found out later: > > 1) The ''fork'' implementation is totally gorked and should be renamed to > something other that ''fork''... it''s more like ''clone_me_and_do_over()''. > 2) On Windows, pipes are essentially worthless because select() always says > there''s data, which will take you into a black hole if you try to read it. > > I *did* figure out, however, that sockets actually behave quite nicely on > Windows. Also, I found your latest win32/process has some nice additions > (modulo the few tweakers we''ve been discussing recently). > > In order to create a fairly clean way to interact with subprocesses, I''ve > now got the code below. > > Let me know if this is helpful. > > Thanks, > > Steve > > => > require ''socket'' > > STDIN.sync = STDOUT.sync = STDERR.sync = true > > class IO > def self.socketpair(sync=true) > if RUBY_PLATFORM.include?(''win32'') > tcp = TCPServer.new(''127.0.0.1'', 0) > one = TCPSocket.new(''127.0.0.1'', tcp.addr[1]) > two = tcp.accept and tcp.close > else > one, two = UNIXSocket.socketpair > end > one.sync = two.sync = true if sync > [one, two] > end > > def self.spawn(cmd=nil) > io, child_io = 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'' => child_io, > ''stdout'' => child_io, > ''stderr'' => File.open(''nul'', ''wb'') # ignore STDERR, for now (what > about sync? close?) > } > ) > at_exit do > Process.TerminateProcess(child.process_handle, child.process_id) > Process.CloseHandle(child.process_handle) > end > child_io.close > > io > end > end > > io = IO.spawn(''date'') > > # communicate using "io" and control threads... >