github.com/x04/go/src@v0.0.0-20200202162449-3d481ceb3525/runtime/netpoll_windows.go (about) 1 // Copyright 2013 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 package runtime 6 7 import ( 8 "github.com/x04/go/src/unsafe" 9 ) 10 11 const _DWORD_MAX = 0xffffffff 12 13 const _INVALID_HANDLE_VALUE = ^uintptr(0) 14 15 // net_op must be the same as beginning of internal/poll.operation. 16 // Keep these in sync. 17 type net_op struct { 18 // used by windows 19 o overlapped 20 // used by netpoll 21 pd *pollDesc 22 mode int32 23 errno int32 24 qty uint32 25 } 26 27 type overlappedEntry struct { 28 key uintptr 29 op *net_op // In reality it's *overlapped, but we cast it to *net_op anyway. 30 internal uintptr 31 qty uint32 32 } 33 34 var iocphandle uintptr = _INVALID_HANDLE_VALUE // completion port io handle 35 36 func netpollinit() { 37 iocphandle = stdcall4(_CreateIoCompletionPort, _INVALID_HANDLE_VALUE, 0, 0, _DWORD_MAX) 38 if iocphandle == 0 { 39 println("runtime: CreateIoCompletionPort failed (errno=", getlasterror(), ")") 40 throw("runtime: netpollinit failed") 41 } 42 } 43 44 func netpollIsPollDescriptor(fd uintptr) bool { 45 return fd == iocphandle 46 } 47 48 func netpollopen(fd uintptr, pd *pollDesc) int32 { 49 if stdcall4(_CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0 { 50 return int32(getlasterror()) 51 } 52 return 0 53 } 54 55 func netpollclose(fd uintptr) int32 { 56 // nothing to do 57 return 0 58 } 59 60 func netpollarm(pd *pollDesc, mode int) { 61 throw("runtime: unused") 62 } 63 64 func netpollBreak() { 65 if stdcall4(_PostQueuedCompletionStatus, iocphandle, 0, 0, 0) == 0 { 66 println("runtime: netpoll: PostQueuedCompletionStatus failed (errno=", getlasterror(), ")") 67 throw("runtime: netpoll: PostQueuedCompletionStatus failed") 68 } 69 } 70 71 // netpoll checks for ready network connections. 72 // Returns list of goroutines that become runnable. 73 // delay < 0: blocks indefinitely 74 // delay == 0: does not block, just polls 75 // delay > 0: block for up to that many nanoseconds 76 func netpoll(delay int64) gList { 77 var entries [64]overlappedEntry 78 var wait, qty, key, flags, n, i uint32 79 var errno int32 80 var op *net_op 81 var toRun gList 82 83 mp := getg().m 84 85 if iocphandle == _INVALID_HANDLE_VALUE { 86 return gList{} 87 } 88 if delay < 0 { 89 wait = _INFINITE 90 } else if delay == 0 { 91 wait = 0 92 } else if delay < 1e6 { 93 wait = 1 94 } else if delay < 1e15 { 95 wait = uint32(delay / 1e6) 96 } else { 97 // An arbitrary cap on how long to wait for a timer. 98 // 1e9 ms == ~11.5 days. 99 wait = 1e9 100 } 101 102 if _GetQueuedCompletionStatusEx != nil { 103 n = uint32(len(entries) / int(gomaxprocs)) 104 if n < 8 { 105 n = 8 106 } 107 if delay != 0 { 108 mp.blocked = true 109 } 110 if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 { 111 mp.blocked = false 112 errno = int32(getlasterror()) 113 if errno == _WAIT_TIMEOUT { 114 return gList{} 115 } 116 println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno, ")") 117 throw("runtime: netpoll failed") 118 } 119 mp.blocked = false 120 for i = 0; i < n; i++ { 121 op = entries[i].op 122 if op != nil { 123 errno = 0 124 qty = 0 125 if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 { 126 errno = int32(getlasterror()) 127 } 128 handlecompletion(&toRun, op, errno, qty) 129 } else { 130 if delay == 0 { 131 // Forward the notification to the 132 // blocked poller. 133 netpollBreak() 134 } 135 } 136 } 137 } else { 138 op = nil 139 errno = 0 140 qty = 0 141 if delay != 0 { 142 mp.blocked = true 143 } 144 if stdcall5(_GetQueuedCompletionStatus, iocphandle, uintptr(unsafe.Pointer(&qty)), uintptr(unsafe.Pointer(&key)), uintptr(unsafe.Pointer(&op)), uintptr(wait)) == 0 { 145 mp.blocked = false 146 errno = int32(getlasterror()) 147 if errno == _WAIT_TIMEOUT { 148 return gList{} 149 } 150 if op == nil { 151 println("runtime: GetQueuedCompletionStatus failed (errno=", errno, ")") 152 throw("runtime: netpoll failed") 153 } 154 // dequeued failed IO packet, so report that 155 } 156 mp.blocked = false 157 if op == nil { 158 if delay == 0 { 159 // Forward the notification to the 160 // blocked poller. 161 netpollBreak() 162 } 163 return gList{} 164 } 165 handlecompletion(&toRun, op, errno, qty) 166 } 167 return toRun 168 } 169 170 func handlecompletion(toRun *gList, op *net_op, errno int32, qty uint32) { 171 if op == nil { 172 println("runtime: GetQueuedCompletionStatus returned op == nil") 173 throw("runtime: netpoll failed") 174 } 175 mode := op.mode 176 if mode != 'r' && mode != 'w' { 177 println("runtime: GetQueuedCompletionStatus returned invalid mode=", mode) 178 throw("runtime: netpoll failed") 179 } 180 op.errno = errno 181 op.qty = qty 182 netpollready(toRun, op.pd, mode) 183 }