From: Josh Bleecher Snyder Date: Wed, 3 Nov 2021 21:08:43 +0000 (-0700) Subject: net: remove the alloc from WriteMsgUDPAddrPort X-Git-Tag: go1.18beta1~529 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=bfd74fd4228009bb9243c1836f9886ba1ad56e15;p=gostls13.git net: remove the alloc from WriteMsgUDPAddrPort name old time/op new time/op delta ReadWriteMsgUDPAddrPort-8 5.12µs ± 8% 4.59µs ± 3% -10.19% (p=0.000 n=10+9) name old alloc/op new alloc/op delta ReadWriteMsgUDPAddrPort-8 64.0B ± 0% 32.0B ± 0% -50.00% (p=0.000 n=10+10) name old allocs/op new allocs/op delta ReadWriteMsgUDPAddrPort-8 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.000 n=10+10) Change-Id: Idf540b2f9f8035660305a0ab1cfc3e162569db63 Reviewed-on: https://go-review.googlesource.com/c/go/+/361257 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- diff --git a/src/internal/poll/fd_unix.go b/src/internal/poll/fd_unix.go index fd5ac85850..b090e5b6bd 100644 --- a/src/internal/poll/fd_unix.go +++ b/src/internal/poll/fd_unix.go @@ -485,6 +485,58 @@ func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, err } } +// WriteMsgInet4 is WriteMsg specialized for syscall.SockaddrInet4. +func (fd *FD) WriteMsgInet4(p []byte, oob []byte, sa syscall.SockaddrInet4) (int, int, error) { + if err := fd.writeLock(); err != nil { + return 0, 0, err + } + defer fd.writeUnlock() + if err := fd.pd.prepareWrite(fd.isFile); err != nil { + return 0, 0, err + } + for { + n, err := unix.SendmsgNInet4(fd.Sysfd, p, oob, sa, 0) + if err == syscall.EINTR { + continue + } + if err == syscall.EAGAIN && fd.pd.pollable() { + if err = fd.pd.waitWrite(fd.isFile); err == nil { + continue + } + } + if err != nil { + return n, 0, err + } + return n, len(oob), err + } +} + +// WriteMsgInet6 is WriteMsg specialized for syscall.SockaddrInet6. +func (fd *FD) WriteMsgInet6(p []byte, oob []byte, sa syscall.SockaddrInet6) (int, int, error) { + if err := fd.writeLock(); err != nil { + return 0, 0, err + } + defer fd.writeUnlock() + if err := fd.pd.prepareWrite(fd.isFile); err != nil { + return 0, 0, err + } + for { + n, err := unix.SendmsgNInet6(fd.Sysfd, p, oob, sa, 0) + if err == syscall.EINTR { + continue + } + if err == syscall.EAGAIN && fd.pd.pollable() { + if err = fd.pd.waitWrite(fd.isFile); err == nil { + continue + } + } + if err != nil { + return n, 0, err + } + return n, len(oob), err + } +} + // Accept wraps the accept network call. func (fd *FD) Accept() (int, syscall.Sockaddr, string, error) { if err := fd.readLock(); err != nil { diff --git a/src/internal/poll/fd_windows.go b/src/internal/poll/fd_windows.go index 139f78a7c1..f8fc4de75d 100644 --- a/src/internal/poll/fd_windows.go +++ b/src/internal/poll/fd_windows.go @@ -1128,25 +1128,35 @@ func (fd *FD) RawWrite(f func(uintptr) bool) error { return syscall.EWINDOWS } +func sockaddrInet4ToRaw(sa syscall.SockaddrInet4) (unsafe.Pointer, int32) { + var raw syscall.RawSockaddrInet4 + raw.Family = syscall.AF_INET + p := (*[2]byte)(unsafe.Pointer(&raw.Port)) + p[0] = byte(sa.Port >> 8) + p[1] = byte(sa.Port) + raw.Addr = sa.Addr + return unsafe.Pointer(&raw), int32(unsafe.Sizeof(raw)) +} + +func sockaddrInet6ToRaw(sa syscall.SockaddrInet6) (unsafe.Pointer, int32) { + var raw syscall.RawSockaddrInet6 + raw.Family = syscall.AF_INET6 + p := (*[2]byte)(unsafe.Pointer(&raw.Port)) + p[0] = byte(sa.Port >> 8) + p[1] = byte(sa.Port) + raw.Scope_id = sa.ZoneId + raw.Addr = sa.Addr + return unsafe.Pointer(&raw), int32(unsafe.Sizeof(raw)) +} + func sockaddrToRaw(sa syscall.Sockaddr) (unsafe.Pointer, int32, error) { switch sa := sa.(type) { case *syscall.SockaddrInet4: - var raw syscall.RawSockaddrInet4 - raw.Family = syscall.AF_INET - p := (*[2]byte)(unsafe.Pointer(&raw.Port)) - p[0] = byte(sa.Port >> 8) - p[1] = byte(sa.Port) - raw.Addr = sa.Addr - return unsafe.Pointer(&raw), int32(unsafe.Sizeof(raw)), nil + ptr, sz := sockaddrInet4ToRaw(*sa) + return ptr, sz, nil case *syscall.SockaddrInet6: - var raw syscall.RawSockaddrInet6 - raw.Family = syscall.AF_INET6 - p := (*[2]byte)(unsafe.Pointer(&raw.Port)) - p[0] = byte(sa.Port >> 8) - p[1] = byte(sa.Port) - raw.Scope_id = sa.ZoneId - raw.Addr = sa.Addr - return unsafe.Pointer(&raw), int32(unsafe.Sizeof(raw)), nil + ptr, sz := sockaddrInet6ToRaw(*sa) + return ptr, sz, nil default: return nil, 0, syscall.EWINDOWS } @@ -1206,3 +1216,47 @@ func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, err }) return n, int(o.msg.Control.Len), err } + +// WriteMsgInet4 is WriteMsg specialized for syscall.SockaddrInet4. +func (fd *FD) WriteMsgInet4(p []byte, oob []byte, sa syscall.SockaddrInet4) (int, int, error) { + if len(p) > maxRW { + return 0, 0, errors.New("packet is too large (only 1GB is allowed)") + } + + if err := fd.writeLock(); err != nil { + return 0, 0, err + } + defer fd.writeUnlock() + + o := &fd.wop + o.InitMsg(p, oob) + rsa, len := sockaddrInet4ToRaw(sa) + o.msg.Name = (syscall.Pointer)(rsa) + o.msg.Namelen = len + n, err := execIO(o, func(o *operation) error { + return windows.WSASendMsg(o.fd.Sysfd, &o.msg, 0, &o.qty, &o.o, nil) + }) + return n, int(o.msg.Control.Len), err +} + +// WriteMsgInet6 is WriteMsg specialized for syscall.SockaddrInet6. +func (fd *FD) WriteMsgInet6(p []byte, oob []byte, sa syscall.SockaddrInet6) (int, int, error) { + if len(p) > maxRW { + return 0, 0, errors.New("packet is too large (only 1GB is allowed)") + } + + if err := fd.writeLock(); err != nil { + return 0, 0, err + } + defer fd.writeUnlock() + + o := &fd.wop + o.InitMsg(p, oob) + rsa, len := sockaddrInet6ToRaw(sa) + o.msg.Name = (syscall.Pointer)(rsa) + o.msg.Namelen = len + n, err := execIO(o, func(o *operation) error { + return windows.WSASendMsg(o.fd.Sysfd, &o.msg, 0, &o.qty, &o.o, nil) + }) + return n, int(o.msg.Control.Len), err +} diff --git a/src/internal/syscall/unix/net.go b/src/internal/syscall/unix/net.go index 773cf34d96..71e50f54c3 100644 --- a/src/internal/syscall/unix/net.go +++ b/src/internal/syscall/unix/net.go @@ -26,3 +26,11 @@ func SendtoInet4(fd int, p []byte, flags int, to syscall.SockaddrInet4) (err err //go:linkname SendtoInet6 syscall.sendtoInet6 //go:noescape func SendtoInet6(fd int, p []byte, flags int, to syscall.SockaddrInet6) (err error) + +//go:linkname SendmsgNInet4 syscall.sendmsgNInet4 +//go:noescape +func SendmsgNInet4(fd int, p, oob []byte, to syscall.SockaddrInet4, flags int) (n int, err error) + +//go:linkname SendmsgNInet6 syscall.sendmsgNInet6 +//go:noescape +func SendmsgNInet6(fd int, p, oob []byte, to syscall.SockaddrInet6, flags int) (n int, err error) diff --git a/src/internal/syscall/unix/net_js.go b/src/internal/syscall/unix/net_js.go index 3fc5a66470..35bc687b58 100644 --- a/src/internal/syscall/unix/net_js.go +++ b/src/internal/syscall/unix/net_js.go @@ -26,3 +26,11 @@ func SendtoInet4(fd int, p []byte, flags int, to syscall.SockaddrInet4) (err err func SendtoInet6(fd int, p []byte, flags int, to syscall.SockaddrInet6) (err error) { return syscall.ENOSYS } + +func SendmsgNInet4(fd int, p, oob []byte, to syscall.SockaddrInet4, flags int) (n int, err error) { + return 0, syscall.ENOSYS +} + +func SendmsgNInet6(fd int, p, oob []byte, to syscall.SockaddrInet6, flags int) (n int, err error) { + return 0, syscall.ENOSYS +} diff --git a/src/net/fd_posix.go b/src/net/fd_posix.go index 1887a45186..edcef1f2e1 100644 --- a/src/net/fd_posix.go +++ b/src/net/fd_posix.go @@ -110,6 +110,18 @@ func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob return n, oobn, wrapSyscallError(writeMsgSyscallName, err) } +func (fd *netFD) writeMsgInet4(p []byte, oob []byte, sa syscall.SockaddrInet4) (n int, oobn int, err error) { + n, oobn, err = fd.pfd.WriteMsgInet4(p, oob, sa) + runtime.KeepAlive(fd) + return n, oobn, wrapSyscallError(writeMsgSyscallName, err) +} + +func (fd *netFD) writeMsgInet6(p []byte, oob []byte, sa syscall.SockaddrInet6) (n int, oobn int, err error) { + n, oobn, err = fd.pfd.WriteMsgInet6(p, oob, sa) + runtime.KeepAlive(fd) + return n, oobn, wrapSyscallError(writeMsgSyscallName, err) +} + func (fd *netFD) SetDeadline(t time.Time) error { return fd.pfd.SetDeadline(t) } diff --git a/src/net/net_fake.go b/src/net/net_fake.go index d58bd82029..2ade9f7774 100644 --- a/src/net/net_fake.go +++ b/src/net/net_fake.go @@ -279,6 +279,14 @@ func (fd *netFD) readMsg(p []byte, oob []byte, flags int) (n, oobn, retflags int return 0, 0, 0, nil, syscall.ENOSYS } +func (fd *netFD) writeMsgInet4(p []byte, oob []byte, sa syscall.SockaddrInet4) (n int, oobn int, err error) { + return 0, 0, syscall.ENOSYS +} + +func (fd *netFD) writeMsgInet6(p []byte, oob []byte, sa syscall.SockaddrInet6) (n int, oobn int, err error) { + return 0, 0, syscall.ENOSYS +} + func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) { return 0, syscall.ENOSYS } diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go index c93994f836..468afbc4dc 100644 --- a/src/net/udpsock_posix.go +++ b/src/net/udpsock_posix.go @@ -188,15 +188,13 @@ func (c *UDPConn) writeMsgAddrPort(b, oob []byte, addr netip.AddrPort) (n, oobn if err != nil { return 0, 0, err } - // TODO: Implement writeMsgInet4 to avoid allocation converting sa to an interface. - return c.fd.writeMsg(b, oob, &sa) + return c.fd.writeMsgInet4(b, oob, sa) case syscall.AF_INET6: sa, err := addrPortToSockaddrInet6(addr) if err != nil { return 0, 0, err } - // TODO: Implement writeMsgInet6 to avoid allocation converting sa to an interface. - return c.fd.writeMsg(b, oob, &sa) + return c.fd.writeMsgInet6(b, oob, sa) default: return 0, 0, &AddrError{Err: "invalid address family", Addr: addr.Addr().String()} } diff --git a/src/syscall/syscall_unix.go b/src/syscall/syscall_unix.go index d1ecc361c6..8692a65794 100644 --- a/src/syscall/syscall_unix.go +++ b/src/syscall/syscall_unix.go @@ -351,6 +351,22 @@ func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) return sendmsgN(fd, p, oob, ptr, salen, flags) } +func sendmsgNInet4(fd int, p, oob []byte, to SockaddrInet4, flags int) (n int, err error) { + ptr, salen, err := to.sockaddr() + if err != nil { + return 0, err + } + return sendmsgN(fd, p, oob, ptr, salen, flags) +} + +func sendmsgNInet6(fd int, p, oob []byte, to SockaddrInet6, flags int) (n int, err error) { + ptr, salen, err := to.sockaddr() + if err != nil { + return 0, err + } + return sendmsgN(fd, p, oob, ptr, salen, flags) +} + func sendtoInet4(fd int, p []byte, flags int, to SockaddrInet4) (err error) { ptr, n, err := to.sockaddr() if err != nil {