Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java
41137 views
1
/*
2
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.nio.ch;
27
28
import java.io.IOException;
29
import java.nio.channels.ClosedSelectorException;
30
import java.nio.channels.SelectionKey;
31
import java.nio.channels.Selector;
32
import java.nio.channels.spi.SelectorProvider;
33
import java.util.ArrayDeque;
34
import java.util.Deque;
35
import java.util.HashMap;
36
import java.util.Map;
37
import java.util.concurrent.TimeUnit;
38
import java.util.function.Consumer;
39
40
import static sun.nio.ch.KQueue.EVFILT_READ;
41
import static sun.nio.ch.KQueue.EVFILT_WRITE;
42
import static sun.nio.ch.KQueue.EV_ADD;
43
import static sun.nio.ch.KQueue.EV_DELETE;
44
45
/**
46
* KQueue based Selector implementation for macOS
47
*/
48
49
class KQueueSelectorImpl extends SelectorImpl {
50
51
// maximum number of events to poll in one call to kqueue
52
private static final int MAX_KEVENTS = 256;
53
54
// kqueue file descriptor
55
private final int kqfd;
56
57
// address of poll array (event list) when polling for pending events
58
private final long pollArrayAddress;
59
60
// file descriptors used for interrupt
61
private final int fd0;
62
private final int fd1;
63
64
// maps file descriptor to selection key, synchronize on selector
65
private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
66
67
// pending new registrations/updates, queued by setEventOps
68
private final Object updateLock = new Object();
69
private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
70
71
// interrupt triggering and clearing
72
private final Object interruptLock = new Object();
73
private boolean interruptTriggered;
74
75
// used by updateSelectedKeys to handle cases where the same file
76
// descriptor is polled by more than one filter
77
private int pollCount;
78
79
KQueueSelectorImpl(SelectorProvider sp) throws IOException {
80
super(sp);
81
82
this.kqfd = KQueue.create();
83
this.pollArrayAddress = KQueue.allocatePollArray(MAX_KEVENTS);
84
85
try {
86
long fds = IOUtil.makePipe(false);
87
this.fd0 = (int) (fds >>> 32);
88
this.fd1 = (int) fds;
89
} catch (IOException ioe) {
90
KQueue.freePollArray(pollArrayAddress);
91
FileDispatcherImpl.closeIntFD(kqfd);
92
throw ioe;
93
}
94
95
// register one end of the socket pair for wakeups
96
KQueue.register(kqfd, fd0, EVFILT_READ, EV_ADD);
97
}
98
99
private void ensureOpen() {
100
if (!isOpen())
101
throw new ClosedSelectorException();
102
}
103
104
@Override
105
protected int doSelect(Consumer<SelectionKey> action, long timeout)
106
throws IOException
107
{
108
assert Thread.holdsLock(this);
109
110
long to = Math.min(timeout, Integer.MAX_VALUE); // max kqueue timeout
111
boolean blocking = (to != 0);
112
boolean timedPoll = (to > 0);
113
114
int numEntries;
115
processUpdateQueue();
116
processDeregisterQueue();
117
try {
118
begin(blocking);
119
120
do {
121
long startTime = timedPoll ? System.nanoTime() : 0;
122
numEntries = KQueue.poll(kqfd, pollArrayAddress, MAX_KEVENTS, to);
123
if (numEntries == IOStatus.INTERRUPTED && timedPoll) {
124
// timed poll interrupted so need to adjust timeout
125
long adjust = System.nanoTime() - startTime;
126
to -= TimeUnit.MILLISECONDS.convert(adjust, TimeUnit.NANOSECONDS);
127
if (to <= 0) {
128
// timeout expired so no retry
129
numEntries = 0;
130
}
131
}
132
} while (numEntries == IOStatus.INTERRUPTED);
133
assert IOStatus.check(numEntries);
134
135
} finally {
136
end(blocking);
137
}
138
processDeregisterQueue();
139
return processEvents(numEntries, action);
140
}
141
142
/**
143
* Process changes to the interest ops.
144
*/
145
private void processUpdateQueue() {
146
assert Thread.holdsLock(this);
147
148
synchronized (updateLock) {
149
SelectionKeyImpl ski;
150
while ((ski = updateKeys.pollFirst()) != null) {
151
if (ski.isValid()) {
152
int fd = ski.getFDVal();
153
// add to fdToKey if needed
154
SelectionKeyImpl previous = fdToKey.putIfAbsent(fd, ski);
155
assert (previous == null) || (previous == ski);
156
157
int newEvents = ski.translateInterestOps();
158
int registeredEvents = ski.registeredEvents();
159
160
// DatagramChannelImpl::disconnect has reset socket
161
if (ski.getAndClearReset() && registeredEvents != 0) {
162
KQueue.register(kqfd, fd, EVFILT_READ, EV_DELETE);
163
registeredEvents = 0;
164
}
165
166
if (newEvents != registeredEvents) {
167
168
// add or delete interest in read events
169
if ((registeredEvents & Net.POLLIN) != 0) {
170
if ((newEvents & Net.POLLIN) == 0) {
171
KQueue.register(kqfd, fd, EVFILT_READ, EV_DELETE);
172
}
173
} else if ((newEvents & Net.POLLIN) != 0) {
174
KQueue.register(kqfd, fd, EVFILT_READ, EV_ADD);
175
}
176
177
// add or delete interest in write events
178
if ((registeredEvents & Net.POLLOUT) != 0) {
179
if ((newEvents & Net.POLLOUT) == 0) {
180
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_DELETE);
181
}
182
} else if ((newEvents & Net.POLLOUT) != 0) {
183
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_ADD);
184
}
185
186
ski.registeredEvents(newEvents);
187
}
188
}
189
}
190
}
191
}
192
193
/**
194
* Process the polled events.
195
* If the interrupt fd has been selected, drain it and clear the interrupt.
196
*/
197
private int processEvents(int numEntries, Consumer<SelectionKey> action)
198
throws IOException
199
{
200
assert Thread.holdsLock(this);
201
202
int numKeysUpdated = 0;
203
boolean interrupted = false;
204
205
// A file descriptor may be registered with kqueue with more than one
206
// filter and so there may be more than one event for a fd. The poll
207
// count is incremented here and compared against the SelectionKey's
208
// "lastPolled" field. This ensures that the ready ops is updated rather
209
// than replaced when a file descriptor is polled by both the read and
210
// write filter.
211
pollCount++;
212
213
for (int i = 0; i < numEntries; i++) {
214
long kevent = KQueue.getEvent(pollArrayAddress, i);
215
int fd = KQueue.getDescriptor(kevent);
216
if (fd == fd0) {
217
interrupted = true;
218
} else {
219
SelectionKeyImpl ski = fdToKey.get(fd);
220
if (ski != null) {
221
int rOps = 0;
222
short filter = KQueue.getFilter(kevent);
223
if (filter == EVFILT_READ) {
224
rOps |= Net.POLLIN;
225
} else if (filter == EVFILT_WRITE) {
226
rOps |= Net.POLLOUT;
227
}
228
int updated = processReadyEvents(rOps, ski, action);
229
if (updated > 0 && ski.lastPolled != pollCount) {
230
numKeysUpdated++;
231
ski.lastPolled = pollCount;
232
}
233
}
234
}
235
}
236
237
if (interrupted) {
238
clearInterrupt();
239
}
240
return numKeysUpdated;
241
}
242
243
@Override
244
protected void implClose() throws IOException {
245
assert !isOpen();
246
assert Thread.holdsLock(this);
247
248
// prevent further wakeup
249
synchronized (interruptLock) {
250
interruptTriggered = true;
251
}
252
253
FileDispatcherImpl.closeIntFD(kqfd);
254
KQueue.freePollArray(pollArrayAddress);
255
256
FileDispatcherImpl.closeIntFD(fd0);
257
FileDispatcherImpl.closeIntFD(fd1);
258
}
259
260
@Override
261
protected void implDereg(SelectionKeyImpl ski) throws IOException {
262
assert !ski.isValid();
263
assert Thread.holdsLock(this);
264
265
int fd = ski.getFDVal();
266
int registeredEvents = ski.registeredEvents();
267
if (fdToKey.remove(fd) != null) {
268
if (registeredEvents != 0) {
269
if ((registeredEvents & Net.POLLIN) != 0)
270
KQueue.register(kqfd, fd, EVFILT_READ, EV_DELETE);
271
if ((registeredEvents & Net.POLLOUT) != 0)
272
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_DELETE);
273
ski.registeredEvents(0);
274
}
275
} else {
276
assert registeredEvents == 0;
277
}
278
}
279
280
@Override
281
public void setEventOps(SelectionKeyImpl ski) {
282
ensureOpen();
283
synchronized (updateLock) {
284
updateKeys.addLast(ski);
285
}
286
}
287
288
@Override
289
public Selector wakeup() {
290
synchronized (interruptLock) {
291
if (!interruptTriggered) {
292
try {
293
IOUtil.write1(fd1, (byte)0);
294
} catch (IOException ioe) {
295
throw new InternalError(ioe);
296
}
297
interruptTriggered = true;
298
}
299
}
300
return this;
301
}
302
303
private void clearInterrupt() throws IOException {
304
synchronized (interruptLock) {
305
IOUtil.drain(fd0);
306
interruptTriggered = false;
307
}
308
}
309
}
310
311