github.com/icodeface/tls@v0.0.0-20230910023335-34df9250cd12/internal/poll/writev.go (about) 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 // +build darwin dragonfly freebsd linux netbsd openbsd 6 7 package poll 8 9 import ( 10 "io" 11 "syscall" 12 ) 13 14 // Writev wraps the writev system call. 15 func (fd *FD) Writev(v *[][]byte) (int64, error) { 16 if err := fd.writeLock(); err != nil { 17 return 0, err 18 } 19 defer fd.writeUnlock() 20 if err := fd.pd.prepareWrite(fd.isFile); err != nil { 21 return 0, err 22 } 23 24 var iovecs []syscall.Iovec 25 if fd.iovecs != nil { 26 iovecs = *fd.iovecs 27 } 28 // TODO: read from sysconf(_SC_IOV_MAX)? The Linux default is 29 // 1024 and this seems conservative enough for now. Darwin's 30 // UIO_MAXIOV also seems to be 1024. 31 maxVec := 1024 32 33 var n int64 34 var err error 35 for len(*v) > 0 { 36 iovecs = iovecs[:0] 37 for _, chunk := range *v { 38 if len(chunk) == 0 { 39 continue 40 } 41 iovecs = append(iovecs, syscall.Iovec{Base: &chunk[0]}) 42 if fd.IsStream && len(chunk) > 1<<30 { 43 iovecs[len(iovecs)-1].SetLen(1 << 30) 44 break // continue chunk on next writev 45 } 46 iovecs[len(iovecs)-1].SetLen(len(chunk)) 47 if len(iovecs) == maxVec { 48 break 49 } 50 } 51 if len(iovecs) == 0 { 52 break 53 } 54 fd.iovecs = &iovecs // cache 55 56 var wrote uintptr 57 wrote, err = writev(fd.Sysfd, iovecs) 58 if wrote == ^uintptr(0) { 59 wrote = 0 60 } 61 TestHookDidWritev(int(wrote)) 62 n += int64(wrote) 63 consume(v, int64(wrote)) 64 if err != nil { 65 if err.(syscall.Errno) == syscall.EAGAIN { 66 if err = fd.pd.waitWrite(fd.isFile); err == nil { 67 continue 68 } 69 } 70 break 71 } 72 if n == 0 { 73 err = io.ErrUnexpectedEOF 74 break 75 } 76 } 77 return n, err 78 }