]> Cypherpunks repositories - gostls13.git/commitdiff
net: reduce allocations for UDP send/recv on Windows
authorJosh Bleecher Snyder <josharian@gmail.com>
Mon, 28 Jun 2021 22:41:20 +0000 (15:41 -0700)
committerDamien Neil <dneil@google.com>
Mon, 16 Aug 2021 23:57:10 +0000 (23:57 +0000)
This brings the optimizations added in CLs 331489 and 331490 to Windows.

Updates #43451

Change-Id: I75cf520050325d9eb5c2785d6d8677cc864fcac8
Reviewed-on: https://go-review.googlesource.com/c/go/+/331511
Trust: Josh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
api/next.txt
src/internal/poll/fd_windows.go
src/syscall/syscall_windows.go

index 4dbaae3cf205af4f86f0d96798b924ba606248a7..3eb7f3f797fdbabefe3c14e5dac81e1ef4fc88f7 100644 (file)
@@ -102,3 +102,7 @@ pkg syscall (openbsd-amd64-cgo), func RecvfromInet4(int, []uint8, int, *Sockaddr
 pkg syscall (openbsd-amd64-cgo), func RecvfromInet6(int, []uint8, int, *SockaddrInet6) (int, error)
 pkg syscall (openbsd-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
 pkg syscall (openbsd-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
+pkg syscall (windows-386), func WSASendtoInet4(Handle, *WSABuf, uint32, *uint32, uint32, SockaddrInet4, *Overlapped, *uint8) error
+pkg syscall (windows-386), func WSASendtoInet6(Handle, *WSABuf, uint32, *uint32, uint32, SockaddrInet6, *Overlapped, *uint8) error
+pkg syscall (windows-amd64), func WSASendtoInet4(Handle, *WSABuf, uint32, *uint32, uint32, SockaddrInet4, *Overlapped, *uint8) error
+pkg syscall (windows-amd64), func WSASendtoInet6(Handle, *WSABuf, uint32, *uint32, uint32, SockaddrInet6, *Overlapped, *uint8) error
index 14e8f4965b963eb0796da8971d7df9aa624a5c92..48fcdf306cfe7591adbf0b5a78fc328c678ed76d 100644 (file)
@@ -79,6 +79,8 @@ type operation struct {
        buf    syscall.WSABuf
        msg    windows.WSAMsg
        sa     syscall.Sockaddr
+       sa4    syscall.SockaddrInet4
+       sa6    syscall.SockaddrInet6
        rsa    *syscall.RawSockaddrAny
        rsan   int32
        handle syscall.Handle
@@ -595,7 +597,30 @@ func (fd *FD) ReadFrom(buf []byte) (int, syscall.Sockaddr, error) {
 
 // ReadFrom wraps the recvfrom network call for IPv4.
 func (fd *FD) ReadFromInet4(buf []byte, sa4 *syscall.SockaddrInet4) (int, error) {
-       n, sa, err := fd.ReadFrom(buf)
+       if len(buf) == 0 {
+               return 0, nil
+       }
+       if len(buf) > maxRW {
+               buf = buf[:maxRW]
+       }
+       if err := fd.readLock(); err != nil {
+               return 0, err
+       }
+       defer fd.readUnlock()
+       o := &fd.rop
+       o.InitBuf(buf)
+       n, err := execIO(o, func(o *operation) error {
+               if o.rsa == nil {
+                       o.rsa = new(syscall.RawSockaddrAny)
+               }
+               o.rsan = int32(unsafe.Sizeof(*o.rsa))
+               return syscall.WSARecvFrom(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil)
+       })
+       err = fd.eofError(n, err)
+       if err != nil {
+               return n, err
+       }
+       sa, _ := o.rsa.Sockaddr()
        if sa != nil {
                *sa4 = *(sa.(*syscall.SockaddrInet4))
        }
@@ -604,7 +629,30 @@ func (fd *FD) ReadFromInet4(buf []byte, sa4 *syscall.SockaddrInet4) (int, error)
 
 // ReadFrom wraps the recvfrom network call for IPv6.
 func (fd *FD) ReadFromInet6(buf []byte, sa6 *syscall.SockaddrInet6) (int, error) {
-       n, sa, err := fd.ReadFrom(buf)
+       if len(buf) == 0 {
+               return 0, nil
+       }
+       if len(buf) > maxRW {
+               buf = buf[:maxRW]
+       }
+       if err := fd.readLock(); err != nil {
+               return 0, err
+       }
+       defer fd.readUnlock()
+       o := &fd.rop
+       o.InitBuf(buf)
+       n, err := execIO(o, func(o *operation) error {
+               if o.rsa == nil {
+                       o.rsa = new(syscall.RawSockaddrAny)
+               }
+               o.rsan = int32(unsafe.Sizeof(*o.rsa))
+               return syscall.WSARecvFrom(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil)
+       })
+       err = fd.eofError(n, err)
+       if err != nil {
+               return n, err
+       }
+       sa, _ := o.rsa.Sockaddr()
        if sa != nil {
                *sa6 = *(sa.(*syscall.SockaddrInet6))
        }
@@ -810,8 +858,42 @@ func (fd *FD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
 }
 
 // WriteTo wraps the sendto network call for IPv4.
-func (fd *FD) WriteToInet4(buf []byte, sa syscall.SockaddrInet4) (int, error) {
-       return fd.WriteTo(buf, &sa)
+func (fd *FD) WriteToInet4(buf []byte, sa4 syscall.SockaddrInet4) (int, error) {
+       if err := fd.writeLock(); err != nil {
+               return 0, err
+       }
+       defer fd.writeUnlock()
+
+       if len(buf) == 0 {
+               // handle zero-byte payload
+               o := &fd.wop
+               o.InitBuf(buf)
+               o.sa4 = sa4
+               n, err := execIO(o, func(o *operation) error {
+                       return syscall.WSASendtoInet4(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, o.sa4, &o.o, nil)
+               })
+               return n, err
+       }
+
+       ntotal := 0
+       for len(buf) > 0 {
+               b := buf
+               if len(b) > maxRW {
+                       b = b[:maxRW]
+               }
+               o := &fd.wop
+               o.InitBuf(b)
+               o.sa4 = sa4
+               n, err := execIO(o, func(o *operation) error {
+                       return syscall.WSASendtoInet4(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, o.sa4, &o.o, nil)
+               })
+               ntotal += int(n)
+               if err != nil {
+                       return ntotal, err
+               }
+               buf = buf[n:]
+       }
+       return ntotal, nil
 }
 
 // WriteTo wraps the sendto network call for IPv6.
index 660179ae9e8cf32ddccb2e09b3ac45dbf136f860..d4e51e541d1f09bb75c1497ad175f5f37c73e78c 100644 (file)
@@ -924,6 +924,38 @@ func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32
        return err
 }
 
+func WSASendtoInet4(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to SockaddrInet4, overlapped *Overlapped, croutine *byte) (err error) {
+       rsa, len, err := to.sockaddr()
+       if err != nil {
+               return err
+       }
+       r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(rsa)), uintptr(len), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
+       if r1 == socket_error {
+               if e1 != 0 {
+                       err = errnoErr(e1)
+               } else {
+                       err = EINVAL
+               }
+       }
+       return err
+}
+
+func WSASendtoInet6(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to SockaddrInet6, overlapped *Overlapped, croutine *byte) (err error) {
+       rsa, len, err := to.sockaddr()
+       if err != nil {
+               return err
+       }
+       r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(rsa)), uintptr(len), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
+       if r1 == socket_error {
+               if e1 != 0 {
+                       err = errnoErr(e1)
+               } else {
+                       err = EINVAL
+               }
+       }
+       return err
+}
+
 func LoadGetAddrInfo() error {
        return procGetAddrInfoW.Find()
 }