diff --git a/src/os/file_plan9.go b/src/os/file_plan9.go index 043500744b1..5e0ad682084 100644 --- a/src/os/file_plan9.go +++ b/src/os/file_plan9.go @@ -29,8 +29,13 @@ type file struct { } // Fd returns the integer Plan 9 file descriptor referencing the open file. -// The file descriptor is valid only until f.Close is called or f is garbage collected. -// On Unix systems this will cause the SetDeadline methods to stop working. +// If f is closed, the file descriptor becomes invalid. +// If f is garbage collected, a finalizer may close the file descriptor, +// making it invalid; see runtime.SetFinalizer for more information on when +// a finalizer might be run. On Unix systems this will cause the SetDeadline +// methods to stop working. +// +// As an alternative, see the f.SyscallCon method. func (f *File) Fd() uintptr { if f == nil { return ^(uintptr(0)) diff --git a/src/os/file_unix.go b/src/os/file_unix.go index dc7d868a32b..c4dd4fc6a95 100644 --- a/src/os/file_unix.go +++ b/src/os/file_unix.go @@ -62,8 +62,13 @@ type file struct { } // Fd returns the integer Unix file descriptor referencing the open file. -// The file descriptor is valid only until f.Close is called or f is garbage collected. -// On Unix systems this will cause the SetDeadline methods to stop working. +// If f is closed, the file descriptor becomes invalid. +// If f is garbage collected, a finalizer may close the file descriptor, +// making it invalid; see runtime.SetFinalizer for more information on when +// a finalizer might be run. On Unix systems this will cause the SetDeadline +// methods to stop working. +// +// As an alternative, see the f.SyscallCon method. func (f *File) Fd() uintptr { if f == nil { return ^(uintptr(0)) diff --git a/src/os/file_windows.go b/src/os/file_windows.go index cc695fd94c7..f744a350231 100644 --- a/src/os/file_windows.go +++ b/src/os/file_windows.go @@ -26,8 +26,11 @@ type file struct { } // Fd returns the Windows handle referencing the open file. -// The handle is valid only until f.Close is called or f is garbage collected. -// On Unix systems this will cause the SetDeadline methods to stop working. +// If f is closed, the file descriptor becomes invalid. +// If f is garbage collected, a finalizer may close the file descriptor, +// making it invalid; see runtime.SetFinalizer for more information on when +// a finalizer might be run. On Unix systems this will cause the SetDeadline +// methods to stop working. func (file *File) Fd() uintptr { if file == nil { return uintptr(syscall.InvalidHandle) diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go index d6c85a8b939..cd6196dcabd 100644 --- a/src/runtime/mfinal.go +++ b/src/runtime/mfinal.go @@ -293,15 +293,15 @@ func runfinq() { // pass the object to a call of the KeepAlive function to mark the // last point in the function where the object must be reachable. // -// For example, if p points to a struct that contains a file descriptor d, -// and p has a finalizer that closes that file descriptor, and if the last -// use of p in a function is a call to syscall.Write(p.d, buf, size), then -// p may be unreachable as soon as the program enters syscall.Write. The -// finalizer may run at that moment, closing p.d, causing syscall.Write -// to fail because it is writing to a closed file descriptor (or, worse, -// to an entirely different file descriptor opened by a different goroutine). -// To avoid this problem, call runtime.KeepAlive(p) after the call to -// syscall.Write. +// For example, if p points to a struct, such as os.File, that contains +// a file descriptor d, and p has a finalizer that closes that file +// descriptor, and if the last use of p in a function is a call to +// syscall.Write(p.d, buf, size), then p may be unreachable as soon as +// the program enters syscall.Write. The finalizer may run at that moment, +// closing p.d, causing syscall.Write to fail because it is writing to +// a closed file descriptor (or, worse, to an entirely different +// file descriptor opened by a different goroutine). To avoid this problem, +// call runtime.KeepAlive(p) after the call to syscall.Write. // // A single goroutine runs all finalizers for a program, sequentially. // If a finalizer must run for a long time, it should do so by starting