@@ -54,7 +54,7 @@ func rename(oldname, newname string) error {
54
54
55
55
// file is the real representation of *File.
56
56
// The extra level of indirection ensures that no clients of os
57
- // can overwrite this data, which could cause the finalizer
57
+ // can overwrite this data, which could cause the cleanup
58
58
// to close the wrong file descriptor.
59
59
type file struct {
60
60
pfd poll.FD
@@ -63,17 +63,18 @@ type file struct {
63
63
nonblock bool // whether we set nonblocking mode
64
64
stdoutOrErr bool // whether this is stdout or stderr
65
65
appendMode bool // whether file is opened for appending
66
+ cleanup runtime.Cleanup // cleanup closes the file when no longer referenced
66
67
}
67
68
68
69
// Fd returns the integer Unix file descriptor referencing the open file.
69
70
// If f is closed, the file descriptor becomes invalid.
70
- // If f is garbage collected, a finalizer may close the file descriptor,
71
- // making it invalid; see [runtime.SetFinalizer ] for more information on when
72
- // a finalizer might be run. On Unix systems this will cause the [File.SetDeadline]
71
+ // If f is garbage collected, a cleanup may close the file descriptor,
72
+ // making it invalid; see [runtime.AddCleanup ] for more information on when
73
+ // a cleanup might be run. On Unix systems this will cause the [File.SetDeadline]
73
74
// methods to stop working.
74
75
// Because file descriptors can be reused, the returned file descriptor may
75
- // only be closed through the [File.Close] method of f, or by its finalizer during
76
- // garbage collection. Otherwise, during garbage collection the finalizer
76
+ // only be closed through the [File.Close] method of f, or by its cleanup during
77
+ // garbage collection. Otherwise, during garbage collection the cleanup
77
78
// may close an unrelated file descriptor with the same (reused) number.
78
79
//
79
80
// As an alternative, see the f.SyscallConn method.
@@ -240,7 +241,8 @@ func newFile(fd int, name string, kind newFileKind, nonBlocking bool) *File {
240
241
}
241
242
}
242
243
243
- runtime .SetFinalizer (f .file , (* file ).close )
244
+ // Close the file when the File is not live.
245
+ f .cleanup = runtime .AddCleanup (f , func (f * file ) { f .close () }, f .file )
244
246
return f
245
247
}
246
248
@@ -337,8 +339,9 @@ func (file *file) close() error {
337
339
err = & PathError {Op : "close" , Path : file .name , Err : e }
338
340
}
339
341
340
- // no need for a finalizer anymore
341
- runtime .SetFinalizer (file , nil )
342
+ // There is no need for a cleanup at this point. File must be alive at the point
343
+ // where cleanup.stop is called.
344
+ file .cleanup .Stop ()
342
345
return err
343
346
}
344
347
0 commit comments