git-subtree-dir: ts git-subtree-mainline: 92528599badd9da7f5b10d64f10186a1646bb520 git-subtree-split: 7530d353fdefcc59d83c3c8ebea0a147dcbab234
136 lines
2.2 KiB
Go
136 lines
2.2 KiB
Go
package ts
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"os"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
type iovec struct {
|
|
data [][]byte
|
|
Len int
|
|
pos int
|
|
idx int
|
|
}
|
|
|
|
func (self *iovec) Prepend(b []byte) {
|
|
self.data = append([][]byte{b}, self.data...)
|
|
self.Len += len(b)
|
|
}
|
|
|
|
func (self *iovec) Append(b []byte) {
|
|
self.data = append(self.data, b)
|
|
self.Len += len(b)
|
|
}
|
|
|
|
func (self *iovec) WriteTo(w io.Writer, n int) (written int, err error) {
|
|
for n > 0 && self.Len > 0 {
|
|
data := self.data[self.idx]
|
|
|
|
var b []byte
|
|
if n > len(data) {
|
|
b = data
|
|
} else {
|
|
b = data[:n]
|
|
}
|
|
|
|
data = data[len(b):]
|
|
if len(data) == 0 {
|
|
self.idx++
|
|
} else {
|
|
self.data[self.idx] = data
|
|
}
|
|
self.Len -= len(b)
|
|
n -= len(b)
|
|
written += len(b)
|
|
|
|
if _, err = w.Write(b); err != nil {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
type sysiovec struct {
|
|
Base uintptr
|
|
Len uint64
|
|
}
|
|
|
|
type vecWriter struct {
|
|
fd uintptr
|
|
smallBytesBuf []byte
|
|
iov []sysiovec
|
|
}
|
|
|
|
func (self *vecWriter) Write(p []byte) (written int, err error) {
|
|
iov := sysiovec{
|
|
Len: uint64(len(p)),
|
|
}
|
|
|
|
if len(p) < 16 {
|
|
iov.Base = uintptr(len(self.smallBytesBuf))
|
|
self.smallBytesBuf = append(self.smallBytesBuf, p...)
|
|
} else {
|
|
iov.Base = uintptr(unsafe.Pointer(&p[0]))
|
|
}
|
|
|
|
self.iov = append(self.iov, iov)
|
|
return
|
|
}
|
|
|
|
func (self *vecWriter) Flush() (err error) {
|
|
for i := range self.iov {
|
|
iov := &self.iov[i]
|
|
if iov.Base < uintptr(len(self.smallBytesBuf)) {
|
|
iov.Base = uintptr(unsafe.Pointer(&self.smallBytesBuf[iov.Base]))
|
|
}
|
|
}
|
|
|
|
N := 1024
|
|
for i := 0; i < len(self.iov); i += N {
|
|
n := len(self.iov) - i
|
|
if n > N {
|
|
n = N
|
|
}
|
|
_, _, errno := syscall.Syscall(syscall.SYS_WRITEV, self.fd, uintptr(unsafe.Pointer(&self.iov[i])), uintptr(n))
|
|
if errno != 0 {
|
|
err = fmt.Errorf("writev failed with error: %d", errno)
|
|
return
|
|
}
|
|
}
|
|
|
|
if DebugWriter {
|
|
fmt.Printf("vecw: smallBytesBuf=%d iovNr=%d\n", len(self.smallBytesBuf), len(self.iov))
|
|
}
|
|
|
|
self.iov = self.iov[:0]
|
|
self.smallBytesBuf = self.smallBytesBuf[:0]
|
|
|
|
return
|
|
}
|
|
|
|
func newVecWriter(w io.Writer) (vecw *vecWriter) {
|
|
var err error
|
|
var f *os.File
|
|
|
|
switch obj := w.(type) {
|
|
case *net.TCPConn:
|
|
f, err = obj.File()
|
|
if err != nil {
|
|
return
|
|
}
|
|
case *os.File:
|
|
f = obj
|
|
default:
|
|
return
|
|
}
|
|
|
|
vecw = &vecWriter{
|
|
fd: f.Fd(),
|
|
}
|
|
return
|
|
}
|