1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
|
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
import "unsafe"
// This is based on the former libgo/runtime/netpoll_select.c implementation
// except that it uses AIX pollset_poll instead of select and is written in Go.
type pollset_t int32
type pollfd struct {
fd int32
events int16
revents int16
}
const _POLLIN = 0x0001
const _POLLOUT = 0x0002
const _POLLHUP = 0x2000
const _POLLERR = 0x4000
type poll_ctl struct {
cmd int16
events int16
fd int32
}
const _PS_ADD = 0x0
const _PS_DELETE = 0x2
//extern pollset_create
func pollset_create(maxfd int32) pollset_t
//go:noescape
//extern pollset_ctl
func pollset_ctl(ps pollset_t, pollctl_array *poll_ctl, array_length int32) int32
//go:noescape
//extern pollset_poll
func pollset_poll(ps pollset_t, polldata_array *pollfd, array_length int32, timeout int32) int32
//go:noescape
//extern pipe
func libc_pipe(fd *int32) int32
//extern __go_fcntl_uintptr
func fcntlUintptr(fd, cmd, arg uintptr) (uintptr, uintptr)
func fcntl(fd, cmd int32, arg uintptr) uintptr {
r, _ := fcntlUintptr(uintptr(fd), uintptr(cmd), arg)
return r
}
var (
ps pollset_t = -1
mpfds map[int32]*pollDesc
pmtx mutex
rdwake int32
wrwake int32
needsUpdate bool
)
func netpollinit() {
var p [2]int32
if ps = pollset_create(-1); ps < 0 {
throw("runtime: netpollinit failed to create pollset")
}
// It is not possible to add or remove descriptors from
// the pollset while pollset_poll is active.
// We use a pipe to wakeup pollset_poll when the pollset
// needs to be updated.
if err := libc_pipe(&p[0]); err < 0 {
throw("runtime: netpollinit failed to create pipe")
}
rdwake = p[0]
wrwake = p[1]
fl := fcntl(rdwake, _F_GETFL, 0)
fcntl(rdwake, _F_SETFL, fl|_O_NONBLOCK)
fcntl(rdwake, _F_SETFD, _FD_CLOEXEC)
fl = fcntl(wrwake, _F_GETFL, 0)
fcntl(wrwake, _F_SETFL, fl|_O_NONBLOCK)
fcntl(wrwake, _F_SETFD, _FD_CLOEXEC)
// Add the read side of the pipe to the pollset.
var pctl poll_ctl
pctl.cmd = _PS_ADD
pctl.fd = rdwake
pctl.events = _POLLIN
if pollset_ctl(ps, &pctl, 1) != 0 {
throw("runtime: netpollinit failed to register pipe")
}
mpfds = make(map[int32]*pollDesc)
}
func netpolldescriptor() uintptr {
// ps is not a real file descriptor.
return ^uintptr(0)
}
func netpollopen(fd uintptr, pd *pollDesc) int32 {
// pollset_ctl will block if pollset_poll is active
// so wakeup pollset_poll first.
lock(&pmtx)
needsUpdate = true
unlock(&pmtx)
b := [1]byte{0}
write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
var pctl poll_ctl
pctl.cmd = _PS_ADD
pctl.fd = int32(fd)
pctl.events = _POLLIN | _POLLOUT
if pollset_ctl(ps, &pctl, 1) != 0 {
return int32(errno())
}
lock(&pmtx)
mpfds[int32(fd)] = pd
needsUpdate = false
unlock(&pmtx)
return 0
}
func netpollclose(fd uintptr) int32 {
// pollset_ctl will block if pollset_poll is active
// so wakeup pollset_poll first.
lock(&pmtx)
needsUpdate = true
unlock(&pmtx)
b := [1]byte{0}
write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
var pctl poll_ctl
pctl.cmd = _PS_DELETE
pctl.fd = int32(fd)
if pollset_ctl(ps, &pctl, 1) != 0 {
return int32(errno())
}
lock(&pmtx)
delete(mpfds, int32(fd))
needsUpdate = false
unlock(&pmtx)
return 0
}
func netpollarm(pd *pollDesc, mode int) {
throw("runtime: unused")
}
func netpoll(block bool) *g {
if ps == -1 {
return nil
}
timeout := int32(-1)
if !block {
timeout = 0
}
var pfds [128]pollfd
retry:
lock(&pmtx)
if needsUpdate {
unlock(&pmtx)
osyield()
goto retry
}
unlock(&pmtx)
nfound := pollset_poll(ps, &pfds[0], int32(len(pfds)), timeout)
if nfound < 0 {
e := errno()
if e != _EINTR {
throw("runtime: pollset_poll failed")
}
goto retry
}
var gp guintptr
for i := int32(0); i < nfound; i++ {
pfd := &pfds[i]
var mode int32
if pfd.revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
if pfd.fd == rdwake {
var b [1]byte
read(pfd.fd, unsafe.Pointer(&b[0]), 1)
continue
}
mode += 'r'
}
if pfd.revents&(_POLLOUT|_POLLHUP|_POLLERR) != 0 {
mode += 'w'
}
if mode != 0 {
lock(&pmtx)
pd := mpfds[pfd.fd]
unlock(&pmtx)
if pd != nil {
netpollready(&gp, pd, mode)
}
}
}
if block && gp == 0 {
goto retry
}
return gp.ptr()
}
|