-
Notifications
You must be signed in to change notification settings - Fork 19k
os.File.Read() does not return after os.File.Close() and os.File.Fd() #26439
Copy link
Copy link
Closed
Labels
Description
What did you do?
Compile and run the following program.
package main
import (
"fmt"
"io"
"log"
"os"
"time"
)
func main() {
err := Main()
if err != nil {
log.Fatal(err)
}
}
func readpart(r io.ReadCloser) error {
done := make(chan struct{})
defer func() { <-done }()
go func() {
// To be reasonably sure that the parent goroutine is already
// in the call to Read().
time.Sleep(50 * time.Millisecond)
err := r.Close()
fmt.Printf("close err %v\n", err)
done <- struct{}{}
}()
_, err := r.Read(make([]byte, 128))
if err != nil {
return err
}
return nil
}
func getfile() (*os.File, error) {
r, _, err := os.Pipe()
return r, err
}
func Main() error {
f0, err := getfile()
if err != nil {
return err
}
err = readpart(f0)
fmt.Printf("error of f0.Read(): %v\n", err)
f1, err := getfile()
if err != nil {
return err
}
fmt.Printf("f1.Fd() %d\n", f1.Fd())
err = readpart(f1)
fmt.Printf("error of f1.Read(): %v\n", err)
return nil
}What did you expect to see?
The program exits with a successful error code. The program runs until the end because the Read() will return immediately after Close has been called on the underlying *os.File.
What did you see instead?
After f1.Close() has returned, the program blocks in a call to f1.Read().
Analysis with strace shows that close() is only called for f0. For f1, the Go stdlib never calls close(). From the side of my program, the only difference is that I called f1.Fd(), but not f0.Fd(). Remove the call to f1.Fd() and the program will terminate.
I am experiencing this issue while working with serial ports. In order to set the baud rate and other parameters, I need the file descriptor to deal with termios.
System details
go version go1.10.3 linux/amd64
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/joe/.cache/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/joe/gop"
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build575248038=/tmp/go-build -gno-record-gcc-switches"
GOROOT/bin/go version: go version go1.10.3 linux/amd64
GOROOT/bin/go tool compile -V: compile version go1.10.3
uname -sr: Linux 4.13.0-45-generic
Distributor ID: Ubuntu
Description: Ubuntu 16.04.4 LTS
Release: 16.04
Codename: xenial
/lib/x86_64-linux-gnu/libc.so.6: GNU C Library (Ubuntu GLIBC 2.23-0ubuntu10) stable release version 2.23, by Roland McGrath et al.
gdb --version: GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Reactions are currently unavailable