github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/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 "unsafe" 13 ) 14 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 19 } 20 defer fd.writeUnlock() 21 if err := fd.pd.prepareWrite(); 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 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 41 } 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 46 } 47 iovecs[len(iovecs)-1].SetLen(len(chunk)) 48 if len(iovecs) == maxVec { 49 break 50 } 51 } 52 if len(iovecs) == 0 { 53 break 54 } 55 fd.iovecs = &iovecs // cache 56 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 63 } 64 TestHookDidWritev(int(wrote)) 65 n += int64(wrote) 66 consume(v, int64(wrote)) 67 if e0 == syscall.EAGAIN { 68 if err = fd.pd.waitWrite(); err == nil { 69 continue 70 } 71 } else if e0 != 0 { 72 err = syscall.Errno(e0) 73 } 74 if err != nil { 75 break 76 } 77 if n == 0 { 78 err = io.ErrUnexpectedEOF 79 break 80 } 81 } 82 return n, err 83 }