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.
11 const _DWORD_MAX
= 0xffffffff
13 const _INVALID_HANDLE_VALUE
= ^uintptr(0)
15 // net_op must be the same as beginning of internal/poll.operation.
16 // Keep these in sync.
27 type overlappedEntry
struct {
29 op
*net_op
// In reality it's *overlapped, but we cast it to *net_op anyway.
34 var iocphandle
uintptr = _INVALID_HANDLE_VALUE
// completion port io handle
37 iocphandle
= stdcall4(_CreateIoCompletionPort
, _INVALID_HANDLE_VALUE
, 0, 0, _DWORD_MAX
)
39 println("runtime: CreateIoCompletionPort failed (errno=", getlasterror(), ")")
40 throw("runtime: netpollinit failed")
44 func netpolldescriptor() uintptr {
48 func netpollopen(fd
uintptr, pd
*pollDesc
) int32 {
49 if stdcall4(_CreateIoCompletionPort
, fd
, iocphandle
, 0, 0) == 0 {
50 return -int32(getlasterror())
55 func netpollclose(fd
uintptr) int32 {
60 func netpollarm(pd
*pollDesc
, mode
int) {
61 throw("runtime: unused")
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
75 if iocphandle
== _INVALID_HANDLE_VALUE
{
83 if _GetQueuedCompletionStatusEx
!= nil {
84 n
= uint32(len(entries
) / int(gomaxprocs
))
91 if stdcall6(_GetQueuedCompletionStatusEx
, iocphandle
, uintptr(unsafe
.Pointer(&entries
[0])), uintptr(n
), uintptr(unsafe
.Pointer(&n
)), uintptr(wait
), 0) == 0 {
93 errno
= int32(getlasterror())
94 if !block
&& errno
== _WAIT_TIMEOUT
{
97 println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno
, ")")
98 throw("runtime: netpoll failed")
101 for i
= 0; i
< n
; i
++ {
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())
108 handlecompletion(&gp
, op
, errno
, qty
)
117 if stdcall5(_GetQueuedCompletionStatus
, iocphandle
, uintptr(unsafe
.Pointer(&qty
)), uintptr(unsafe
.Pointer(&key
)), uintptr(unsafe
.Pointer(&op
)), uintptr(wait
)) == 0 {
119 errno
= int32(getlasterror())
120 if !block
&& errno
== _WAIT_TIMEOUT
{
124 println("runtime: GetQueuedCompletionStatus failed (errno=", errno
, ")")
125 throw("runtime: netpoll failed")
127 // dequeued failed IO packet, so report that
130 handlecompletion(&gp
, op
, errno
, qty
)
132 if block
&& gp
== 0 {
138 func handlecompletion(gpp
*guintptr
, op
*net_op
, errno
int32, qty
uint32) {
140 println("runtime: GetQueuedCompletionStatus returned op == nil")
141 throw("runtime: netpoll failed")
144 if mode
!= 'r' && mode
!= 'w' {
145 println("runtime: GetQueuedCompletionStatus returned invalid mode=", mode
)
146 throw("runtime: netpoll failed")
150 netpollready(gpp
, op
.pd
, mode
)