1
0
mirror of https://github.com/golang/go synced 2024-11-20 07:54:39 -07:00

net: implement Buffers on windows

Updates #13451

Change-Id: I2c3c66d9532c16e616c476e2afe31b3ddc0a8d79
Reviewed-on: https://go-review.googlesource.com/32371
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Alex Brainman 2016-10-29 18:37:49 +11:00
parent c57a443e87
commit e22b5efb36
2 changed files with 78 additions and 4 deletions

View File

@ -96,6 +96,7 @@ type operation struct {
rsan int32
handle syscall.Handle
flags uint32
bufs []syscall.WSABuf
}
func (o *operation) InitBuf(buf []byte) {
@ -106,6 +107,30 @@ func (o *operation) InitBuf(buf []byte) {
}
}
func (o *operation) InitBufs(buf *Buffers) {
if o.bufs == nil {
o.bufs = make([]syscall.WSABuf, 0, len(*buf))
} else {
o.bufs = o.bufs[:0]
}
for _, b := range *buf {
var p *byte
if len(b) > 0 {
p = &b[0]
}
o.bufs = append(o.bufs, syscall.WSABuf{uint32(len(b)), p})
}
}
// ClearBufs clears all pointers to Buffers parameter captured
// by InitBufs, so it can be released by garbage collector.
func (o *operation) ClearBufs() {
for i := range o.bufs {
o.bufs[i].Buf = nil
}
o.bufs = o.bufs[:0]
}
// ioSrv executes net IO requests.
type ioSrv struct {
req chan ioSrvReq
@ -484,6 +509,42 @@ func (fd *netFD) Write(buf []byte) (int, error) {
return n, err
}
func (c *conn) writeBuffers(v *Buffers) (int64, error) {
if !c.ok() {
return 0, syscall.EINVAL
}
n, err := c.fd.writeBuffers(v)
if err != nil {
return n, &OpError{Op: "WSASend", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
}
return n, nil
}
func (fd *netFD) writeBuffers(buf *Buffers) (int64, error) {
if len(*buf) == 0 {
return 0, nil
}
if err := fd.writeLock(); err != nil {
return 0, err
}
defer fd.writeUnlock()
if race.Enabled {
race.ReleaseMerge(unsafe.Pointer(&ioSync))
}
o := &fd.wop
o.InitBufs(buf)
n, err := wsrv.ExecIO(o, "WSASend", func(o *operation) error {
return syscall.WSASend(o.fd.sysfd, &o.bufs[0], uint32(len(*buf)), &o.qty, 0, &o.o, nil)
})
o.ClearBufs()
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("wsasend", err)
}
testHookDidWritev(n)
buf.consume(int64(n))
return int64(n), err
}
func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
if len(buf) == 0 {
return 0, nil

View File

@ -150,18 +150,27 @@ func testBuffer_writeTo(t *testing.T, chunks int, useCopy bool) {
}
var wantSum int
var wantMinCalls int
switch runtime.GOOS {
case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd":
var wantMinCalls int
wantSum = want.Len()
v := chunks
for v > 0 {
wantMinCalls++
v -= 1024
}
}
if len(writeLog.log) < wantMinCalls {
t.Errorf("write calls = %v < wanted min %v", len(writeLog.log), wantMinCalls)
if len(writeLog.log) < wantMinCalls {
t.Errorf("write calls = %v < wanted min %v", len(writeLog.log), wantMinCalls)
}
case "windows":
var wantCalls int
wantSum = want.Len()
if wantSum > 0 {
wantCalls = 1 // windows will always do 1 syscall, unless sending empty buffer
}
if len(writeLog.log) != wantCalls {
t.Errorf("write calls = %v; want %v", len(writeLog.log), wantCalls)
}
}
if gotSum != wantSum {
t.Errorf("writev call sum = %v; want %v", gotSum, wantSum)
@ -171,6 +180,10 @@ func testBuffer_writeTo(t *testing.T, chunks int, useCopy bool) {
}
func TestWritevError(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skipf("skipping the test: windows does not have problem sending large chunks of data")
}
ln, err := newLocalListener("tcp")
if err != nil {
t.Fatal(err)