Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

os: SetDeadline doesn't work after an Fd() call #22934

Closed
crvv opened this issue Nov 30, 2017 · 3 comments
Closed

os: SetDeadline doesn't work after an Fd() call #22934

crvv opened this issue Nov 30, 2017 · 3 comments

Comments

@crvv
Copy link
Contributor

crvv commented Nov 30, 2017

What version of Go are you using (go version)?

go version devel +ed8b7dedd3 Thu Nov 30 01:46:50 2017 +0000 linux/amd64

What did you do?

package main

import (
    "os"
    "time"
)

func main() {
    r, w, err := os.Pipe()
    if err != nil { panic(err) }
    println(r.Fd())
    go func() {
        time.Sleep(time.Second*2)
        _, err := w.Write([]byte("Hello, world!"))
        if err != nil { panic(err) }
    }()
    err = r.SetDeadline(time.Now().Add(time.Second))
    // expect an error at this line
    if err != nil { panic(err) }
    buffer := make([]byte, 16)
    n, err := r.Read(buffer)
    // or this line
    if err != nil { panic(err) }
    println(string(buffer[:n]))
}

What did you expect to see?

A timeout error.
Or an error when SetDeadline.

The Fd() can also be called after SetDeadline(), so a timeout error is better.

What did you see instead?

A successful Read and "Hello, world!".

The method Fd() put the file descriptor into blocking mode and the deadline doesn't work after it.

syscall.SetNonblock(f.pfd.Sysfd, false)

There is a similar issue with package net. #21862

@bradfitz
Copy link
Contributor

Ian, I assume this is also just a documentation thing?

@gopherbot
Copy link
Contributor

Change https://golang.org/cl/81636 mentions this issue: os: calling Fd disables the SetDeadline methods

@gopherbot
Copy link
Contributor

Change https://golang.org/cl/82915 mentions this issue: net: calling File disables the SetDeadline methods

gopherbot pushed a commit that referenced this issue Dec 8, 2017
This essentially applies https://golang.org/cl/81636 to the net package.

The full truth seems too complicated to write in this method's doc, so
I'm going with a simple half truth.

The full truth is that File returns the descriptor in blocking mode,
because that is historically how it worked, and existing programs
would be surprised if the descriptor is suddenly non-blocking. On Unix
systems whether a socket is non-blocking or not is a property of the
underlying file description, not of a particular file descriptor, so
changing the returned descriptor to blocking mode also changes the
existing socket to blocking mode. Blocking mode works fine, althoug I/O
operations now take up a thread. SetDeadline and friends rely on the
runtime poller, and the runtime poller only works if the descriptor is
non-blocking. So it's correct that calling File disables SetDeadline.
The other half of the truth is that if the program is willing to work
with a non-blocking descriptor, it could call
syscall.SetNonblock(f.Fd(), true) to change the descriptor, and
the original socket, to non-blocking mode. At that point SetDeadline
would start working again. I tried to write that in a way that is
short and comprehensible but failed. Since we now have the RawConn
approach to frobbing the descriptor, and hopefully most people can use
that rather than calling File, I decided to punt.

Updates #22934
Fixes #21862

Change-Id: If269da762f6f5a88c334e7b6d6f3998f7e10b11e
Reviewed-on: https://go-review.googlesource.com/82915
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
@golang golang locked and limited conversation to collaborators Dec 8, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants