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

bugfix:save file.Fd() to avoid block again #15

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

detailyang
Copy link

See the code below:

  1. setNonblock(desc.fd(), true)
  2. desc.fd()

The second desc.fd() will set the kernel file description block again.

#11 is likely related.

Signed-off-by: detailyang <detailyang@gmail.com>
See the code as below:

1. setNonblock(file.Fd())
2. file.Fd()

The second file.Fd() above will set the fd to block again.

Signed-off-by: detailyang <detailyang@gmail.com>
Signed-off-by: detailyang <detailyang@gmail.com>
Signed-off-by: detailyang <detailyang@gmail.com>
@detailyang
Copy link
Author

@rvasily

Would you have a look at this?

Many thanks:)

@gobwas gobwas mentioned this pull request Sep 14, 2019
return &Desc{file: os.NewFile(fd, ""), event: ev, fd: int(fd)}
}

// NewDescFile creates descriptor from os.File
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! Could you please follow this rules for comments? Thanks!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

func (h *Desc) fd() int {
return int(h.file.Fd())
// Fd returns the underlying file descriptor
func (h *Desc) Fd() int {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this now must be exported?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since I need the underlying fd in my scene so I have to export the fd:(.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my scene, I need the fd and join the fd to another epoll fd which is super strange but it works. I use easygo to solve golang/go#15735

}

// NewDescFile creates descriptor from os.File
func NewDescFile(file *os.File, ev Event) *Desc {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really necessary to provide additional Desc constructor here? Why just don't setup fd field of the struct right in place where it is created and remove whole Fd() getter method?

@gobwas
Copy link
Contributor

gobwas commented Sep 14, 2019

@rvasily looks like this PR is better than this.

@rdmrcv
Copy link

rdmrcv commented Sep 15, 2019

Might be useful to take a look at the syscall.RawConn (https://golang.org/pkg/syscall/#RawConn). Since go 1.9 it may allow to avoid FD duplication at all.

Signed-off-by: detailyang <detailyang@gmail.com>
@detailyang
Copy link
Author

@gobwas sorry, I'm busy:) can you look at this.

@ligser RawConn says the following:

  // The file descriptor fd is guaranteed to remain valid while
      // f executes but not after f returns.

The fd is invalid after f returns although we know the fd should never be changed?

@rdmrcv
Copy link

rdmrcv commented Sep 20, 2019

@detailyang Yes, I think about that notice too, but in the stdlib code it does not looks like the FD changed anywhere. So I think this notice about the FD state not the FD value.

But anyway if you create a new method like:

func (h *Desc) Control(f func(fd uintptr) error) (err error) {
	// Here we rely that func will be executed in the same goroutine and we can
	// receive new err value at the end (err captured to the func).
	cntErr := h.rawConn.Control(func(fd uintptr) {
		err = f(fd)
	})
	runtime.KeepAlive(h)
	if cntErr != nil {
		return cntErr
	}

	return err
}

and store a syscall.RawConn you can do not worry about it. When you need a FD you pass a callback and work with the valid FD inside it.

Signed-off-by: detailyang <detailyang@gmail.com>
@rdmrcv
Copy link

rdmrcv commented Sep 20, 2019

But that approach does not widely tested. I use it in my own implementation and do not know about caveats. Maybe repo owners see something that I missed about that approach.

@detailyang
Copy link
Author

detailyang commented Sep 20, 2019

@ligser many thanks.

I do not understand the way you use runtime.Keepalive to keepalive h don't GC? it looks makes no sense because the h will not gc in the method of h.

I check the code in https://github.com/golang/go/blob/master/src/internal/poll/fd_unix.go#L512 which I think it says the fd must be associated with the opened file but after the callback return the fd maybe is associated with the closed file or another file which the new fd is the value..

@rdmrcv
Copy link

rdmrcv commented Sep 20, 2019

@detailyang https://groups.google.com/forum/#!topic/Golang-nuts/LIWj6Gl--es there is some doubts about method arguments and GC. Anyway KeepAlive here just for ensure and just because I see same pattern somewhere in stdlib it may be not required.

@rdmrcv
Copy link

rdmrcv commented Sep 20, 2019

Oh, looks like I seen that in net/rawconn, and looks like the KeepAlive should not be required in my snippet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants