github.com/cbeuw/gotfo@v0.0.0-20180331191851-f2b091af84de/fd_go110_windows.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build go1.10 6 7 package gotfo 8 9 import ( 10 "net" 11 "sync" 12 "syscall" 13 "unsafe" 14 ) 15 16 var ( 17 initErr error 18 ) 19 20 // CancelIo Windows API cancels all outstanding IO for a particular 21 // socket on current thread. To overcome that limitation, we run 22 // special goroutine, locked to OS single thread, that both starts 23 // and cancels IO. It means, there are 2 unavoidable thread switches 24 // for every IO. 25 // Some newer versions of Windows has new CancelIoEx API, that does 26 // not have that limitation and can be used from any thread. This 27 // package uses CancelIoEx API, if present, otherwise it fallback 28 // to CancelIo. 29 30 var ( 31 skipSyncNotif bool 32 ) 33 34 func sysInit() { 35 var d syscall.WSAData 36 e := syscall.WSAStartup(uint32(0x202), &d) 37 if e != nil { 38 initErr = e 39 } 40 41 // It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS if non IFS providers are installed: 42 // http://support.microsoft.com/kb/2568167 43 skipSyncNotif = true 44 protos := [2]int32{syscall.IPPROTO_TCP, 0} 45 var buf [32]syscall.WSAProtocolInfo 46 len := uint32(unsafe.Sizeof(buf)) 47 n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len) 48 if err != nil { 49 skipSyncNotif = false 50 } else { 51 for i := int32(0); i < n; i++ { 52 if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 { 53 skipSyncNotif = false 54 break 55 } 56 } 57 } 58 } 59 60 // internal/syscall/windows/syscall_windows.go 61 type WSAMsg struct { 62 Name *syscall.RawSockaddrAny 63 Namelen int32 64 Buffers *syscall.WSABuf 65 BufferCount uint32 66 Control syscall.WSABuf 67 Flags uint32 68 } 69 70 // operation contains superset of data necessary to perform all async IO. 71 type operation struct { 72 // Used by IOCP interface, it must be first field 73 // of the struct, as our code rely on it. 74 o syscall.Overlapped 75 76 // fields used by runtime.netpoll 77 runtimeCtx uintptr 78 mode int32 79 errno int32 80 qty uint32 81 82 // fields used only by net package 83 fd *pollFD 84 errc chan error 85 buf syscall.WSABuf 86 // new in go1.10 https://github.com/golang/go/commit/e49bc465a3acb2dd72e9afa5d40e541205c7d460 87 msg WSAMsg 88 sa syscall.Sockaddr 89 rsa *syscall.RawSockaddrAny 90 rsan int32 91 handle syscall.Handle 92 flags uint32 93 bufs []syscall.WSABuf 94 } 95 96 type pollFD struct { 97 // Lock sysfd and serialize access to Read and Write methods. 98 fdmu fdMutex 99 100 // System file descriptor. Immutable until Close. 101 sysfd syscall.Handle 102 103 // Read operation. 104 rop operation 105 // Write operation. 106 wop operation 107 108 // I/O poller. 109 pd pollDesc 110 111 // Used to implement pread/pwrite. 112 l sync.Mutex 113 114 // For console I/O. 115 isConsole bool 116 lastbits []byte // first few bytes of the last incomplete rune in last write 117 readuint16 []uint16 // buffer to hold uint16s obtained with ReadConsole 118 readbyte []byte // buffer to hold decoding of readuint16 from utf16 to utf8 119 readbyteOffset int // readbyte[readOffset:] is yet to be consumed with file.Read 120 121 // new in go1.10 https://github.com/golang/go/commit/382d4928b8a758a91f06de9e6cb10b92bb882eff#diff-618b3f21201d29fa6d82d50df02dcdba 122 csema uint32 123 124 skipSyncNotif bool 125 126 // Whether this is a streaming descriptor, as opposed to a 127 // packet-based descriptor like a UDP socket. 128 IsStream bool 129 130 // Whether a zero byte read indicates EOF. This is false for a 131 // message based socket connection. 132 ZeroReadIsEOF bool 133 134 // Whether this is a normal file. 135 isFile bool 136 137 // Whether this is a directory. 138 isDir bool 139 } 140 141 // Network file descriptor. 142 type netFD struct { 143 pollFD 144 145 // immutable until Close 146 family int 147 sotype int 148 isConnected bool 149 net string 150 laddr net.Addr 151 raddr net.Addr 152 } 153 154 func newFD(sysfd syscall.Handle, family int) (*netFD, error) { 155 if initErr != nil { 156 return nil, initErr 157 } 158 159 ret := &netFD{ 160 pollFD: pollFD{ 161 sysfd: sysfd, 162 IsStream: true, 163 ZeroReadIsEOF: true, 164 }, 165 family: family, 166 sotype: syscall.SOCK_STREAM, 167 net: "tcp", 168 } 169 return ret, nil 170 } 171 172 func (fd *netFD) init() error { 173 if initErr != nil { 174 return initErr 175 } 176 177 if err := fd.pd.init(fd); err != nil { 178 return err 179 } 180 181 // We do not use events, so we can skip them always. 182 flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE) 183 // It's not safe to skip completion notifications for UDP: 184 // http://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx 185 if skipSyncNotif { 186 flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 187 } 188 err := syscall.SetFileCompletionNotificationModes(fd.sysfd, flags) 189 if err == nil && flags&syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS != 0 { 190 fd.skipSyncNotif = true 191 } 192 193 fd.rop.mode = 'r' 194 fd.wop.mode = 'w' 195 fd.rop.fd = &fd.pollFD 196 fd.wop.fd = &fd.pollFD 197 fd.rop.runtimeCtx = fd.pd.runtimeCtx 198 fd.wop.runtimeCtx = fd.pd.runtimeCtx 199 200 return nil 201 } 202 203 func (fd *pollFD) incref() error { 204 if !fd.fdmu.incref() { 205 return errClosing 206 } 207 return nil 208 } 209 210 // decref removes a reference from fd. 211 // It also closes fd when the state of fd is set to closed and there 212 // is no remaining reference. 213 func (fd *pollFD) decref() error { 214 if fd.fdmu.decref() { 215 return fd.destroy() 216 } 217 return nil 218 } 219 220 func (fd *pollFD) destroy() error { 221 if fd.sysfd == syscall.InvalidHandle { 222 return syscall.EINVAL 223 } 224 // Poller may want to unregister fd in readiness notification mechanism, 225 // so this must be executed before fd.CloseFunc. 226 fd.pd.close() 227 var err error 228 if fd.isFile || fd.isConsole { 229 err = syscall.CloseHandle(fd.sysfd) 230 } else if fd.isDir { 231 err = syscall.FindClose(fd.sysfd) 232 } else { 233 // The net package uses the CloseFunc variable for testing. 234 err = syscall.Closesocket(fd.sysfd) 235 } 236 fd.sysfd = syscall.InvalidHandle 237 runtime_Semrelease(&fd.csema) 238 return err 239 } 240 241 // Close closes the FD. The underlying file descriptor is closed by 242 // the destroy method when there are no remaining references. 243 func (fd *pollFD) Close() error { 244 if !fd.fdmu.increfAndClose() { 245 return errClosing 246 } 247 // unblock pending reader and writer 248 fd.pd.evict() 249 err := fd.decref() 250 // Wait until the descriptor is closed. If this was the only 251 // reference, it is already closed. 252 runtime_Semacquire(&fd.csema) 253 return err 254 } 255 256 // Shutdown wraps the shutdown network call. 257 func (fd *pollFD) Shutdown(how int) error { 258 if err := fd.incref(); err != nil { 259 return err 260 } 261 defer fd.decref() 262 return syscall.Shutdown(fd.sysfd, how) 263 }