Skip to content

Commit 60ba6d3

Browse files
committed
feat: implement writev and readv on BSD-like OS's
1 parent 802fa35 commit 60ba6d3

File tree

1 file changed

+45
-33
lines changed

1 file changed

+45
-33
lines changed

internal/io/io_bsd.go

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,45 +18,57 @@
1818
package io
1919

2020
import (
21-
"golang.org/x/sys/unix"
21+
"unsafe"
2222

23-
"github.com/panjf2000/gnet/errors"
23+
"golang.org/x/sys/unix"
2424
)
2525

26-
// Writev simply calls write() multiple times cuz writev() on BSD-like OS's is not yet implemented in Go.
27-
func Writev(fd int, iov [][]byte) (int, error) {
28-
var sum int
29-
for i := range iov {
30-
n, err := unix.Write(fd, iov[i])
31-
if err != nil {
32-
if sum == 0 {
33-
sum = n
34-
}
35-
return sum, err
36-
}
37-
sum += n
38-
if n < len(iov[i]) {
39-
return sum, errors.ErrShortWritev
40-
}
26+
// Writev invokes the writev system call directly.
27+
//
28+
// Note that SYS_WRITEV is about to be deprecated on Darwin
29+
// and the Go team suggested to use libSystem wrappers instead of direct system-calls,
30+
// hence, this way to implement the writev might not be backward-compatible in the future.
31+
func Writev(fd int, bs [][]byte) (int, error) {
32+
if len(bs) == 0 {
33+
return 0, nil
34+
}
35+
iov := bytes2iovec(bs)
36+
n, _, err := unix.RawSyscall(unix.SYS_WRITEV, uintptr(fd), uintptr(unsafe.Pointer(&iov[0])), uintptr(len(iov)))
37+
if err != 0 {
38+
return int(n), err
4139
}
42-
return sum, nil
40+
return int(n), nil
4341
}
4442

45-
// Readv simply calls read() multiple times cuz readv() on BSD-like OS's is not yet implemented in Go.
46-
func Readv(fd int, iov [][]byte) (int, error) {
47-
var sum int
48-
for i := range iov {
49-
n, err := unix.Read(fd, iov[i])
50-
if err != nil {
51-
if sum == 0 {
52-
sum = n
53-
}
54-
return sum, err
55-
}
56-
sum += n
57-
if n < len(iov[i]) {
58-
return sum, errors.ErrShortReadv
43+
// Readv invokes the readv system call directly.
44+
//
45+
// Note that SYS_READV is about to be deprecated on Darwin
46+
// and the Go team suggested to use libSystem wrappers instead of direct system-calls,
47+
// hence, this way to implement the readv might not be backward-compatible in the future.
48+
func Readv(fd int, bs [][]byte) (int, error) {
49+
if len(bs) == 0 {
50+
return 0, nil
51+
}
52+
iov := bytes2iovec(bs)
53+
// syscall
54+
n, _, err := unix.RawSyscall(unix.SYS_READV, uintptr(fd), uintptr(unsafe.Pointer(&iov[0])), uintptr(len(iov)))
55+
if err != 0 {
56+
return int(n), err
57+
}
58+
return int(n), nil
59+
}
60+
61+
var _zero uintptr
62+
63+
func bytes2iovec(bs [][]byte) []unix.Iovec {
64+
iovecs := make([]unix.Iovec, len(bs))
65+
for i, b := range bs {
66+
iovecs[i].SetLen(len(b))
67+
if len(b) > 0 {
68+
iovecs[i].Base = &b[0]
69+
} else {
70+
iovecs[i].Base = (*byte)(unsafe.Pointer(&_zero))
5971
}
6072
}
61-
return sum, nil
73+
return iovecs
6274
}

0 commit comments

Comments
 (0)