Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java
32288 views
1
/*
2
* Copyright (c) 2005, 2013, 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.security.AccessController;
30
import java.util.BitSet;
31
import java.util.HashMap;
32
import java.util.Map;
33
import sun.security.action.GetIntegerAction;
34
35
/**
36
* Manipulates a native array of epoll_event structs on Linux:
37
*
38
* typedef union epoll_data {
39
* void *ptr;
40
* int fd;
41
* __uint32_t u32;
42
* __uint64_t u64;
43
* } epoll_data_t;
44
*
45
* struct epoll_event {
46
* __uint32_t events;
47
* epoll_data_t data;
48
* };
49
*
50
* The system call to wait for I/O events is epoll_wait(2). It populates an
51
* array of epoll_event structures that are passed to the call. The data
52
* member of the epoll_event structure contains the same data as was set
53
* when the file descriptor was registered to epoll via epoll_ctl(2). In
54
* this implementation we set data.fd to be the file descriptor that we
55
* register. That way, we have the file descriptor available when we
56
* process the events.
57
*/
58
59
class EPollArrayWrapper {
60
// EPOLL_EVENTS
61
private static final int EPOLLIN = 0x001;
62
63
// opcodes
64
private static final int EPOLL_CTL_ADD = 1;
65
private static final int EPOLL_CTL_DEL = 2;
66
private static final int EPOLL_CTL_MOD = 3;
67
68
// Miscellaneous constants
69
private static final int SIZE_EPOLLEVENT = sizeofEPollEvent();
70
private static final int EVENT_OFFSET = 0;
71
private static final int DATA_OFFSET = offsetofData();
72
private static final int FD_OFFSET = DATA_OFFSET;
73
private static final int OPEN_MAX = IOUtil.fdLimit();
74
private static final int NUM_EPOLLEVENTS = Math.min(OPEN_MAX, 8192);
75
76
// Special value to indicate that an update should be ignored
77
private static final byte KILLED = (byte)-1;
78
79
// Initial size of arrays for fd registration changes
80
private static final int INITIAL_PENDING_UPDATE_SIZE = 64;
81
82
// maximum size of updatesLow
83
private static final int MAX_UPDATE_ARRAY_SIZE = AccessController.doPrivileged(
84
new GetIntegerAction("sun.nio.ch.maxUpdateArraySize", Math.min(OPEN_MAX, 64*1024)));
85
86
// The fd of the epoll driver
87
private final int epfd;
88
89
// The epoll_event array for results from epoll_wait
90
private final AllocatedNativeObject pollArray;
91
92
// Base address of the epoll_event array
93
private final long pollArrayAddress;
94
95
// The fd of the interrupt line going out
96
private int outgoingInterruptFD;
97
98
// The fd of the interrupt line coming in
99
private int incomingInterruptFD;
100
101
// The index of the interrupt FD
102
private int interruptedIndex;
103
104
// Number of updated pollfd entries
105
int updated;
106
107
// object to synchronize fd registration changes
108
private final Object updateLock = new Object();
109
110
// number of file descriptors with registration changes pending
111
private int updateCount;
112
113
// file descriptors with registration changes pending
114
private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE];
115
116
// events for file descriptors with registration changes pending, indexed
117
// by file descriptor and stored as bytes for efficiency reasons. For
118
// file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at
119
// least) then the update is stored in a map.
120
private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE];
121
private Map<Integer,Byte> eventsHigh;
122
123
// Used by release and updateRegistrations to track whether a file
124
// descriptor is registered with epoll.
125
private final BitSet registered = new BitSet();
126
127
128
EPollArrayWrapper() throws IOException {
129
// creates the epoll file descriptor
130
epfd = epollCreate();
131
132
// the epoll_event array passed to epoll_wait
133
int allocationSize = NUM_EPOLLEVENTS * SIZE_EPOLLEVENT;
134
pollArray = new AllocatedNativeObject(allocationSize, true);
135
pollArrayAddress = pollArray.address();
136
137
// eventHigh needed when using file descriptors > 64k
138
if (OPEN_MAX > MAX_UPDATE_ARRAY_SIZE)
139
eventsHigh = new HashMap<>();
140
}
141
142
void initInterrupt(int fd0, int fd1) {
143
outgoingInterruptFD = fd1;
144
incomingInterruptFD = fd0;
145
epollCtl(epfd, EPOLL_CTL_ADD, fd0, EPOLLIN);
146
}
147
148
void putEventOps(int i, int event) {
149
int offset = SIZE_EPOLLEVENT * i + EVENT_OFFSET;
150
pollArray.putInt(offset, event);
151
}
152
153
void putDescriptor(int i, int fd) {
154
int offset = SIZE_EPOLLEVENT * i + FD_OFFSET;
155
pollArray.putInt(offset, fd);
156
}
157
158
int getEventOps(int i) {
159
int offset = SIZE_EPOLLEVENT * i + EVENT_OFFSET;
160
return pollArray.getInt(offset);
161
}
162
163
int getDescriptor(int i) {
164
int offset = SIZE_EPOLLEVENT * i + FD_OFFSET;
165
return pollArray.getInt(offset);
166
}
167
168
/**
169
* Returns {@code true} if updates for the given key (file
170
* descriptor) are killed.
171
*/
172
private boolean isEventsHighKilled(Integer key) {
173
assert key >= MAX_UPDATE_ARRAY_SIZE;
174
Byte value = eventsHigh.get(key);
175
return (value != null && value == KILLED);
176
}
177
178
/**
179
* Sets the pending update events for the given file descriptor. This
180
* method has no effect if the update events is already set to KILLED,
181
* unless {@code force} is {@code true}.
182
*/
183
private void setUpdateEvents(int fd, byte events, boolean force) {
184
if (fd < MAX_UPDATE_ARRAY_SIZE) {
185
if ((eventsLow[fd] != KILLED) || force) {
186
eventsLow[fd] = events;
187
}
188
} else {
189
Integer key = Integer.valueOf(fd);
190
if (!isEventsHighKilled(key) || force) {
191
eventsHigh.put(key, Byte.valueOf(events));
192
}
193
}
194
}
195
196
/**
197
* Returns the pending update events for the given file descriptor.
198
*/
199
private byte getUpdateEvents(int fd) {
200
if (fd < MAX_UPDATE_ARRAY_SIZE) {
201
return eventsLow[fd];
202
} else {
203
Byte result = eventsHigh.get(Integer.valueOf(fd));
204
// result should never be null
205
return result.byteValue();
206
}
207
}
208
209
/**
210
* Update the events for a given file descriptor
211
*/
212
void setInterest(int fd, int mask) {
213
synchronized (updateLock) {
214
// record the file descriptor and events
215
int oldCapacity = updateDescriptors.length;
216
if (updateCount == oldCapacity) {
217
int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE;
218
int[] newDescriptors = new int[newCapacity];
219
System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity);
220
updateDescriptors = newDescriptors;
221
}
222
updateDescriptors[updateCount++] = fd;
223
224
// events are stored as bytes for efficiency reasons
225
byte b = (byte)mask;
226
assert (b == mask) && (b != KILLED);
227
setUpdateEvents(fd, b, false);
228
}
229
}
230
231
/**
232
* Add a file descriptor
233
*/
234
void add(int fd) {
235
// force the initial update events to 0 as it may be KILLED by a
236
// previous registration.
237
synchronized (updateLock) {
238
assert !registered.get(fd);
239
setUpdateEvents(fd, (byte)0, true);
240
}
241
}
242
243
/**
244
* Remove a file descriptor
245
*/
246
void remove(int fd) {
247
synchronized (updateLock) {
248
// kill pending and future update for this file descriptor
249
setUpdateEvents(fd, KILLED, false);
250
251
// remove from epoll
252
if (registered.get(fd)) {
253
epollCtl(epfd, EPOLL_CTL_DEL, fd, 0);
254
registered.clear(fd);
255
}
256
}
257
}
258
259
/**
260
* Close epoll file descriptor and free poll array
261
*/
262
void closeEPollFD() throws IOException {
263
FileDispatcherImpl.closeIntFD(epfd);
264
pollArray.free();
265
}
266
267
int poll(long timeout) throws IOException {
268
updateRegistrations();
269
updated = epollWait(pollArrayAddress, NUM_EPOLLEVENTS, timeout, epfd);
270
for (int i=0; i<updated; i++) {
271
if (getDescriptor(i) == incomingInterruptFD) {
272
interruptedIndex = i;
273
interrupted = true;
274
break;
275
}
276
}
277
return updated;
278
}
279
280
/**
281
* Update the pending registrations.
282
*/
283
private void updateRegistrations() {
284
synchronized (updateLock) {
285
int j = 0;
286
while (j < updateCount) {
287
int fd = updateDescriptors[j];
288
short events = getUpdateEvents(fd);
289
boolean isRegistered = registered.get(fd);
290
int opcode = 0;
291
292
if (events != KILLED) {
293
if (isRegistered) {
294
opcode = (events != 0) ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
295
} else {
296
opcode = (events != 0) ? EPOLL_CTL_ADD : 0;
297
}
298
if (opcode != 0) {
299
epollCtl(epfd, opcode, fd, events);
300
if (opcode == EPOLL_CTL_ADD) {
301
registered.set(fd);
302
} else if (opcode == EPOLL_CTL_DEL) {
303
registered.clear(fd);
304
}
305
}
306
}
307
j++;
308
}
309
updateCount = 0;
310
}
311
}
312
313
// interrupt support
314
private boolean interrupted = false;
315
316
public void interrupt() {
317
interrupt(outgoingInterruptFD);
318
}
319
320
public int interruptedIndex() {
321
return interruptedIndex;
322
}
323
324
boolean interrupted() {
325
return interrupted;
326
}
327
328
void clearInterrupted() {
329
interrupted = false;
330
}
331
332
static {
333
IOUtil.load();
334
init();
335
}
336
337
private native int epollCreate();
338
private native void epollCtl(int epfd, int opcode, int fd, int events);
339
private native int epollWait(long pollAddress, int numfds, long timeout,
340
int epfd) throws IOException;
341
private static native int sizeofEPollEvent();
342
private static native int offsetofData();
343
private static native void interrupt(int fd);
344
private static native void init();
345
}
346
347