Here's the bit of relevant code:
...
def closeFileHandles
if($opt_debug)
$stdin.close()
$stderr.reopen('/tmp/stderr', 'a')
$stdout = $stderr
else
$stdout.close(); $stderr.close(); $stdin.close()
end
end
def RunTest(test,run_id)
handle = startTest(@machine, test, run_id)
fork {
logfile = File.open('/tmp/testout', 'a')
logfile.sync = true
logfile.puts "about to close filehandles"
closeFileHandles()
logfile.puts "waiting for test to finish"
sleep 20 while ProcessRunning?(handle, run_id)
logfile.puts "go get logfiles"
getLogFiles(test, run_id)
logfile.close()
}
end
The problem is, if $opt_debug is not set, and $stdout, $stderr, and
$stdin are closed, then no data past "about to close filehandles" gets
written to /tmp/testout. Actually, something seems to crash the child
during or after closeFileHandles(), since I wrote this code to debug
why the logfiles weren't getting copied back.
If I'm missing something, then please clue me in; I've been tearing my
hair out trying to fix this.
-=Eric
--
Come to think of it, there are already a million monkeys on a million
typewriters, and Usenet is NOTHING like Shakespeare.
-- Blair Houghton
> So I have a program now that starts off tests on remote machines, and
> is supposed to fork itself off, wait for the tests to finish, and
> fetch their logfiles back to the server.
[snip]
perhaps something in the parent is writing to stderr/out? i ask because this
works fine for me
def close
$stderr.close
$stdout.close
$stdin.close
end
def method
fork do
f = File.open 'forkout', 'w'
f.puts Time.now
close
#$stdout.puts 'foobar'
f.puts Time.now
f.close
end
end
method
Process.wait
*unless* i uncomment the line writing to $stdout, in which case i get the
behaviour you define too.
-a
--
====================================
| Ara Howard
| NOAA Forecast Systems Laboratory
| Information and Technology Services
| Data Systems Group
| R/FST 325 Broadway
| Boulder, CO 80305-3328
| Email: aho...@fsl.noaa.gov
| Phone: 303-497-7238
| Fax: 303-497-7259
====================================
Why shouldn't the parent write to stderr/out? The child should
inherit its own copy of all open file descriptors (which at this point
is just stdin, stdout and stderr). Did you mean the child may be
writing?
Here's a minimal example:
1 puts "before fork"
2 fork {
3 puts "in child"
4 logfile = File.open('/tmp/logfile','w')
5 logfile.sync=true
6 logfile.puts "before cleosing file descriptors"
7 $stdout.close
8 $stdout = nil
9 logfile.puts "closed $stdout"
10 $stderr.close
11 $stderr = nil
12 logfile.puts "closed $stderr"
13 $stdin.close
14 $stdin = nil
15 logfile.puts "closed $stdin"
16 }
17 puts "after fork, in parent"
This crashes at the line "$stdout = nil" with:
/tmp/test.rb:8: closed stream (IOError)
from /tmp/test.rb:3:in 'fork'
from /tmp/test.rb:3
This is what I don't get: I closed $stdout on the line before. Why
does it appear to be writing to a closed stream on line 8? I get the
same result if I try to replace line 8 with
$stdout = $stderr
E> 7 $stdout.close
E> 8 $stdout = nil
It want to flush $stdout, don't make an assignement after the close
pigeon% cat b.rb
#!/usr/bin/ruby
puts "before fork"
fork do
puts "in child"
logfile = File.open('/tmp/logfile','w')
logfile.sync=true
logfile.puts "before cleosing file descriptors"
$stdout.close
logfile.puts "closed $stdout"
$stderr.close
logfile.puts "closed $stderr"
$stdin.close
logfile.puts "closed $stdin"
end
puts "after fork, in parent"
pigeon%
pigeon% b.rb
before fork
after fork, in parent
in child
pigeon%
pigeon% cat /tmp/logfile
before cleosing file descriptors
closed $stdout
closed $stderr
closed $stdin
pigeon%
Guy Decoux
Why? $stdout.close should flush the filehandle. At least, in every
other programming language I've ever used, closing a filehandle
flushes its output. I cannot see any good reason why any filehandle,
once closed, should have any I/O associated with it.
I'm all for blaming myself before the language, but this seems very
clearly a bug to me. Am I just missing something?
> ts <dec...@moulon.inra.fr> writes:
> > >>>>> "E" == Eric Schwartz <emsc...@fc.hp.com> writes:
> >
> > E> 7 $stdout.close
> > E> 8 $stdout = nil
> >
> > It want to flush $stdout, don't make an assignement after the close
>
> Why? $stdout.close should flush the filehandle. At least, in every
> other programming language I've ever used, closing a filehandle
> flushes its output. I cannot see any good reason why any filehandle,
> once closed, should have any I/O associated with it.
i think this is because sync is false for stdout, stderr etc. eg. the close
is a *request* to close and flush, but the os may defer the flush. that is,
unless sync were true for all the closed handles...
Yes, but the point is that close() should flush the filehandle from
Ruby's perspective. If the OS wants to delay its flush, that's fine,
it's allowed, but Ruby should not be trying to do a flush (or, indeed,
*any* I/O on any filehandle, be it $stdout or $myfilehandle) after
calling close() on it.
I've filed a bug on ruby-lang.org about this, hopefully someone can
take a look at it. In the meantime, I've managed to work around it.