111
|
1 // Copyright 2017 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 "unsafe"
|
|
8
|
|
9 // This is based on the former libgo/runtime/netpoll_select.c implementation
|
131
|
10 // except that it uses poll instead of select and is written in Go.
|
111
|
11
|
|
12 type pollfd struct {
|
|
13 fd int32
|
|
14 events int16
|
|
15 revents int16
|
|
16 }
|
|
17
|
|
18 const _POLLIN = 0x0001
|
|
19 const _POLLOUT = 0x0002
|
|
20 const _POLLHUP = 0x2000
|
|
21 const _POLLERR = 0x4000
|
|
22
|
131
|
23 //go:noescape
|
|
24 //extern poll
|
|
25 func libc_poll(pfds *pollfd, npfds uintptr, timeout uintptr) int32
|
111
|
26
|
131
|
27 //go:noescape
|
111
|
28 //extern pipe
|
|
29 func libc_pipe(fd *int32) int32
|
|
30
|
|
31 //extern __go_fcntl_uintptr
|
|
32 func fcntlUintptr(fd, cmd, arg uintptr) (uintptr, uintptr)
|
|
33
|
|
34 func fcntl(fd, cmd int32, arg uintptr) uintptr {
|
|
35 r, _ := fcntlUintptr(uintptr(fd), uintptr(cmd), arg)
|
|
36 return r
|
|
37 }
|
|
38
|
|
39 var (
|
131
|
40 pfds []pollfd
|
|
41 pds []*pollDesc
|
|
42 mtxpoll mutex
|
|
43 mtxset mutex
|
111
|
44 rdwake int32
|
|
45 wrwake int32
|
|
46 needsUpdate bool
|
|
47 )
|
|
48
|
|
49 func netpollinit() {
|
|
50 var p [2]int32
|
|
51
|
131
|
52 // Create the pipe we use to wakeup poll.
|
111
|
53 if err := libc_pipe(&p[0]); err < 0 {
|
|
54 throw("runtime: netpollinit failed to create pipe")
|
|
55 }
|
|
56 rdwake = p[0]
|
|
57 wrwake = p[1]
|
|
58
|
|
59 fl := fcntl(rdwake, _F_GETFL, 0)
|
|
60 fcntl(rdwake, _F_SETFL, fl|_O_NONBLOCK)
|
|
61 fcntl(rdwake, _F_SETFD, _FD_CLOEXEC)
|
|
62
|
|
63 fl = fcntl(wrwake, _F_GETFL, 0)
|
|
64 fcntl(wrwake, _F_SETFD, _FD_CLOEXEC)
|
|
65
|
131
|
66 // Pre-allocate array of pollfd structures for poll.
|
|
67 pfds = make([]pollfd, 1, 128)
|
|
68 // Poll the read side of the pipe.
|
|
69 pfds[0].fd = rdwake
|
|
70 pfds[0].events = _POLLIN
|
111
|
71
|
131
|
72 // Allocate index to pd array
|
|
73 pds = make([]*pollDesc, 1, 128)
|
|
74 pds[0] = nil
|
111
|
75 }
|
|
76
|
|
77 func netpolldescriptor() uintptr {
|
|
78 return ^uintptr(0)
|
|
79 }
|
|
80
|
131
|
81 func netpollwakeup() {
|
|
82 if !needsUpdate {
|
|
83 needsUpdate = true
|
|
84 b := [1]byte{0}
|
|
85 write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
|
|
86 }
|
|
87 }
|
|
88
|
111
|
89 func netpollopen(fd uintptr, pd *pollDesc) int32 {
|
131
|
90 lock(&mtxpoll)
|
|
91 netpollwakeup()
|
|
92
|
|
93 lock(&mtxset)
|
|
94 unlock(&mtxpoll)
|
111
|
95
|
131
|
96 pd.user = uint32(len(pfds))
|
|
97 var pfd pollfd
|
|
98 pfd.fd = int32(fd)
|
|
99 pfds = append(pfds, pfd)
|
|
100 pds = append(pds, pd)
|
|
101 unlock(&mtxset)
|
111
|
102 return 0
|
|
103 }
|
|
104
|
|
105 func netpollclose(fd uintptr) int32 {
|
131
|
106 lock(&mtxpoll)
|
|
107 netpollwakeup()
|
|
108
|
|
109 lock(&mtxset)
|
|
110 unlock(&mtxpoll)
|
111
|
111
|
131
|
112 for i := 0; i < len(pfds); i++ {
|
|
113 if pfds[i].fd == int32(fd) {
|
|
114 pfds[i] = pfds[len(pfds)-1]
|
|
115 pfds = pfds[:len(pfds)-1]
|
|
116
|
|
117 pds[i] = pds[len(pds)-1]
|
|
118 pds[i].user = uint32(i)
|
|
119 pds = pds[:len(pds)-1]
|
|
120 break
|
|
121 }
|
111
|
122 }
|
131
|
123 unlock(&mtxset)
|
111
|
124 return 0
|
|
125 }
|
|
126
|
|
127 func netpollarm(pd *pollDesc, mode int) {
|
131
|
128 lock(&mtxpoll)
|
|
129 netpollwakeup()
|
|
130
|
|
131 lock(&mtxset)
|
|
132 unlock(&mtxpoll)
|
|
133
|
|
134 switch mode {
|
|
135 case 'r':
|
|
136 pfds[pd.user].events |= _POLLIN
|
|
137 case 'w':
|
|
138 pfds[pd.user].events |= _POLLOUT
|
|
139 }
|
|
140 unlock(&mtxset)
|
111
|
141 }
|
|
142
|
131
|
143 //go:nowritebarrierrec
|
111
|
144 func netpoll(block bool) *g {
|
131
|
145 timeout := ^uintptr(0)
|
111
|
146 if !block {
|
|
147 timeout = 0
|
131
|
148 return nil
|
111
|
149 }
|
|
150 retry:
|
131
|
151 lock(&mtxpoll)
|
|
152 lock(&mtxset)
|
|
153 needsUpdate = false
|
|
154 unlock(&mtxpoll)
|
|
155
|
|
156 n := libc_poll(&pfds[0], uintptr(len(pfds)), timeout)
|
|
157 if n < 0 {
|
|
158 e := errno()
|
|
159 if e != _EINTR {
|
|
160 throw("runtime: poll failed")
|
|
161 }
|
|
162 unlock(&mtxset)
|
111
|
163 goto retry
|
|
164 }
|
131
|
165 // Check if some descriptors need to be changed
|
|
166 if n != 0 && pfds[0].revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
|
|
167 var b [1]byte
|
|
168 for read(rdwake, unsafe.Pointer(&b[0]), 1) == 1 {
|
111
|
169 }
|
131
|
170 // Do not look at the other fds in this case as the mode may have changed
|
|
171 // XXX only additions of flags are made, so maybe it is ok
|
|
172 unlock(&mtxset)
|
111
|
173 goto retry
|
|
174 }
|
|
175 var gp guintptr
|
131
|
176 for i := 0; i < len(pfds) && n > 0; i++ {
|
111
|
177 pfd := &pfds[i]
|
|
178
|
|
179 var mode int32
|
|
180 if pfd.revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
|
|
181 mode += 'r'
|
131
|
182 pfd.events &= ^_POLLIN
|
111
|
183 }
|
|
184 if pfd.revents&(_POLLOUT|_POLLHUP|_POLLERR) != 0 {
|
|
185 mode += 'w'
|
131
|
186 pfd.events &= ^_POLLOUT
|
111
|
187 }
|
|
188 if mode != 0 {
|
131
|
189 netpollready(&gp, pds[i], mode)
|
|
190 n--
|
111
|
191 }
|
|
192 }
|
131
|
193 unlock(&mtxset)
|
111
|
194 if block && gp == 0 {
|
|
195 goto retry
|
|
196 }
|
|
197 return gp.ptr()
|
|
198 }
|