From: Yasuhiro Matsumoto Date: Sat, 11 Jun 2011 03:24:48 +0000 (+1000) Subject: net: Sendfile for win32. X-Git-Tag: weekly.2011-06-16~67 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=13740973814ebfe11c76caa576a75b0c6f9be352;p=gostls13.git net: Sendfile for win32. implement using TransmitFile(). R=bsiegert, bradfitz, alex.brainman, rsc, go.peter.90 CC=golang-dev https://golang.org/cl/4536076 --- diff --git a/src/pkg/net/Makefile b/src/pkg/net/Makefile index 5472df3925..c762122f2d 100644 --- a/src/pkg/net/Makefile +++ b/src/pkg/net/Makefile @@ -82,7 +82,7 @@ GOFILES_windows=\ file_windows.go\ interface_stub.go\ resolv_windows.go\ - sendfile_stub.go\ + sendfile_windows.go\ sock_windows.go\ GOFILES+=$(GOFILES_$(GOOS)) diff --git a/src/pkg/net/sendfile_windows.go b/src/pkg/net/sendfile_windows.go new file mode 100644 index 0000000000..34abc5490b --- /dev/null +++ b/src/pkg/net/sendfile_windows.go @@ -0,0 +1,68 @@ +// Copyright 2011 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. + +package net + +import ( + "io" + "os" + "syscall" +) + +type sendfileOp struct { + anOp + src int32 // source + n uint32 +} + +func (o *sendfileOp) Submit() (errno int) { + return syscall.TransmitFile(int32(o.fd.sysfd), o.src, o.n, 0, &o.o, nil, syscall.TF_WRITE_BEHIND) +} + +func (o *sendfileOp) Name() string { + return "TransmitFile" +} + +// sendFile copies the contents of r to c using the TransmitFile +// system call to minimize copies. +// +// if handled == true, sendFile returns the number of bytes copied and any +// non-EOF error. +// +// if handled == false, sendFile performed no work. +// +// Note that sendfile for windows does not suppport >2GB file. +func sendFile(c *netFD, r io.Reader) (written int64, err os.Error, handled bool) { + var n int64 = 0 // by default, copy until EOF + + lr, ok := r.(*io.LimitedReader) + if ok { + n, r = lr.N, lr.R + if n <= 0 { + return 0, nil, true + } + } + f, ok := r.(*os.File) + if !ok { + return 0, nil, false + } + + c.wio.Lock() + defer c.wio.Unlock() + c.incref() + defer c.decref() + + var o sendfileOp + o.Init(c) + o.n = uint32(n) + o.src = int32(f.Fd()) + done, err := iosrv.ExecIO(&o, 0) + if err != nil { + return 0, err, false + } + if lr != nil { + lr.N -= int64(done) + } + return int64(done), nil, true +} diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go index d01664d126..c9bcb37ecb 100644 --- a/src/pkg/syscall/syscall_windows.go +++ b/src/pkg/syscall/syscall_windows.go @@ -173,6 +173,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno //sys FlushViewOfFile(addr uintptr, length uintptr) (errno int) //sys VirtualLock(addr uintptr, length uintptr) (errno int) //sys VirtualUnlock(addr uintptr, length uintptr) (errno int) +//sys TransmitFile(s int32, handle int32, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) = wsock32.TransmitFile // syscall interface implementation for other packages diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go index 447b09043e..c72cf7351c 100644 --- a/src/pkg/syscall/zsyscall_windows_386.go +++ b/src/pkg/syscall/zsyscall_windows_386.go @@ -77,6 +77,7 @@ var ( procFlushViewOfFile = getSysProcAddr(modkernel32, "FlushViewOfFile") procVirtualLock = getSysProcAddr(modkernel32, "VirtualLock") procVirtualUnlock = getSysProcAddr(modkernel32, "VirtualUnlock") + procTransmitFile = getSysProcAddr(modwsock32, "TransmitFile") procWSAStartup = getSysProcAddr(modwsock32, "WSAStartup") procWSACleanup = getSysProcAddr(modwsock32, "WSACleanup") procsocket = getSysProcAddr(modwsock32, "socket") @@ -1008,6 +1009,20 @@ func VirtualUnlock(addr uintptr, length uintptr) (errno int) { return } +func TransmitFile(s int32, handle int32, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) { + r1, _, e1 := Syscall9(procTransmitFile, 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0) + if int(r1) == 0 { + if e1 != 0 { + errno = int(e1) + } else { + errno = EINVAL + } + } else { + errno = 0 + } + return +} + func WSAStartup(verreq uint32, data *WSAData) (sockerrno int) { r0, _, _ := Syscall(procWSAStartup, 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0) sockerrno = int(r0) diff --git a/src/pkg/syscall/ztypes_windows_386.go b/src/pkg/syscall/ztypes_windows_386.go index b04fea5766..30939f58f7 100644 --- a/src/pkg/syscall/ztypes_windows_386.go +++ b/src/pkg/syscall/ztypes_windows_386.go @@ -545,3 +545,19 @@ type DNSRecord struct { Reserved uint32 Data [40]byte } + +const ( + TF_DISCONNECT = 1 + TF_REUSE_SOCKET = 2 + TF_WRITE_BEHIND = 4 + TF_USE_DEFAULT_WORKER = 0 + TF_USE_SYSTEM_THREAD = 16 + TF_USE_KERNEL_APC = 32 +) + +type TransmitFileBuffers struct { + Head uintptr + HeadLength uint32 + Tail uintptr + TailLength uint32 +}