|
18 | 18 | package io |
19 | 19 |
|
20 | 20 | import ( |
21 | | - "golang.org/x/sys/unix" |
| 21 | + "unsafe" |
22 | 22 |
|
23 | | - "github.com/panjf2000/gnet/errors" |
| 23 | + "golang.org/x/sys/unix" |
24 | 24 | ) |
25 | 25 |
|
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 |
41 | 39 | } |
42 | | - return sum, nil |
| 40 | + return int(n), nil |
43 | 41 | } |
44 | 42 |
|
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)) |
59 | 71 | } |
60 | 72 | } |
61 | | - return sum, nil |
| 73 | + return iovecs |
62 | 74 | } |
0 commit comments