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