github.com/cbeuw/gotfo@v0.0.0-20180331191851-f2b091af84de/fd_go18_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.8,!go1.9 6 7 package gotfo 8 9 import ( 10 "net" 11 "os" 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 = os.NewSyscallError("wsastartup", 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 // operation contains superset of data necessary to perform all async IO. 61 type operation struct { 62 // Used by IOCP interface, it must be first field 63 // of the struct, as our code rely on it. 64 o syscall.Overlapped 65 66 // fields used by runtime.netpoll 67 runtimeCtx uintptr 68 mode int32 69 errno int32 70 qty uint32 71 72 // fields used only by net package 73 fd *netFD 74 errc chan error 75 buf syscall.WSABuf 76 sa syscall.Sockaddr 77 rsa *syscall.RawSockaddrAny 78 rsan int32 79 handle syscall.Handle 80 flags uint32 81 bufs []syscall.WSABuf 82 } 83 84 // Network file descriptor. 85 type netFD struct { 86 // locking/lifetime of sysfd + serialize access to Read and Write methods 87 fdmu fdMutex 88 89 // immutable until Close 90 sysfd syscall.Handle 91 family int 92 sotype int 93 isStream bool 94 isConnected bool 95 skipSyncNotif bool 96 net string 97 laddr net.Addr 98 raddr net.Addr 99 100 rop operation // read operation 101 wop operation // write operation 102 103 // wait server 104 pd pollDesc 105 } 106 107 func newFD(sysfd syscall.Handle, family int) (*netFD, error) { 108 if initErr != nil { 109 return nil, initErr 110 } 111 112 return &netFD{ 113 sysfd: sysfd, 114 family: family, 115 sotype: syscall.SOCK_STREAM, 116 net: "tcp", 117 isStream: true, 118 }, nil 119 } 120 121 func (fd *netFD) init() error { 122 if err := fd.pd.init(fd); err != nil { 123 return err 124 } 125 126 // We do not use events, so we can skip them always. 127 flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE) 128 // It's not safe to skip completion notifications for UDP: 129 // http://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx 130 if skipSyncNotif { 131 flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 132 } 133 err := syscall.SetFileCompletionNotificationModes(fd.sysfd, flags) 134 if err == nil && flags&syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS != 0 { 135 fd.skipSyncNotif = true 136 } 137 138 fd.rop.mode = 'r' 139 fd.wop.mode = 'w' 140 fd.rop.fd = fd 141 fd.wop.fd = fd 142 fd.rop.runtimeCtx = fd.pd.runtimeCtx 143 fd.wop.runtimeCtx = fd.pd.runtimeCtx 144 145 return nil 146 }