Source file
src/internal/poll/fd_windows_test.go
1
2
3
4
5 package poll_test
6
7 import (
8 "errors"
9 "internal/poll"
10 "internal/syscall/windows"
11 "io"
12 "os"
13 "path/filepath"
14 "syscall"
15 "testing"
16 "unsafe"
17 )
18
19 func init() {
20 poll.InitWSA()
21 }
22
23
24 func checkFileIsNotPartOfNetpoll(t *testing.T, f *os.File) {
25 t.Helper()
26 sc, err := f.SyscallConn()
27 if err != nil {
28 t.Fatal(err)
29 }
30 if err := sc.Control(func(fd uintptr) {
31
32
33 overlapped, err := windows.IsNonblock(syscall.Handle(fd))
34 if err != nil {
35 t.Fatalf("%v fd=%v: %v", f.Name(), fd, err)
36 }
37 if overlapped {
38
39 if _, err := windows.CreateIoCompletionPort(syscall.Handle(fd), 0, 0, 1); err != nil {
40 t.Fatalf("%v fd=%v: is part of netpoll, but should not be: %v", f.Name(), fd, err)
41 }
42 }
43 }); err != nil {
44 t.Fatalf("%v fd=%v: is not initialized", f.Name(), f.Fd())
45 }
46 }
47
48 func TestFileFdsAreInitialised(t *testing.T) {
49 t.Parallel()
50 exe, err := os.Executable()
51 if err != nil {
52 t.Fatal(err)
53 }
54 f, err := os.Open(exe)
55 if err != nil {
56 t.Fatal(err)
57 }
58 defer f.Close()
59
60 checkFileIsNotPartOfNetpoll(t, f)
61 }
62
63 func TestSerialFdsAreInitialised(t *testing.T) {
64 t.Parallel()
65 for _, name := range []string{"COM1", "COM2", "COM3", "COM4"} {
66 t.Run(name, func(t *testing.T) {
67 t.Parallel()
68 h, err := syscall.CreateFile(syscall.StringToUTF16Ptr(name),
69 syscall.GENERIC_READ|syscall.GENERIC_WRITE,
70 0,
71 nil,
72 syscall.OPEN_EXISTING,
73 syscall.FILE_ATTRIBUTE_NORMAL|syscall.FILE_FLAG_OVERLAPPED,
74 0)
75 if err != nil {
76 if errno, ok := err.(syscall.Errno); ok {
77 switch errno {
78 case syscall.ERROR_FILE_NOT_FOUND,
79 syscall.ERROR_ACCESS_DENIED:
80 t.Log("Skipping: ", err)
81 return
82 }
83 }
84 t.Fatal(err)
85 }
86 f := os.NewFile(uintptr(h), name)
87 defer f.Close()
88
89 checkFileIsNotPartOfNetpoll(t, f)
90 })
91 }
92 }
93
94 func TestWSASocketConflict(t *testing.T) {
95 t.Parallel()
96 s, err := windows.WSASocket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP, nil, 0, windows.WSA_FLAG_OVERLAPPED)
97 if err != nil {
98 t.Fatal(err)
99 }
100 fd := poll.FD{Sysfd: s, IsStream: true, ZeroReadIsEOF: true}
101 if err = fd.Init("tcp", true); err != nil {
102 syscall.CloseHandle(s)
103 t.Fatal(err)
104 }
105 defer fd.Close()
106
107 const SIO_TCP_INFO = syscall.IOC_INOUT | syscall.IOC_VENDOR | 39
108 inbuf := uint32(0)
109 var outbuf _TCP_INFO_v0
110 cbbr := uint32(0)
111
112 var ov syscall.Overlapped
113
114
115 ov.HEvent, _ = windows.CreateEvent(nil, 0, 0, nil)
116 if ov.HEvent == 0 {
117 t.Fatalf("could not create the event!")
118 }
119 defer syscall.CloseHandle(ov.HEvent)
120
121 if err = fd.WSAIoctl(
122 SIO_TCP_INFO,
123 (*byte)(unsafe.Pointer(&inbuf)),
124 uint32(unsafe.Sizeof(inbuf)),
125 (*byte)(unsafe.Pointer(&outbuf)),
126 uint32(unsafe.Sizeof(outbuf)),
127 &cbbr,
128 &ov,
129 0,
130 ); err != nil && !errors.Is(err, syscall.ERROR_IO_PENDING) {
131 t.Fatalf("could not perform the WSAIoctl: %v", err)
132 }
133
134 if err != nil && errors.Is(err, syscall.ERROR_IO_PENDING) {
135
136
137 if res, err := syscall.WaitForSingleObject(ov.HEvent, syscall.INFINITE); res != 0 {
138 t.Fatalf("waiting for the completion of the overlapped IO failed: %v", err)
139 }
140 }
141 }
142
143 type _TCP_INFO_v0 struct {
144 State uint32
145 Mss uint32
146 ConnectionTimeMs uint64
147 TimestampsEnabled bool
148 RttUs uint32
149 MinRttUs uint32
150 BytesInFlight uint32
151 Cwnd uint32
152 SndWnd uint32
153 RcvWnd uint32
154 RcvBuf uint32
155 BytesOut uint64
156 BytesIn uint64
157 BytesReordered uint32
158 BytesRetrans uint32
159 FastRetrans uint32
160 DupAcksIn uint32
161 TimeoutEpisodes uint32
162 SynRetrans uint8
163 }
164
165 func newFD(t testing.TB, h syscall.Handle, kind string, overlapped bool) *poll.FD {
166 fd := poll.FD{
167 Sysfd: h,
168 IsStream: true,
169 ZeroReadIsEOF: true,
170 }
171 err := fd.Init(kind, overlapped)
172 if overlapped && err != nil {
173
174 fd.Close()
175 t.Fatal(err)
176 }
177 t.Cleanup(func() {
178 fd.Close()
179 })
180 return &fd
181 }
182
183 func newFile(t testing.TB, name string, overlapped bool) *poll.FD {
184 namep, err := syscall.UTF16PtrFromString(name)
185 if err != nil {
186 t.Fatal(err)
187 }
188 flags := syscall.FILE_ATTRIBUTE_NORMAL
189 if overlapped {
190 flags |= syscall.FILE_FLAG_OVERLAPPED
191 }
192 h, err := syscall.CreateFile(namep,
193 syscall.GENERIC_READ|syscall.GENERIC_WRITE,
194 syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_READ,
195 nil, syscall.OPEN_ALWAYS, uint32(flags), 0)
196 if err != nil {
197 t.Fatal(err)
198 }
199 typ, err := syscall.GetFileType(h)
200 if err != nil {
201 syscall.CloseHandle(h)
202 t.Fatal(err)
203 }
204 kind := "file"
205 if typ == syscall.FILE_TYPE_PIPE {
206 kind = "pipe"
207 }
208 return newFD(t, h, kind, overlapped)
209 }
210
211 func BenchmarkReadOverlapped(b *testing.B) {
212 benchmarkRead(b, true)
213 }
214
215 func BenchmarkReadSync(b *testing.B) {
216 benchmarkRead(b, false)
217 }
218
219 func benchmarkRead(b *testing.B, overlapped bool) {
220 name := filepath.Join(b.TempDir(), "foo")
221 const content = "hello world"
222 err := os.WriteFile(name, []byte(content), 0644)
223 if err != nil {
224 b.Fatal(err)
225 }
226 file := newFile(b, name, overlapped)
227 var buf [len(content)]byte
228 for b.Loop() {
229 _, err := io.ReadFull(file, buf[:])
230 if err != nil {
231 b.Fatal(err)
232 }
233 if _, err := file.Seek(0, io.SeekStart); err != nil {
234 b.Fatal(err)
235 }
236 }
237 }
238
View as plain text