Don Cohen wrote:
> Sam Steingold writes:
> > 1. if the lisp stream object is already marked as closed, do
> > nothing, return immediately.
> One issue is whether there could ever be a difference between what
> streams are "marked as closed" and what streams are "really" closed.
> By which I mean some disagreement between clisp and the OS about
> whether a stream is closed.
if CLOSE signals an error, then the underlying FD _might_ have been closed, but
the lisp stream object is not marked as closed.
CLOSE can signal errors if some buffer flushing operation fails (unless :ABORT
is T, in which case all errors are ignored).
> > 2. flush buffers (see close_buffered, close_ochannel, close_ichannel)
> Below you say that this can cause errors that are not correctly handled
> but it sounds like the problem is only when abort is true.
what does "correctly handled" mean in this context?
ABORT T: all errors are ignored
ABORT NIL: debugger is invoked on the first error, all further processing is
> I don't think I'm using with-open-stream to create network streams,
> and I'm pretty sure that it's the network streams that are causing
> the errors.
OK, so you never call CLOSE :ABORT T, right?
> > 3. call close(2) (see low_close_handle); if the abort argument is
> > non-NIL, ignore errors from close(2).
> What sort of errors could occur and what would be the result of abort
> is nil ?
see the close(2) man page as to what errors can happen.
if ABORT=T, these errors are silently ignored.
if ABORT=NIL, lisp function ERROR is called.
> > 4. mark the lisp stream object as closed; remove it from the list
> > of open streams.
> > normally abort is NIL (unless you are using with-open-stream, see
> > macroexpand), so if close(2) fails, lisp CLOSE will _not_ mark the
> > stream as closed and will not remove it from the list of open
> > streams, i.e., if the lisp stream object is abandoned, then GC will
> > close it before collecting (i.e., call builtin_stream_close with
> But this close would probably produce the same errors as before.
> So we end up with a stream that lisp thinks is closed (and can be
> GC'd) but the OS thinks it's still open?
> Maybe that does no harm, since it's only an integer fh that, as far as
> lisp can see, simply never gets allocated again.
if you do not use with-open-stream, then, indeed, if CLOSE fails, you may end
up with a lisp stream object which is considered open by lisp but has a closed
FD under the hood.
> > abort=true - thus not printing the ebadf message, see
> > stream.d:close_some_files, called from spvw_garcol.d:gar_col_done).
> > so, after you call CLOSE on a lisp stream object with a bad FD, you
> > see the EBADF error and the lisp stream object is NOT marked
> > close. Whenever you do something else with it, you are probably
> > getting a ebadf, until you either call (CLOSE :ABORT) on it or
> > abandon the object, it is GCed, and GC calls (CLOSE :ABORT) on it.
> I think the segfault occurred when I called close (without abort)
> the first time, and it seems likely (to me) that this is also how all
> the other segfaults arise.
so, the fundamental question now is - how come you have bad FDs?
> > (gdb) br builtin_stream_close
> > (gdb) run
> > clisp> (setq s (socket-connect 21 "ftp.gnu.org" :buffered t))
> > clisp> (write-char #\a s)
> > clisp> (close s)
> > now we stop in builtin_stream_close and close the FD before clisp
> > does its thing:
> This corresponds to my theory that the broken connection was
> causing the fd to be closed. Perhaps that's what I've not been
> adequately explaining to you. Is it possible that when the OS
> detects that a tcp connection is broken, it closes the fd ?
I have no idea.
I think it is best to ask this on a dedicated unix forum.
Maybe Fred knows that off hand?
> So at that point lisp thinks that it's open and the OS thinks
if, e.g., shutdown(2) in both directions calls close(2), then, yes, lisp will
think the FD is open, but OS will think it is closed.
> > now the stream is no longer referenced and can be GCed.
> > clisp> (gc)
> > clisp> (gc)
> > clisp> (gc)
> > ** - UNIX error 9 (EBADF): Bad file number
> > an error in GC!!!
> cause it's trying to close the stream, I gather?
yes, when a stream object is GCed, it is automatically closed.