[英]Differences between C write call and Go syscall.Write
syscall write
returns -1 and set errno
is a trivial case. syscall write
返回-1,而设置errno
情况很简单。 I am interested in the status of errno
if C write
call returning zero or positive. 如果C write
调用返回零或正值,我对errno
的状态感兴趣。 The wrapper syscall.Write
in Go simply returns err
if errno
is not zero for any case, which also includes the case of write
call returns positive. 如果errno
在任何情况下都不为零,则Go中的包装器syscall.Write
仅返回err
,这还包括write
调用返回正数的情况。
https://github.com/golang/go/blob/3cb64ea39e0d71fe2af554cbf4e99d14bc08d41b/src/syscall/zsyscall_linux_386.go#L1007 https://github.com/golang/go/blob/3cb64ea39e0d71fe2af554cbf4e99d14bc08d41b/src/syscall/zsyscall_linux_386.go#L1007
However, the man page of C write
call roughly describes errno
may also be set but unspecified if we write zero length buffer without explaining any detail. 但是,如果我们编写零长度缓冲区而没有说明任何细节,则可以粗略地描述errno
的C write
调用的手册页,也可以设置。
Thus, the following cases seem unclear: 因此,以下情况似乎不清楚:
errno
if write
call returning 0 for a file, a non-blocking socket, or a blocking socket? 如果对文件,非阻塞套接字或阻塞套接字的write
调用返回0,则errno
的状态是什么? write
call returning 0 and errno
is not 0? 什么时候以及如何write
调用返回0并且errno
不为0? errno
if write
call returning positive? 如果write
调用返回正值, errno
的状态如何? Will it be negative? 会否定的? I think the above description points to the difference between C write
call and Go syscall.Write
, which is unclear for developers, here are my thoughts: 我认为以上描述指出了C write
调用和Go syscall.Write
之间的区别,对于开发人员来说尚不清楚,这是我的想法:
According to the man page, returning zero is clearly defined in C write
call for to files and for non-blocking sockets, but it's unclear whether there are non-error conditions for a blocking socket which would result in a write()
not blocking, returning 0, and (presumably) possibly succeeding later if retried. 根据手册页,对于文件和非阻塞套接字,在C write
调用中明确定义了返回零,但是不清楚阻塞套接字是否存在非错误条件,这会导致write()
不阻塞,返回0,并且(大概)在以后重试时可能会成功。
Indeed Go directly wraps system call write
. 实际上,Go直接包装了系统调用write
。 However, the following code snippet seems not safe because written
equals to zero is a case that may trigger err
but we don't want to break the loop: 但是,以下代码段似乎并不安全,因为written
为零的情况可能会触发err
但我们不想中断循环:
func writeAll(fd int, buffer []byte) bool {
length := len(buffer)
for length > 0 {
written, err := syscall.Write(fd, buffer)
if err != nil { // here
return false
}
length -= written
buffer = buffer[written:]
}
return true
}
Is there any wrong in my suspicion? 我的怀疑有什么不对吗?
With write
, there are only two cases to consider: 使用write
,只有两种情况需要考虑:
errno
is set. 如果失败,则结果为-1并errno
。 errno
is not set. 如果成功,则结果为0或更大,并且未设置errno
。 There are no other cases to consider, unless you are interested in historical Unix implementations (see: Is a return value of 0 from write(2) in C an error? ). 除非您对历史的Unix实现感兴趣,否则没有其他情况可以考虑(请参阅: C中write(2)的返回值0是否是错误? )。
The reason that write
may return 0 is because the input buffer may be empty. write
可能返回0的原因是因为输入缓冲区可能为空。
However, the man page of C
write
call roughly describeserrno
may also be set but unspecified if we write zero length buffer without explaining any detail. 但是,如果我们编写零长度缓冲区而没有说明任何细节,则可以粗略地描述errno
的Cwrite
调用的手册页,也可以设置。
All this means is that it's possible for a 0-length write to fail. 这一切都意味着0长度写入可能会失败。 If it fails, it returns -1 and sets errno
. 如果失败,则返回-1并设置errno
。 If it succeeds, it returns 0 and does not set errno
. 如果成功,则返回0并且不设置errno
。 This is the same behavior for any other write, it's just mentioned in the man page because people may find it surprising that a 0-length write could fail. 手册页中刚刚提到了这与其他任何写入操作相同的行为,因为人们可能会惊讶地发现0长度写入可能会失败。
What is the status of
errno
ifwrite
call returning 0 for a file, a non-blocking socket, or a blocking socket? 如果对文件,非阻塞套接字或阻塞套接字的write
调用返回0,则errno
的状态是什么?
In this case, errno
is not set, because write
did not fail. 在这种情况下,未设置errno
,因为write
没有失败。 This will only happen if the input buffer is zero bytes. 仅当输入缓冲区为零字节时才会发生这种情况。
When and how
write
call returning 0 anderrno
is not 0? 什么时候以及如何write
调用返回0并且errno
不为0?
This does not happen. 这不会发生。 Either errno
is set and the return is -1, or errno
is not set and the return is 0 or larger. errno
且返回值为-1,或者未设置errno
且返回值为0或更大。
What is the status of
errno
ifwrite
call returning positive? 如果write
调用返回正值,errno
的状态如何? Will it be negative? 会否定的?
The errno
value will not be set. errno
值将不会设置。 It will have the same value as it did before the write
call. 它的值将与write
调用之前的值相同。
Is there any other syscall may encounter the same situation? 是否有任何其他syscall可能遇到相同的情况?
In general, system calls will either return an error or they will succeed. 通常,系统调用将返回错误或成功。 They won't do some mixture of both. 他们不会将两者混合在一起。 Look at the Return Value section of other man pages and you will see that they are mostly the same as write
. 查看其他手册页的“返回值”部分,您将发现它们与write
大部分相同。
This code is safe. 此代码是安全的。
func writeAll(fd int, buffer []byte) bool {
length := len(buffer)
for length > 0 {
written, err := syscall.Write(fd, buffer)
if err != nil { // here
return false
}
length -= written
buffer = buffer[written:]
}
return true
}
Note that it's a bit redundant, we can just do this: 请注意,这有点多余,我们可以这样做:
func writeAll(fd int, buf []byte) bool {
for len(buf) > 0 {
n, err := syscall.Write(fd, buf)
if err != nil {
return false
}
buf = buf[n:]
}
return true
}
Technically, write
is both a system call and a C function (at least on many systems). 从技术上讲, write
既是系统调用又是C函数(至少在许多系统上)。 However, the C function is just a stub which invokes the system call. 但是,C函数只是一个调用系统调用的存根。 Go does not call this stub, it invokes the system call directly, which means that C is not involved here (well, not until you get into the kernel). Go不会调用此存根,而是直接调用系统调用,这意味着此处不涉及C(嗯,直到您进入内核为止)。
The man page shows the calling conventions and behavior of the C stub, write
. 手册页显示了C存根的调用约定和行为write
。 Go chooses to copy that behavior in its own stub, syscall.Write
. Go选择将其行为复制到自己的存根syscall.Write
。 The actual system call itself only has an assembly language interface. 实际的系统调用本身仅具有汇编语言界面。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.