On Wed, 24 Mar 2004 20:13:46 -0700, Ara.T.Howard wrote:

> 
> i'm working on an tk ap that drives alot of complex code, some of which is not
> even ruby, and essitially gives you running progress report.  i've had no end
> to the woes one can get into by mixing threads and forks with tk.  some
> combinations even seem to hang X... in any case, the cause of the forks is
> mostly open3 and i'm considering this alternative:
> 
>     def spawn command
>       ipath = tmpfifo
>       opath = tmpfifo
>       epath = tmpfifo
> 
>       cmd = "#{ command } < #{ ipath } 1> #{ opath } 2> #{ epath } &"
>       system cmd
> 
>       i = open ipath, 'w'
>       o = open opath, 'r'
>       e = open epath, 'r'
> 
>       [i,o,e]
>     end
> 
>     def tmpfifo
>       path = nil
>       42.times do |i|
>         tpath = File.join(Dir.tmpdir, "#{ $$ }.#{ rand }.#{ i }")
>         system "mkfifo #{ tpath }"
>         next unless $? == 0
>         path = tpath
>         at_exit{ File.unlink path rescue STDERR.puts "rm <#{ path }> failed" }
>         break
>       end
>       raise "could not generate tmpfifo" unless path
>       path
>     end
> 
> obviously this is a non-portable alternative - but then again so is open3.  can
> anyone see any large drawbacks to this?  it plays well with threads and tk
> since one can:
> 
>   i,o,e = spawn 'sh'
>   i.puts long_running_command
> 
>   Thread.new do
>     while((out = o.gets))
>     ... 
>       update widgets with out
>     ... 
>     end
>   end
> 
>   Thread.new do
>     while((err = e.gets))
>     ... 
>       update widgets with err 
>     ... 
>     end
>   end
> 
> -a

Nice idea IMHO.
Funny, I had to write something similar yesterday to get rid of open3
warnings that were triggered when publishing my objects with drb because
of its forks. This is what I did. It is much simpler as I do not need to
read stdout while the spawned process runs, nor write to its stdin. I only
need to get stderr and stdout separately.

def runrun(rcmd)
  # Get a temp file
  tmp = Tempfile.new("runrun")
  # Redirect stderr into temp file
  po = IO.popen("#{rcmd} 2>#{tmp.path}")
  stdo = po.readlines
  po.close
  # Reopen temp file and read STDERR
  tmp.open
  stdr = tmp.readlines
  # Close and unlink temp file
  tmp.close!
  # return STDOUT and STDERR
  [stdo, stdr]
end


Regards,
Xavier.