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. 4 5//go:build unix 6 7package poll 8 9import ( 10 "io" 11 "runtime" 12 "syscall" 13) 14 15// Writev wraps the writev system call. 16func (fd *FD) Writev(v *[][]byte) (int64, error) { 17 if err := fd.writeLock(); err != nil { 18 return 0, err 19 } 20 defer fd.writeUnlock() 21 if err := fd.pd.prepareWrite(fd.isFile); err != nil { 22 return 0, err 23 } 24 25 var iovecs []syscall.Iovec 26 if fd.iovecs != nil { 27 iovecs = *fd.iovecs 28 } 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 33 if runtime.GOOS == "aix" || runtime.GOOS == "solaris" { 34 // IOV_MAX is set to XOPEN_IOV_MAX on AIX and Solaris. 35 maxVec = 16 36 } 37 38 var n int64 39 var err error 40 for len(*v) > 0 { 41 iovecs = iovecs[:0] 42 for _, chunk := range *v { 43 if len(chunk) == 0 { 44 continue 45 } 46 iovecs = append(iovecs, newIovecWithBase(&chunk[0])) 47 if fd.IsStream && len(chunk) > 1<<30 { 48 iovecs[len(iovecs)-1].SetLen(1 << 30) 49 break // continue chunk on next writev 50 } 51 iovecs[len(iovecs)-1].SetLen(len(chunk)) 52 if len(iovecs) == maxVec { 53 break 54 } 55 } 56 if len(iovecs) == 0 { 57 break 58 } 59 if fd.iovecs == nil { 60 fd.iovecs = new([]syscall.Iovec) 61 } 62 *fd.iovecs = iovecs // cache 63 64 var wrote uintptr 65 wrote, err = writev(fd.Sysfd, iovecs) 66 if wrote == ^uintptr(0) { 67 wrote = 0 68 } 69 TestHookDidWritev(int(wrote)) 70 n += int64(wrote) 71 consume(v, int64(wrote)) 72 clear(iovecs) 73 if err != nil { 74 if err == syscall.EINTR { 75 continue 76 } 77 if err == syscall.EAGAIN { 78 if err = fd.pd.waitWrite(fd.isFile); err == nil { 79 continue 80 } 81 } 82 break 83 } 84 if n == 0 { 85 err = io.ErrUnexpectedEOF 86 break 87 } 88 } 89 return n, err 90} 91