Skip to content

Commit 690fc2f

Browse files
committed
internal/poll: remove buf field from operation
WSASend and WSARecv functions capture the WSABuf structure before returning, so there is no need to keep a copy of it in the operation structure. Write and Read functions don't need it, they can operate directly on the byte slice. To be on the safe side, pin the input byte slice so that stack-allocated slices don't get moved while overlapped I/O is in progress. Cq-Include-Trybots: luci.golang.try:gotip-windows-amd64-longtest,gotip-windows-amd64-race Change-Id: I474bed94e11acafa0bdd8392b5dcf8993d8e1ed5 Reviewed-on: https://go-review.googlesource.com/c/go/+/704155 Reviewed-by: Junyang Shao <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Damien Neil <[email protected]>
1 parent eaf2345 commit 690fc2f

File tree

2 files changed

+100
-77
lines changed

2 files changed

+100
-77
lines changed

src/internal/poll/fd_windows.go

Lines changed: 95 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"internal/race"
1010
"internal/syscall/windows"
1111
"io"
12+
"runtime"
1213
"sync"
1314
"sync/atomic"
1415
"syscall"
@@ -75,9 +76,6 @@ type operation struct {
7576
// fields used by runtime.netpoll
7677
runtimeCtx uintptr
7778
mode int32
78-
79-
// fields used only by net package
80-
buf syscall.WSABuf
8179
}
8280

8381
func (o *operation) setEvent() {
@@ -107,9 +105,8 @@ func (fd *FD) overlapped(o *operation) *syscall.Overlapped {
107105
return &o.o
108106
}
109107

110-
func (o *operation) InitBuf(buf []byte) {
111-
o.buf.Len = uint32(len(buf))
112-
o.buf.Buf = unsafe.SliceData(buf)
108+
func newWsaBuf(b []byte) *syscall.WSABuf {
109+
return &syscall.WSABuf{Buf: unsafe.SliceData(b), Len: uint32(len(b))}
113110
}
114111

115112
var wsaBufsPool = sync.Pool{
@@ -362,6 +359,9 @@ type FD struct {
362359
isBlocking bool
363360

364361
disassociated atomic.Bool
362+
363+
readPinner runtime.Pinner
364+
writePinner runtime.Pinner
365365
}
366366

367367
// setOffset sets the offset fields of the overlapped object
@@ -537,6 +537,11 @@ func (fd *FD) Read(buf []byte) (int, error) {
537537
defer fd.readUnlock()
538538
}
539539

540+
if len(buf) > 0 && !fd.isBlocking {
541+
fd.readPinner.Pin(&buf[0])
542+
defer fd.readPinner.Unpin()
543+
}
544+
540545
if len(buf) > maxRW {
541546
buf = buf[:maxRW]
542547
}
@@ -547,10 +552,8 @@ func (fd *FD) Read(buf []byte) (int, error) {
547552
case kindConsole:
548553
n, err = fd.readConsole(buf)
549554
case kindFile, kindPipe:
550-
o := &fd.rop
551-
o.InitBuf(buf)
552-
n, err = fd.execIO(o, func(o *operation) (qty uint32, err error) {
553-
err = syscall.ReadFile(fd.Sysfd, unsafe.Slice(o.buf.Buf, o.buf.Len), &qty, fd.overlapped(o))
555+
n, err = fd.execIO(&fd.rop, func(o *operation) (qty uint32, err error) {
556+
err = syscall.ReadFile(fd.Sysfd, buf, &qty, fd.overlapped(o))
554557
return qty, err
555558
})
556559
fd.addOffset(n)
@@ -564,11 +567,9 @@ func (fd *FD) Read(buf []byte) (int, error) {
564567
}
565568
}
566569
case kindNet:
567-
o := &fd.rop
568-
o.InitBuf(buf)
569-
n, err = fd.execIO(o, func(o *operation) (qty uint32, err error) {
570+
n, err = fd.execIO(&fd.rop, func(o *operation) (qty uint32, err error) {
570571
var flags uint32
571-
err = syscall.WSARecv(fd.Sysfd, &o.buf, 1, &qty, &flags, &o.o, nil)
572+
err = syscall.WSARecv(fd.Sysfd, newWsaBuf(buf), 1, &qty, &flags, &o.o, nil)
572573
return qty, err
573574
})
574575
if race.Enabled {
@@ -656,7 +657,7 @@ func (fd *FD) readConsole(b []byte) (int, error) {
656657
}
657658

658659
// Pread emulates the Unix pread system call.
659-
func (fd *FD) Pread(b []byte, off int64) (int, error) {
660+
func (fd *FD) Pread(buf []byte, off int64) (int, error) {
660661
if fd.kind == kindPipe {
661662
// Pread does not work with pipes
662663
return 0, syscall.ESPIPE
@@ -667,8 +668,13 @@ func (fd *FD) Pread(b []byte, off int64) (int, error) {
667668
}
668669
defer fd.readWriteUnlock()
669670

670-
if len(b) > maxRW {
671-
b = b[:maxRW]
671+
if len(buf) > 0 && !fd.isBlocking {
672+
fd.readPinner.Pin(&buf[0])
673+
defer fd.readPinner.Unpin()
674+
}
675+
676+
if len(buf) > maxRW {
677+
buf = buf[:maxRW]
672678
}
673679

674680
if fd.isBlocking {
@@ -687,17 +693,15 @@ func (fd *FD) Pread(b []byte, off int64) (int, error) {
687693
curoffset := fd.offset
688694
defer fd.setOffset(curoffset)
689695
}
690-
o := &fd.rop
691-
o.InitBuf(b)
692696
fd.setOffset(off)
693-
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
694-
err = syscall.ReadFile(fd.Sysfd, unsafe.Slice(o.buf.Buf, o.buf.Len), &qty, &o.o)
697+
n, err := fd.execIO(&fd.rop, func(o *operation) (qty uint32, err error) {
698+
err = syscall.ReadFile(fd.Sysfd, buf, &qty, &o.o)
695699
return qty, err
696700
})
697701
if err == syscall.ERROR_HANDLE_EOF {
698702
err = io.EOF
699703
}
700-
if len(b) != 0 {
704+
if len(buf) != 0 {
701705
err = fd.eofError(n, err)
702706
}
703707
return n, err
@@ -715,14 +719,18 @@ func (fd *FD) ReadFrom(buf []byte) (int, syscall.Sockaddr, error) {
715719
return 0, nil, err
716720
}
717721
defer fd.readUnlock()
718-
o := &fd.rop
719-
o.InitBuf(buf)
722+
723+
if !fd.isBlocking {
724+
fd.readPinner.Pin(&buf[0])
725+
defer fd.readPinner.Unpin()
726+
}
727+
720728
rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
721729
defer wsaRsaPool.Put(rsa)
722-
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
730+
n, err := fd.execIO(&fd.rop, func(o *operation) (qty uint32, err error) {
723731
rsan := int32(unsafe.Sizeof(*rsa))
724732
var flags uint32
725-
err = syscall.WSARecvFrom(fd.Sysfd, &o.buf, 1, &qty, &flags, rsa, &rsan, &o.o, nil)
733+
err = syscall.WSARecvFrom(fd.Sysfd, newWsaBuf(buf), 1, &qty, &flags, rsa, &rsan, &o.o, nil)
726734
return qty, err
727735
})
728736
err = fd.eofError(n, err)
@@ -745,14 +753,18 @@ func (fd *FD) ReadFromInet4(buf []byte, sa4 *syscall.SockaddrInet4) (int, error)
745753
return 0, err
746754
}
747755
defer fd.readUnlock()
748-
o := &fd.rop
749-
o.InitBuf(buf)
756+
757+
if !fd.isBlocking {
758+
fd.readPinner.Pin(&buf[0])
759+
defer fd.readPinner.Unpin()
760+
}
761+
750762
rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
751763
defer wsaRsaPool.Put(rsa)
752-
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
764+
n, err := fd.execIO(&fd.rop, func(o *operation) (qty uint32, err error) {
753765
rsan := int32(unsafe.Sizeof(*rsa))
754766
var flags uint32
755-
err = syscall.WSARecvFrom(fd.Sysfd, &o.buf, 1, &qty, &flags, rsa, &rsan, &o.o, nil)
767+
err = syscall.WSARecvFrom(fd.Sysfd, newWsaBuf(buf), 1, &qty, &flags, rsa, &rsan, &o.o, nil)
756768
return qty, err
757769
})
758770
err = fd.eofError(n, err)
@@ -775,14 +787,18 @@ func (fd *FD) ReadFromInet6(buf []byte, sa6 *syscall.SockaddrInet6) (int, error)
775787
return 0, err
776788
}
777789
defer fd.readUnlock()
778-
o := &fd.rop
779-
o.InitBuf(buf)
790+
791+
if !fd.isBlocking {
792+
fd.readPinner.Pin(&buf[0])
793+
defer fd.readPinner.Unpin()
794+
}
795+
780796
rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
781797
defer wsaRsaPool.Put(rsa)
782-
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
798+
n, err := fd.execIO(&fd.rop, func(o *operation) (qty uint32, err error) {
783799
rsan := int32(unsafe.Sizeof(*rsa))
784800
var flags uint32
785-
err = syscall.WSARecvFrom(fd.Sysfd, &o.buf, 1, &qty, &flags, rsa, &rsan, &o.o, nil)
801+
err = syscall.WSARecvFrom(fd.Sysfd, newWsaBuf(buf), 1, &qty, &flags, rsa, &rsan, &o.o, nil)
786802
return qty, err
787803
})
788804
err = fd.eofError(n, err)
@@ -807,6 +823,11 @@ func (fd *FD) Write(buf []byte) (int, error) {
807823
defer fd.writeUnlock()
808824
}
809825

826+
if len(buf) > 0 && !fd.isBlocking {
827+
fd.writePinner.Pin(&buf[0])
828+
defer fd.writePinner.Unpin()
829+
}
830+
810831
var ntotal int
811832
for {
812833
max := len(buf)
@@ -820,21 +841,17 @@ func (fd *FD) Write(buf []byte) (int, error) {
820841
case kindConsole:
821842
n, err = fd.writeConsole(b)
822843
case kindPipe, kindFile:
823-
o := &fd.wop
824-
o.InitBuf(b)
825-
n, err = fd.execIO(o, func(o *operation) (qty uint32, err error) {
826-
err = syscall.WriteFile(fd.Sysfd, unsafe.Slice(o.buf.Buf, o.buf.Len), &qty, fd.overlapped(o))
844+
n, err = fd.execIO(&fd.wop, func(o *operation) (qty uint32, err error) {
845+
err = syscall.WriteFile(fd.Sysfd, b, &qty, fd.overlapped(o))
827846
return qty, err
828847
})
829848
fd.addOffset(n)
830849
case kindNet:
831850
if race.Enabled {
832851
race.ReleaseMerge(unsafe.Pointer(&ioSync))
833852
}
834-
o := &fd.wop
835-
o.InitBuf(b)
836-
n, err = fd.execIO(o, func(o *operation) (qty uint32, err error) {
837-
err = syscall.WSASend(fd.Sysfd, &o.buf, 1, &qty, 0, &o.o, nil)
853+
n, err = fd.execIO(&fd.wop, func(o *operation) (qty uint32, err error) {
854+
err = syscall.WSASend(fd.Sysfd, newWsaBuf(b), 1, &qty, 0, &o.o, nil)
838855
return qty, err
839856
})
840857
}
@@ -903,6 +920,11 @@ func (fd *FD) Pwrite(buf []byte, off int64) (int, error) {
903920
}
904921
defer fd.readWriteUnlock()
905922

923+
if len(buf) > 0 && !fd.isBlocking {
924+
fd.writePinner.Pin(&buf[0])
925+
defer fd.writePinner.Unpin()
926+
}
927+
906928
if fd.isBlocking {
907929
curoffset, err := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
908930
if err != nil {
@@ -926,12 +948,9 @@ func (fd *FD) Pwrite(buf []byte, off int64) (int, error) {
926948
if max-ntotal > maxRW {
927949
max = ntotal + maxRW
928950
}
929-
b := buf[ntotal:max]
930-
o := &fd.wop
931-
o.InitBuf(b)
932951
fd.setOffset(off + int64(ntotal))
933-
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
934-
err = syscall.WriteFile(fd.Sysfd, unsafe.Slice(o.buf.Buf, o.buf.Len), &qty, &o.o)
952+
n, err := fd.execIO(&fd.wop, func(o *operation) (qty uint32, err error) {
953+
err = syscall.WriteFile(fd.Sysfd, buf[ntotal:max], &qty, &o.o)
935954
return qty, err
936955
})
937956
if n > 0 {
@@ -978,25 +997,26 @@ func (fd *FD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
978997

979998
if len(buf) == 0 {
980999
// handle zero-byte payload
981-
o := &fd.wop
982-
o.InitBuf(buf)
983-
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
984-
err = syscall.WSASendto(fd.Sysfd, &o.buf, 1, &qty, 0, sa, &o.o, nil)
1000+
n, err := fd.execIO(&fd.wop, func(o *operation) (qty uint32, err error) {
1001+
err = syscall.WSASendto(fd.Sysfd, &syscall.WSABuf{}, 1, &qty, 0, sa, &o.o, nil)
9851002
return qty, err
9861003
})
9871004
return n, err
9881005
}
9891006

1007+
if !fd.isBlocking {
1008+
fd.writePinner.Pin(&buf[0])
1009+
defer fd.writePinner.Unpin()
1010+
}
1011+
9901012
ntotal := 0
9911013
for len(buf) > 0 {
9921014
b := buf
9931015
if len(b) > maxRW {
9941016
b = b[:maxRW]
9951017
}
996-
o := &fd.wop
997-
o.InitBuf(b)
998-
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
999-
err = syscall.WSASendto(fd.Sysfd, &o.buf, 1, &qty, 0, sa, &o.o, nil)
1018+
n, err := fd.execIO(&fd.wop, func(o *operation) (qty uint32, err error) {
1019+
err = syscall.WSASendto(fd.Sysfd, newWsaBuf(b), 1, &qty, 0, sa, &o.o, nil)
10001020
return qty, err
10011021
})
10021022
ntotal += int(n)
@@ -1017,25 +1037,26 @@ func (fd *FD) WriteToInet4(buf []byte, sa4 *syscall.SockaddrInet4) (int, error)
10171037

10181038
if len(buf) == 0 {
10191039
// handle zero-byte payload
1020-
o := &fd.wop
1021-
o.InitBuf(buf)
1022-
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
1023-
err = windows.WSASendtoInet4(fd.Sysfd, &o.buf, 1, &qty, 0, sa4, &o.o, nil)
1040+
n, err := fd.execIO(&fd.wop, func(o *operation) (qty uint32, err error) {
1041+
err = windows.WSASendtoInet4(fd.Sysfd, &syscall.WSABuf{}, 1, &qty, 0, sa4, &o.o, nil)
10241042
return qty, err
10251043
})
10261044
return n, err
10271045
}
10281046

1047+
if !fd.isBlocking {
1048+
fd.writePinner.Pin(&buf[0])
1049+
defer fd.writePinner.Unpin()
1050+
}
1051+
10291052
ntotal := 0
10301053
for len(buf) > 0 {
10311054
b := buf
10321055
if len(b) > maxRW {
10331056
b = b[:maxRW]
10341057
}
1035-
o := &fd.wop
1036-
o.InitBuf(b)
1037-
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
1038-
err = windows.WSASendtoInet4(fd.Sysfd, &o.buf, 1, &qty, 0, sa4, &o.o, nil)
1058+
n, err := fd.execIO(&fd.wop, func(o *operation) (qty uint32, err error) {
1059+
err = windows.WSASendtoInet4(fd.Sysfd, newWsaBuf(b), 1, &qty, 0, sa4, &o.o, nil)
10391060
return qty, err
10401061
})
10411062
ntotal += int(n)
@@ -1056,25 +1077,26 @@ func (fd *FD) WriteToInet6(buf []byte, sa6 *syscall.SockaddrInet6) (int, error)
10561077

10571078
if len(buf) == 0 {
10581079
// handle zero-byte payload
1059-
o := &fd.wop
1060-
o.InitBuf(buf)
1061-
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
1062-
err = windows.WSASendtoInet6(fd.Sysfd, &o.buf, 1, &qty, 0, sa6, &o.o, nil)
1080+
n, err := fd.execIO(&fd.wop, func(o *operation) (qty uint32, err error) {
1081+
err = windows.WSASendtoInet6(fd.Sysfd, &syscall.WSABuf{}, 1, &qty, 0, sa6, &o.o, nil)
10631082
return qty, err
10641083
})
10651084
return n, err
10661085
}
10671086

1087+
if !fd.isBlocking {
1088+
fd.writePinner.Pin(&buf[0])
1089+
defer fd.writePinner.Unpin()
1090+
}
1091+
10681092
ntotal := 0
10691093
for len(buf) > 0 {
10701094
b := buf
10711095
if len(b) > maxRW {
10721096
b = b[:maxRW]
10731097
}
1074-
o := &fd.wop
1075-
o.InitBuf(b)
1076-
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
1077-
err = windows.WSASendtoInet6(fd.Sysfd, &o.buf, 1, &qty, 0, sa6, &o.o, nil)
1098+
n, err := fd.execIO(&fd.wop, func(o *operation) (qty uint32, err error) {
1099+
err = windows.WSASendtoInet6(fd.Sysfd, newWsaBuf(b), 1, &qty, 0, sa6, &o.o, nil)
10781100
return qty, err
10791101
})
10801102
ntotal += int(n)
@@ -1264,14 +1286,12 @@ func (fd *FD) RawRead(f func(uintptr) bool) error {
12641286

12651287
// Use a zero-byte read as a way to get notified when this
12661288
// socket is readable. h/t https://stackoverflow.com/a/42019668/332798
1267-
o := &fd.rop
1268-
o.InitBuf(nil)
1269-
_, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
1289+
_, err := fd.execIO(&fd.rop, func(o *operation) (qty uint32, err error) {
12701290
var flags uint32
12711291
if !fd.IsStream {
12721292
flags |= windows.MSG_PEEK
12731293
}
1274-
err = syscall.WSARecv(fd.Sysfd, &o.buf, 1, &qty, &flags, &o.o, nil)
1294+
err = syscall.WSARecv(fd.Sysfd, &syscall.WSABuf{}, 1, &qty, &flags, &o.o, nil)
12751295
return qty, err
12761296
})
12771297
if err == windows.WSAEMSGSIZE {

0 commit comments

Comments
 (0)