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

Linux: open namepipe file may cause process hang #33050

Closed
hwhe opened this issue Jul 11, 2019 · 10 comments
Closed

Linux: open namepipe file may cause process hang #33050

hwhe opened this issue Jul 11, 2019 · 10 comments

Comments

@hwhe
Copy link

hwhe commented Jul 11, 2019

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

$ go version
go version go1.8.5 linux/amd64

Does this issue reproduce with the latest release?

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/"
GORACE=""
GOROOT="/home/go"
GOTOOLDIR="/home/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build303308861=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"

What did you do?

i create a pipe file, if no data write ,it will block on open() function.
when i delete this pipe file, the open() function will hang forever. it may cause fd leak.
It is a reasonable behavior?

What did you expect to see?

delete the pipe file, the Open() should return an error

What did you see instead?

block forever

goroutine 6269 [syscall, 34 minutes]:
syscall.Syscall6(0x101, 0xffffffffffffff9c, 0xc4209a7480, 0x80000, 0x0, 0x0, 0x0, 0x2, 0x2, 0x8abd30)
/root/buildbox/go-1.8.1/src/syscall/asm_linux_amd64.s:44 +0x5
syscall.openat(0xffffffffffffff9c, 0xc420294a80, 0x76, 0x80000, 0x10000c400000000, 0x8, 0x8, 0xc420388270)
/root/buildbox/go-1.8.1/src/syscall/zsyscall_linux_amd64.go:40 +0xd0
syscall.Open(0xc420294a80, 0x76, 0x80000, 0xc400000000, 0x4147ad, 0x41470f, 0xc42019aee8)
/root/buildbox/go-1.8.1/src/syscall/syscall_linux.go:51 +0x50
os.OpenFile(0xc420294a80, 0x76, 0x0, 0x0, 0xc42019af30, 0xc42019af28, 0xc4208de0f0)
/root/buildbox/go-1.8.1/src/os/file_unix.go:97 +0x80
os.Open(0xc420294a80, 0x76, 0x34, 0xc42019af78, 0x2)
/root/buildbox/go-1.8.1/src/os/file.go:247 +0x46

@hwhe
Copy link
Author

hwhe commented Jul 11, 2019

root@ecs-88d2-:/home/# mkfifo xx
root@ecs-88d2-:/home/# file xx
xx: fifo (named pipe)
root@ecs-88d2-:/home/#

open it like this:
f, err := os.Open(file)

if no data write into pipe, it will block in Open() even the file has been deleted.

@cuonglm
Copy link
Member

cuonglm commented Jul 11, 2019

This is intended behavior.

os.Open opens file with os.RDONLY flag, causing it blocks when reading from pipe. To get non-blocking behavior, use os.OpenFile with os.O_RDWR flag.

@hwhe
Copy link
Author

hwhe commented Jul 11, 2019

This is intended behavior.

os.Open opens file with os.RDONLY flag, causing it blocks when reading from pipe. To get non-blocking behavior, use os.OpenFile with os.O_RDWR flag.

i my scenario, client don't know when peer write data, it should block to read the pipe.
my point is when the pipe file no write any data and then has been deleted, the open has no any error to exit block.

@cuonglm
Copy link
Member

cuonglm commented Jul 11, 2019

@hwhe It's the same behavior with any tools using open syscall with RDONLY flag. You can experiment the same behavior with:

$ mkfifo /tmp/fifo
$ cat /tmp/fifo

In other terminal:

$ rm /tmp/fifo

And see cat hangs forever.

@hwhe
Copy link
Author

hwhe commented Jul 11, 2019

@hwhe It's the same behavior with any tools using open syscall with RDONLY flag. You can experiment the same behavior with:

$ mkfifo /tmp/fifo
$ cat /tmp/fifo

In other terminal:

$ rm /tmp/fifo

And see cat hangs forever.

yes, you are right,
but it's a reasonable behavior?
Is there any function or flag to avoid this behavior in golang ?

@cuonglm
Copy link
Member

cuonglm commented Jul 11, 2019

@hwhe It's the same behavior with any tools using open syscall with RDONLY flag. You can experiment the same behavior with:

$ mkfifo /tmp/fifo
$ cat /tmp/fifo

In other terminal:

$ rm /tmp/fifo

And see cat hangs forever.

yes, you are right,
but it's a reasonable behavior?
Is there any function or flag to avoid this behavior in golang ?

Yes, it's the standard behavior, and you can't go beyond it.

The open syscall returns a new file descriptor which is not shared with any other processes. As long as you keep that file descriptor open, you have full control of it, even the original file was deleted in filesystem.

You can read open for more details.

@beoran
Copy link

beoran commented Jul 11, 2019

I would read from the pipe in a separate goroutine, and pass the read results into a channel that is read by the main goroutine. Then, check in the main routine if the FIFO still exists, if not, stop the separate goroutine.

@hwhe
Copy link
Author

hwhe commented Jul 11, 2019

I would read from the pipe in a separate goroutine, and pass the read results into a channel that is read by the main goroutine. Then, check in the main routine if the FIFO still exists, if not, stop the separate goroutine.

if the call Open() goroutine is blocked, how to stop it?

@beoran
Copy link

beoran commented Jul 11, 2019

I would use os.OpenFile with os.O_RDWR, then spin around trying to read in a loop, controlled by a boolean protected with a mutex if neccesary.

@ianlancetaylor
Copy link
Member

This is how GNU/Linux works, and there is nothing we can do about it in the Go library, so closing the issue. You can continue to discuss it here if you like, or perhaps a GNU/Linux or general Unix forum would be appropriate.

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

5 participants