|  | // Copyright 2016 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | // +build darwin dragonfly freebsd linux netbsd openbsd | 
|  |  | 
|  | package poll | 
|  |  | 
|  | import ( | 
|  | "io" | 
|  | "syscall" | 
|  | ) | 
|  |  | 
|  | // Writev wraps the writev system call. | 
|  | func (fd *FD) Writev(v *[][]byte) (int64, error) { | 
|  | if err := fd.writeLock(); err != nil { | 
|  | return 0, err | 
|  | } | 
|  | defer fd.writeUnlock() | 
|  | if err := fd.pd.prepareWrite(fd.isFile); err != nil { | 
|  | return 0, err | 
|  | } | 
|  |  | 
|  | var iovecs []syscall.Iovec | 
|  | if fd.iovecs != nil { | 
|  | iovecs = *fd.iovecs | 
|  | } | 
|  | // TODO: read from sysconf(_SC_IOV_MAX)? The Linux default is | 
|  | // 1024 and this seems conservative enough for now. Darwin's | 
|  | // UIO_MAXIOV also seems to be 1024. | 
|  | maxVec := 1024 | 
|  |  | 
|  | var n int64 | 
|  | var err error | 
|  | for len(*v) > 0 { | 
|  | iovecs = iovecs[:0] | 
|  | for _, chunk := range *v { | 
|  | if len(chunk) == 0 { | 
|  | continue | 
|  | } | 
|  | iovecs = append(iovecs, syscall.Iovec{Base: &chunk[0]}) | 
|  | if fd.IsStream && len(chunk) > 1<<30 { | 
|  | iovecs[len(iovecs)-1].SetLen(1 << 30) | 
|  | break // continue chunk on next writev | 
|  | } | 
|  | iovecs[len(iovecs)-1].SetLen(len(chunk)) | 
|  | if len(iovecs) == maxVec { | 
|  | break | 
|  | } | 
|  | } | 
|  | if len(iovecs) == 0 { | 
|  | break | 
|  | } | 
|  | if fd.iovecs == nil { | 
|  | fd.iovecs = new([]syscall.Iovec) | 
|  | } | 
|  | *fd.iovecs = iovecs // cache | 
|  |  | 
|  | var wrote uintptr | 
|  | wrote, err = writev(fd.Sysfd, iovecs) | 
|  | if wrote == ^uintptr(0) { | 
|  | wrote = 0 | 
|  | } | 
|  | TestHookDidWritev(int(wrote)) | 
|  | n += int64(wrote) | 
|  | consume(v, int64(wrote)) | 
|  | for i := range iovecs { | 
|  | iovecs[i] = syscall.Iovec{} | 
|  | } | 
|  | if err != nil { | 
|  | if err == syscall.EINTR { | 
|  | continue | 
|  | } | 
|  | if err == syscall.EAGAIN { | 
|  | if err = fd.pd.waitWrite(fd.isFile); err == nil { | 
|  | continue | 
|  | } | 
|  | } | 
|  | break | 
|  | } | 
|  | if n == 0 { | 
|  | err = io.ErrUnexpectedEOF | 
|  | break | 
|  | } | 
|  | } | 
|  | return n, err | 
|  | } |