github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/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 //go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort "kernel32.dll" 14 //go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus "kernel32.dll" 15 //go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult "ws2_32.dll" 16 17 var ( 18 _CreateIoCompletionPort, 19 _GetQueuedCompletionStatus, 20 _WSAGetOverlappedResult stdFunction 21 ) 22 23 const _INVALID_HANDLE_VALUE = ^uintptr(0) 24 25 // net_op must be the same as beginning of net.operation. Keep these in sync. 26 type net_op struct { 27 // used by windows 28 o overlapped 29 // used by netpoll 30 pd *pollDesc 31 mode int32 32 errno int32 33 qty uint32 34 } 35 36 type overlappedEntry struct { 37 key uintptr 38 op *net_op // In reality it's *overlapped, but we cast it to *net_op anyway. 39 internal uintptr 40 qty uint32 41 } 42 43 var iocphandle uintptr = _INVALID_HANDLE_VALUE // completion port io handle 44 45 func netpollinit() { 46 iocphandle = uintptr(stdcall4(_CreateIoCompletionPort, _INVALID_HANDLE_VALUE, 0, 0, _DWORD_MAX)) 47 if iocphandle == 0 { 48 println("netpoll: failed to create iocp handle (errno=", getlasterror(), ")") 49 throw("netpoll: failed to create iocp handle") 50 } 51 } 52 53 func netpollopen(fd uintptr, pd *pollDesc) int32 { 54 if stdcall4(_CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0 { 55 return -int32(getlasterror()) 56 } 57 return 0 58 } 59 60 func netpollclose(fd uintptr) int32 { 61 // nothing to do 62 return 0 63 } 64 65 func netpollarm(pd *pollDesc, mode int) { 66 throw("unused") 67 } 68 69 // Polls for completed network IO. 70 // Returns list of goroutines that become runnable. 71 func netpoll(block bool) *g { 72 var entries [64]overlappedEntry 73 var wait, qty, key, flags, n, i uint32 74 var errno int32 75 var op *net_op 76 var gp *g 77 78 mp := getg().m 79 80 if iocphandle == _INVALID_HANDLE_VALUE { 81 return nil 82 } 83 gp = nil 84 wait = 0 85 if block { 86 wait = _INFINITE 87 } 88 retry: 89 if _GetQueuedCompletionStatusEx != nil { 90 n = uint32(len(entries) / int(gomaxprocs)) 91 if n < 8 { 92 n = 8 93 } 94 if block { 95 mp.blocked = true 96 } 97 if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 { 98 mp.blocked = false 99 errno = int32(getlasterror()) 100 if !block && errno == _WAIT_TIMEOUT { 101 return nil 102 } 103 println("netpoll: GetQueuedCompletionStatusEx failed (errno=", errno, ")") 104 throw("netpoll: GetQueuedCompletionStatusEx failed") 105 } 106 mp.blocked = false 107 for i = 0; i < n; i++ { 108 op = entries[i].op 109 errno = 0 110 qty = 0 111 if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 { 112 errno = int32(getlasterror()) 113 } 114 handlecompletion(&gp, op, errno, qty) 115 } 116 } else { 117 op = nil 118 errno = 0 119 qty = 0 120 if block { 121 mp.blocked = true 122 } 123 if stdcall5(_GetQueuedCompletionStatus, iocphandle, uintptr(unsafe.Pointer(&qty)), uintptr(unsafe.Pointer(&key)), uintptr(unsafe.Pointer(&op)), uintptr(wait)) == 0 { 124 mp.blocked = false 125 errno = int32(getlasterror()) 126 if !block && errno == _WAIT_TIMEOUT { 127 return nil 128 } 129 if op == nil { 130 println("netpoll: GetQueuedCompletionStatus failed (errno=", errno, ")") 131 throw("netpoll: GetQueuedCompletionStatus failed") 132 } 133 // dequeued failed IO packet, so report that 134 } 135 mp.blocked = false 136 handlecompletion(&gp, op, errno, qty) 137 } 138 if block && gp == nil { 139 goto retry 140 } 141 return gp 142 } 143 144 func handlecompletion(gpp **g, op *net_op, errno int32, qty uint32) { 145 if op == nil { 146 throw("netpoll: GetQueuedCompletionStatus returned op == nil") 147 } 148 mode := op.mode 149 if mode != 'r' && mode != 'w' { 150 println("netpoll: GetQueuedCompletionStatus returned invalid mode=", mode) 151 throw("netpoll: GetQueuedCompletionStatus returned invalid mode") 152 } 153 op.errno = errno 154 op.qty = qty 155 netpollready((**g)(noescape(unsafe.Pointer(gpp))), op.pd, mode) 156 }