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 net.operation. Keep these in sync.
26 type overlappedEntry
struct {
28 op
*net_op
// In reality it's *overlapped, but we cast it to *net_op anyway.
33 var iocphandle
uintptr = _INVALID_HANDLE_VALUE
// completion port io handle
36 iocphandle
= stdcall4(_CreateIoCompletionPort
, _INVALID_HANDLE_VALUE
, 0, 0, _DWORD_MAX
)
38 println("netpoll: failed to create iocp handle (errno=", getlasterror(), ")")
39 throw("netpoll: failed to create iocp handle")
43 func netpollopen(fd
uintptr, pd
*pollDesc
) int32 {
44 if stdcall4(_CreateIoCompletionPort
, fd
, iocphandle
, 0, 0) == 0 {
45 return -int32(getlasterror())
50 func netpollclose(fd
uintptr) int32 {
55 func netpollarm(pd
*pollDesc
, mode
int) {
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
70 if iocphandle
== _INVALID_HANDLE_VALUE
{
78 if _GetQueuedCompletionStatusEx
!= nil {
79 n
= uint32(len(entries
) / int(gomaxprocs
))
86 if stdcall6(_GetQueuedCompletionStatusEx
, iocphandle
, uintptr(unsafe
.Pointer(&entries
[0])), uintptr(n
), uintptr(unsafe
.Pointer(&n
)), uintptr(wait
), 0) == 0 {
88 errno
= int32(getlasterror())
89 if !block
&& errno
== _WAIT_TIMEOUT
{
92 println("netpoll: GetQueuedCompletionStatusEx failed (errno=", errno
, ")")
93 throw("netpoll: GetQueuedCompletionStatusEx failed")
96 for i
= 0; i
< n
; i
++ {
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())
103 handlecompletion(&gp
, op
, errno
, qty
)
112 if stdcall5(_GetQueuedCompletionStatus
, iocphandle
, uintptr(unsafe
.Pointer(&qty
)), uintptr(unsafe
.Pointer(&key
)), uintptr(unsafe
.Pointer(&op
)), uintptr(wait
)) == 0 {
114 errno
= int32(getlasterror())
115 if !block
&& errno
== _WAIT_TIMEOUT
{
119 println("netpoll: GetQueuedCompletionStatus failed (errno=", errno
, ")")
120 throw("netpoll: GetQueuedCompletionStatus failed")
122 // dequeued failed IO packet, so report that
125 handlecompletion(&gp
, op
, errno
, qty
)
127 if block
&& gp
== 0 {
133 func handlecompletion(gpp
*guintptr
, op
*net_op
, errno
int32, qty
uint32) {
135 throw("netpoll: GetQueuedCompletionStatus returned op == nil")
138 if mode
!= 'r' && mode
!= 'w' {
139 println("netpoll: GetQueuedCompletionStatus returned invalid mode=", mode
)
140 throw("netpoll: GetQueuedCompletionStatus returned invalid mode")
144 netpollready(gpp
, op
.pd
, mode
)