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

internal/poll: Write, Pwrite, WriteTo and WriteMsg have different error semantics #19073

Closed
davecheney opened this issue Feb 14, 2017 · 5 comments

Comments

@davecheney
Copy link
Contributor

davecheney commented Feb 14, 2017

Please answer these questions before submitting your issue. Thanks!

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

go version devel +15c62e8 Mon Feb 13 20:10:19 2017 +0000 darwin/amd64

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

darwin/amd64

What did you do?

Reviewing fd_unix.go:

fd.Write returns a non zero count of bytes on error.
fd.Pwrite returns a non zero count of bytes on error.
fd.WriteTo returns zero bytes on error.
fd.WriteMsg returns a non zero count of bytes and a zero count of out of band bytes on error.

What did you expect to see?

Option 1: Write,Pwrite,WriteTo, and WriteMsg should return the same count of bytes, that is they all return non zero, or all return zero in the presence of an error.

Option 2: the state of the other values returned from Write,Pwrite,WriteTo, and WriteMsg is not defined in the error condition.

Option 2 is my preferred choice.

What did you see instead?

See above

@davecheney
Copy link
Contributor Author

/cc @ianlancetaylor

@bradfitz
Copy link
Contributor

Option 3: do nothing. It's an internal API.

If you have examples where it affects user code, that's more interesting.

@davecheney
Copy link
Contributor Author

If we went with option 2, then

	for {
		err = syscall.Sendto(fd.Sysfd, p, 0, sa)
		if err == syscall.EAGAIN {
			if err = fd.pd.waitWrite(); err == nil {
				continue
			}
		}
		break
	}
	if err == nil {
		n = len(p)
	}
	return

Can be rewritten to

	for {
		err := syscall.Sendto(fd.Sysfd, p, 0, sa)
		if err == syscall.EAGAIN {
			if err = fd.pd.waitWrite(); err == nil {
				continue
			}
		}
		return len(p), err
	}

I think there is value in pursuing this.

@ianlancetaylor
Copy link
Contributor

As far as I can see, the internal/poll package is correctly reflecting the semantics that were implemented for Write, Pwrite, WriteTo, and WriteMsg before the internal poll package was created. That is, internal/poll is just a refactoring of existing functionality, and the functionality of these functions is, as far as I can tell, unchanged. We aren't simply talking about internal/poll; we are talking about the corresponding functions in os and net.

I think it is clear that we can not change the behavior of Write or Pwrite. They can return a number of bytes written and an error. That is permitted by the io.Writer interface. Changing them to not report the number of bytes written on error would be a bug.

WriteMsg, unlike Write and Pwrite, does not use a loop for writing out data. It has a loop, but only to look for EAGAIN. Once WriteMsg succeeds once, it returns. You say above that WriteMsg returns a non-zero count of bytes on error, but that is not accurate. On an error return from the sendmsg system call, we know that no data is wrtten. So WriteMsg is implemented correctly: on error, it reports that no data has been written, which is correct. On success, it reports the length of the data that was written, which must always include all the out-of-band data.

WriteTo, like WriteMsg, does not use a loop. It acts like WriteMsg.

The upshot is that all the functions correctly report the number of bytes written on error. It happens that for WriteTo and WriteMsg the number of bytes written on error is always zero, but for Write and Pwrite it may sometimes be non-zero.

I don't think there is anything to change.

@davecheney
Copy link
Contributor Author

Thanks Ian.

@golang golang locked and limited conversation to collaborators Feb 14, 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