github.com/flyinox/gosm@v0.0.0-20171117061539-16768cb62077/src/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 "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 netpolldescriptor() uintptr { 45 return 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 // Polls for completed network IO. 65 // Returns list of goroutines that become runnable. 66 func netpoll(block bool) *g { 67 var entries [64]overlappedEntry 68 var wait, qty, key, flags, n, i uint32 69 var errno int32 70 var op *net_op 71 var gp guintptr 72 73 mp := getg().m 74 75 if iocphandle == _INVALID_HANDLE_VALUE { 76 return nil 77 } 78 wait = 0 79 if block { 80 wait = _INFINITE 81 } 82 retry: 83 if _GetQueuedCompletionStatusEx != nil { 84 n = uint32(len(entries) / int(gomaxprocs)) 85 if n < 8 { 86 n = 8 87 } 88 if block { 89 mp.blocked = true 90 } 91 if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 { 92 mp.blocked = false 93 errno = int32(getlasterror()) 94 if !block && errno == _WAIT_TIMEOUT { 95 return nil 96 } 97 println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno, ")") 98 throw("runtime: netpoll failed") 99 } 100 mp.blocked = false 101 for i = 0; i < n; i++ { 102 op = entries[i].op 103 errno = 0 104 qty = 0 105 if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 { 106 errno = int32(getlasterror()) 107 } 108 handlecompletion(&gp, op, errno, qty) 109 } 110 } else { 111 op = nil 112 errno = 0 113 qty = 0 114 if block { 115 mp.blocked = true 116 } 117 if stdcall5(_GetQueuedCompletionStatus, iocphandle, uintptr(unsafe.Pointer(&qty)), uintptr(unsafe.Pointer(&key)), uintptr(unsafe.Pointer(&op)), uintptr(wait)) == 0 { 118 mp.blocked = false 119 errno = int32(getlasterror()) 120 if !block && errno == _WAIT_TIMEOUT { 121 return nil 122 } 123 if op == nil { 124 println("runtime: GetQueuedCompletionStatus failed (errno=", errno, ")") 125 throw("runtime: netpoll failed") 126 } 127 // dequeued failed IO packet, so report that 128 } 129 mp.blocked = false 130 handlecompletion(&gp, op, errno, qty) 131 } 132 if block && gp == 0 { 133 goto retry 134 } 135 return gp.ptr() 136 } 137 138 func handlecompletion(gpp *guintptr, op *net_op, errno int32, qty uint32) { 139 if op == nil { 140 println("runtime: GetQueuedCompletionStatus returned op == nil") 141 throw("runtime: netpoll failed") 142 } 143 mode := op.mode 144 if mode != 'r' && mode != 'w' { 145 println("runtime: GetQueuedCompletionStatus returned invalid mode=", mode) 146 throw("runtime: netpoll failed") 147 } 148 op.errno = errno 149 op.qty = qty 150 netpollready(gpp, op.pd, mode) 151 }