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.
8 "runtime/internal/atomic"
12 const _DWORD_MAX
= 0xffffffff
14 const _INVALID_HANDLE_VALUE
= ^uintptr(0)
16 // net_op must be the same as beginning of internal/poll.operation.
17 // Keep these in sync.
28 type overlappedEntry
struct {
30 op
*net_op
// In reality it's *overlapped, but we cast it to *net_op anyway.
36 iocphandle
uintptr = _INVALID_HANDLE_VALUE
// completion port io handle
38 netpollWakeSig
uint32 // used to avoid duplicate calls of netpollBreak
42 iocphandle
= stdcall4(_CreateIoCompletionPort
, _INVALID_HANDLE_VALUE
, 0, 0, _DWORD_MAX
)
44 println("runtime: CreateIoCompletionPort failed (errno=", getlasterror(), ")")
45 throw("runtime: netpollinit failed")
49 func netpollIsPollDescriptor(fd
uintptr) bool {
50 return fd
== iocphandle
53 func netpollopen(fd
uintptr, pd
*pollDesc
) int32 {
54 if stdcall4(_CreateIoCompletionPort
, fd
, iocphandle
, 0, 0) == 0 {
55 return int32(getlasterror())
60 func netpollclose(fd
uintptr) int32 {
65 func netpollarm(pd
*pollDesc
, mode
int) {
66 throw("runtime: unused")
70 if atomic
.Cas(&netpollWakeSig
, 0, 1) {
71 if stdcall4(_PostQueuedCompletionStatus
, iocphandle
, 0, 0, 0) == 0 {
72 println("runtime: netpoll: PostQueuedCompletionStatus failed (errno=", getlasterror(), ")")
73 throw("runtime: netpoll: PostQueuedCompletionStatus failed")
78 // netpoll checks for ready network connections.
79 // Returns list of goroutines that become runnable.
80 // delay < 0: blocks indefinitely
81 // delay == 0: does not block, just polls
82 // delay > 0: block for up to that many nanoseconds
83 func netpoll(delay
int64) gList
{
84 var entries
[64]overlappedEntry
85 var wait
, qty
, flags
, n
, i
uint32
92 if iocphandle
== _INVALID_HANDLE_VALUE
{
97 } else if delay
== 0 {
99 } else if delay
< 1e6
{
101 } else if delay
< 1e15
{
102 wait
= uint32(delay
/ 1e6
)
104 // An arbitrary cap on how long to wait for a timer.
105 // 1e9 ms == ~11.5 days.
109 n
= uint32(len(entries
) / int(gomaxprocs
))
116 if stdcall6(_GetQueuedCompletionStatusEx
, iocphandle
, uintptr(unsafe
.Pointer(&entries
[0])), uintptr(n
), uintptr(unsafe
.Pointer(&n
)), uintptr(wait
), 0) == 0 {
118 errno
= int32(getlasterror())
119 if errno
== _WAIT_TIMEOUT
{
122 println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno
, ")")
123 throw("runtime: netpoll failed")
126 for i
= 0; i
< n
; i
++ {
131 if stdcall5(_WSAGetOverlappedResult
, op
.pd
.fd
, uintptr(unsafe
.Pointer(op
)), uintptr(unsafe
.Pointer(&qty
)), 0, uintptr(unsafe
.Pointer(&flags
))) == 0 {
132 errno
= int32(getlasterror())
134 handlecompletion(&toRun
, op
, errno
, qty
)
136 atomic
.Store(&netpollWakeSig
, 0)
138 // Forward the notification to the
147 func handlecompletion(toRun
*gList
, op
*net_op
, errno
int32, qty
uint32) {
149 if mode
!= 'r' && mode
!= 'w' {
150 println("runtime: GetQueuedCompletionStatusEx returned invalid mode=", mode
)
151 throw("runtime: netpoll failed")
155 netpollready(toRun
, op
.pd
, mode
)