What version of Go are you using (go version)?
1.10.1
Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (go env)?
linux/amd64 and darwin/amd64
What did you do?
listener, _ := net.Listen("tcp", ":8000")
listenerFH, _ := listener.(*net.TCPListener).File()
server.Serve(listener)
// later, in a different goroutine
server.Shutdown(context.Background())
What did you expect to see?
Server graceful shutdown.
What did you see instead?
Shutdown() returned immediately but Serve() never returned.
Diagnosis
The call to File() on the listener puts the socket in blocking mode. As a result, when the listener is closed, the Accept() called by Serve() does not return. Note that, if the call to File() is moved so that it occurs after the call to Accept(), the problem does not occur.
Response from iant@golang.org on golang-nuts, April 18, 2018:
Before about Go 1.9 or so the os package could not handle a non-blocking descriptor, so File had to change the connection to blocking mode in order to make it usable. Now, however, the os package does use nonblocking descriptors where possible. We could probably change the File method to use a nonblocking *os.File. Please do open an issue for that.
What version of Go are you using (
go version)?1.10.1
Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (
go env)?linux/amd64 and darwin/amd64
What did you do?
What did you expect to see?
Server graceful shutdown.
What did you see instead?
Shutdown() returned immediately but Serve() never returned.
Diagnosis
The call to File() on the listener puts the socket in blocking mode. As a result, when the listener is closed, the Accept() called by Serve() does not return. Note that, if the call to File() is moved so that it occurs after the call to Accept(), the problem does not occur.
Response from iant@golang.org on golang-nuts, April 18, 2018: