github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/net/writev_unix.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 net 8 9 import ( 10 "io" 11 "os" 12 "syscall" 13 "unsafe" 14 ) 15 16 func (c *conn) writeBuffers(v *Buffers) (int64, error) { 17 if !c.ok() { 18 return 0, syscall.EINVAL 19 } 20 n, err := c.fd.writeBuffers(v) 21 if err != nil { 22 return n, &OpError{Op: "writev", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} 23 } 24 return n, nil 25 } 26 27 func (fd *netFD) writeBuffers(v *Buffers) (n int64, err error) { 28 if err := fd.writeLock(); err != nil { 29 return 0, err 30 } 31 defer fd.writeUnlock() 32 if err := fd.pd.prepareWrite(); err != nil { 33 return 0, err 34 } 35 36 var iovecs []syscall.Iovec 37 if fd.iovecs != nil { 38 iovecs = *fd.iovecs 39 } 40 // TODO: read from sysconf(_SC_IOV_MAX)? The Linux default is 41 // 1024 and this seems conservative enough for now. Darwin's 42 // UIO_MAXIOV also seems to be 1024. 43 maxVec := 1024 44 45 for len(*v) > 0 { 46 iovecs = iovecs[:0] 47 for _, chunk := range *v { 48 if len(chunk) == 0 { 49 continue 50 } 51 iovecs = append(iovecs, syscall.Iovec{Base: &chunk[0]}) 52 if fd.isStream && len(chunk) > 1<<30 { 53 iovecs[len(iovecs)-1].SetLen(1 << 30) 54 break // continue chunk on next writev 55 } 56 iovecs[len(iovecs)-1].SetLen(len(chunk)) 57 if len(iovecs) == maxVec { 58 break 59 } 60 } 61 if len(iovecs) == 0 { 62 break 63 } 64 fd.iovecs = &iovecs // cache 65 66 wrote, _, e0 := syscall.Syscall(syscall.SYS_WRITEV, 67 uintptr(fd.sysfd), 68 uintptr(unsafe.Pointer(&iovecs[0])), 69 uintptr(len(iovecs))) 70 if wrote == ^uintptr(0) { 71 wrote = 0 72 } 73 testHookDidWritev(int(wrote)) 74 n += int64(wrote) 75 v.consume(int64(wrote)) 76 if e0 == syscall.EAGAIN { 77 if err = fd.pd.waitWrite(); err == nil { 78 continue 79 } 80 } else if e0 != 0 { 81 err = syscall.Errno(e0) 82 } 83 if err != nil { 84 break 85 } 86 if n == 0 { 87 err = io.ErrUnexpectedEOF 88 break 89 } 90 } 91 if _, ok := err.(syscall.Errno); ok { 92 err = os.NewSyscallError("writev", err) 93 } 94 return n, err 95 }