Home > Backend Development > Golang > GOLANG: Why don't SetDeadline/SetReadDeadline/SetWriteDeadline work for files when using os.File.Fd()?

GOLANG: Why don't SetDeadline/SetReadDeadline/SetWriteDeadline work for files when using os.File.Fd()?

PHPz
Release: 2024-02-09 08:30:21
forward
1113 people have browsed it

GOLANG:为什么在使用 os.File.Fd() 时 SetDeadline/SetReadDeadline/SetWriteDeadline 对文件不起作用?

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.

Question content

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.

Solution

tl; Doctor:

After using os.file.fd(), use syscall.setnonblock(fd.fd(), true)

on the file

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
    }
}
Copy after login

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)
}
Copy after login

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)

on the file

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!

source:stackoverflow.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template