net: Sendfile for win32.

implement using TransmitFile().

R=bsiegert, bradfitz, alex.brainman, rsc, go.peter.90
CC=golang-dev
https://golang.org/cl/4536076
This commit is contained in:
Yasuhiro Matsumoto 2011-06-11 13:24:48 +10:00 committed by Alex Brainman
parent 968afa0e8c
commit 1374097381
5 changed files with 101 additions and 1 deletions

View File

@ -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))

View File

@ -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
}

View File

@ -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

View File

@ -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)

View File

@ -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
}