libgo: update to go1.9
[official-gcc.git] / libgo / go / internal / poll / writev.go
blob4bf8804e217c1119a5cca0fa067ce2c35f566e74
1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // +build darwin dragonfly freebsd linux netbsd openbsd
7 package poll
9 import (
10 "io"
11 "syscall"
12 "unsafe"
15 // Writev wraps the writev system call.
16 func (fd *FD) Writev(v *[][]byte) (int64, error) {
17 if err := fd.writeLock(); err != nil {
18 return 0, err
20 defer fd.writeUnlock()
21 if err := fd.pd.prepareWrite(fd.isFile); err != nil {
22 return 0, err
25 var iovecs []syscall.Iovec
26 if fd.iovecs != nil {
27 iovecs = *fd.iovecs
29 // TODO: read from sysconf(_SC_IOV_MAX)? The Linux default is
30 // 1024 and this seems conservative enough for now. Darwin's
31 // UIO_MAXIOV also seems to be 1024.
32 maxVec := 1024
34 var n int64
35 var err error
36 for len(*v) > 0 {
37 iovecs = iovecs[:0]
38 for _, chunk := range *v {
39 if len(chunk) == 0 {
40 continue
42 iovecs = append(iovecs, syscall.Iovec{Base: &chunk[0]})
43 if fd.IsStream && len(chunk) > 1<<30 {
44 iovecs[len(iovecs)-1].SetLen(1 << 30)
45 break // continue chunk on next writev
47 iovecs[len(iovecs)-1].SetLen(len(chunk))
48 if len(iovecs) == maxVec {
49 break
52 if len(iovecs) == 0 {
53 break
55 fd.iovecs = &iovecs // cache
57 wrote, _, e0 := syscall.Syscall(syscall.SYS_WRITEV,
58 uintptr(fd.Sysfd),
59 uintptr(unsafe.Pointer(&iovecs[0])),
60 uintptr(len(iovecs)))
61 if wrote == ^uintptr(0) {
62 wrote = 0
64 TestHookDidWritev(int(wrote))
65 n += int64(wrote)
66 consume(v, int64(wrote))
67 if e0 == syscall.EAGAIN {
68 if err = fd.pd.waitWrite(fd.isFile); err == nil {
69 continue
71 } else if e0 != 0 {
72 err = syscall.Errno(e0)
74 if err != nil {
75 break
77 if n == 0 {
78 err = io.ErrUnexpectedEOF
79 break
82 return n, err