php editor Zimo will answer your question in this article about SetDeadline/SetReadDeadline/SetWriteDeadline not working on files when using os.File.Fd() in Golang . In Golang, these methods are used to set the deadline of files, but sometimes they may be invalid. Next, we'll explore possible causes and provide solutions to ensure these methods are working properly.
I use a combination of os.File.SetReadDeadline
and os.File.ReadFull
. But even with SetReadDeadline
, the deadline I set is completely ignored and ReadFull
blocks forever. why is that?
Additional information: I'm firing some IOCTLS to the file, so os.File.Fd() is needed to get the file descriptor.
tl; Doctor:
After using os.file.fd()
, use syscall.setnonblock(fd.fd(), true)
This is due to read
In golang unix:
func (fd *fd) read(p []byte) (int, error) { if err := fd.readlock(); err != nil { return 0, err } defer fd.readunlock() if len(p) == 0 { // if the caller wanted a zero byte read, return immediately // without trying (but after acquiring the readlock). // otherwise syscall.read returns 0, nil which looks like // io.eof. // todo(bradfitz): make it wait for readability? (issue 15735) return 0, nil } if err := fd.pd.prepareread(fd.isfile); err != nil { return 0, err } if fd.isstream && len(p) > maxrw { p = p[:maxrw] } for { n, err := ignoringeintrio(syscall.read, fd.sysfd, p) if err != nil { n = 0 if err == syscall.eagain && fd.pd.pollable() { if err = fd.pd.waitread(fd.isfile); err == nil { continue } } } err = fd.eoferror(n, err) return n, err } }
If the file is set to blocking mode, the first n, err := ignoringeintrio(syscall.read, fd.sysfd, p)
will block forever. waitread
Will only be executed if the file is opened in non-blocking mode. But I did open the file in non-blocking mode, so what happened?
Implementation of os.file.fd()
Broken it:
func (f *File) Fd() uintptr { if f == nil { return ^(uintptr(0)) } // If we put the file descriptor into nonblocking mode, // then set it to blocking mode before we return it, // because historically we have always returned a descriptor // opened in blocking mode. The File will continue to work, // but any blocking operation will tie up a thread. if f.nonblock { f.pfd.SetBlocking() } return uintptr(f.pfd.Sysfd) }
fd()
Always sets the file to blocking. Therefore, we must undo the operation before waiting for polling to read. therefore:
After using os.file.fd()
, use syscall.setnonblock(fd.fd(), true)
The above is the detailed content of GOLANG: Why don't SetDeadline/SetReadDeadline/SetWriteDeadline work for files when using os.File.Fd()?. For more information, please follow other related articles on the PHP Chinese website!