2017-03-02 Richard Biener <rguenther@suse.de>
[official-gcc.git] / libgo / go / runtime / netpoll_windows.go
blob7ad115850d58fdc9a505fc7071852d6801aa93f0
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.
5 package runtime
7 import (
8 "unsafe"
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.
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
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
33 var iocphandle uintptr = _INVALID_HANDLE_VALUE // completion port io handle
35 func netpollinit() {
36 iocphandle = 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")
43 func netpollopen(fd uintptr, pd *pollDesc) int32 {
44 if stdcall4(_CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0 {
45 return -int32(getlasterror())
47 return 0
50 func netpollclose(fd uintptr) int32 {
51 // nothing to do
52 return 0
55 func netpollarm(pd *pollDesc, mode int) {
56 throw("unused")
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
68 mp := getg().m
70 if iocphandle == _INVALID_HANDLE_VALUE {
71 return nil
73 wait = 0
74 if block {
75 wait = _INFINITE
77 retry:
78 if _GetQueuedCompletionStatusEx != nil {
79 n = uint32(len(entries) / int(gomaxprocs))
80 if n < 8 {
81 n = 8
83 if block {
84 mp.blocked = true
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
92 println("netpoll: GetQueuedCompletionStatusEx failed (errno=", errno, ")")
93 throw("netpoll: GetQueuedCompletionStatusEx failed")
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())
103 handlecompletion(&gp, op, errno, qty)
105 } else {
106 op = nil
107 errno = 0
108 qty = 0
109 if block {
110 mp.blocked = true
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
118 if op == nil {
119 println("netpoll: GetQueuedCompletionStatus failed (errno=", errno, ")")
120 throw("netpoll: GetQueuedCompletionStatus failed")
122 // dequeued failed IO packet, so report that
124 mp.blocked = false
125 handlecompletion(&gp, op, errno, qty)
127 if block && gp == 0 {
128 goto retry
130 return gp.ptr()
133 func handlecompletion(gpp *guintptr, op *net_op, errno int32, qty uint32) {
134 if op == nil {
135 throw("netpoll: GetQueuedCompletionStatus returned op == nil")
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")
142 op.errno = errno
143 op.qty = qty
144 netpollready(gpp, op.pd, mode)