Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/java/nio/channels/spi/AbstractSelectableChannel.java
41161 views
1
/*
2
* Copyright (c) 2000, 2019, 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 java.nio.channels.spi;
27
28
import java.io.IOException;
29
import java.nio.channels.CancelledKeyException;
30
import java.nio.channels.ClosedChannelException;
31
import java.nio.channels.ClosedSelectorException;
32
import java.nio.channels.IllegalBlockingModeException;
33
import java.nio.channels.IllegalSelectorException;
34
import java.nio.channels.SelectableChannel;
35
import java.nio.channels.SelectionKey;
36
import java.nio.channels.Selector;
37
import java.util.Arrays;
38
import java.util.function.Consumer;
39
40
41
/**
42
* Base implementation class for selectable channels.
43
*
44
* <p> This class defines methods that handle the mechanics of channel
45
* registration, deregistration, and closing. It maintains the current
46
* blocking mode of this channel as well as its current set of selection keys.
47
* It performs all of the synchronization required to implement the {@link
48
* java.nio.channels.SelectableChannel} specification. Implementations of the
49
* protected abstract methods defined in this class need not synchronize
50
* against other threads that might be engaged in the same operations. </p>
51
*
52
*
53
* @author Mark Reinhold
54
* @author Mike McCloskey
55
* @author JSR-51 Expert Group
56
* @since 1.4
57
*/
58
59
public abstract class AbstractSelectableChannel
60
extends SelectableChannel
61
{
62
63
// The provider that created this channel
64
private final SelectorProvider provider;
65
66
// Keys that have been created by registering this channel with selectors.
67
// They are saved because if this channel is closed the keys must be
68
// deregistered. Protected by keyLock.
69
//
70
private SelectionKey[] keys = null;
71
private int keyCount = 0;
72
73
// Lock for key set and count
74
private final Object keyLock = new Object();
75
76
// Lock for registration and configureBlocking operations
77
private final Object regLock = new Object();
78
79
// True when non-blocking, need regLock to change;
80
private volatile boolean nonBlocking;
81
82
/**
83
* Initializes a new instance of this class.
84
*
85
* @param provider
86
* The provider that created this channel
87
*/
88
protected AbstractSelectableChannel(SelectorProvider provider) {
89
this.provider = provider;
90
}
91
92
/**
93
* Returns the provider that created this channel.
94
*
95
* @return The provider that created this channel
96
*/
97
public final SelectorProvider provider() {
98
return provider;
99
}
100
101
102
// -- Utility methods for the key set --
103
104
private void addKey(SelectionKey k) {
105
assert Thread.holdsLock(keyLock);
106
int i = 0;
107
if ((keys != null) && (keyCount < keys.length)) {
108
// Find empty element of key array
109
for (i = 0; i < keys.length; i++)
110
if (keys[i] == null)
111
break;
112
} else if (keys == null) {
113
keys = new SelectionKey[2];
114
} else {
115
// Grow key array
116
int n = keys.length * 2;
117
SelectionKey[] ks = new SelectionKey[n];
118
for (i = 0; i < keys.length; i++)
119
ks[i] = keys[i];
120
keys = ks;
121
i = keyCount;
122
}
123
keys[i] = k;
124
keyCount++;
125
}
126
127
private SelectionKey findKey(Selector sel) {
128
assert Thread.holdsLock(keyLock);
129
if (keys == null)
130
return null;
131
for (int i = 0; i < keys.length; i++)
132
if ((keys[i] != null) && (keys[i].selector() == sel))
133
return keys[i];
134
return null;
135
136
}
137
138
void removeKey(SelectionKey k) { // package-private
139
synchronized (keyLock) {
140
for (int i = 0; i < keys.length; i++)
141
if (keys[i] == k) {
142
keys[i] = null;
143
keyCount--;
144
}
145
((AbstractSelectionKey)k).invalidate();
146
}
147
}
148
149
private boolean haveValidKeys() {
150
synchronized (keyLock) {
151
if (keyCount == 0)
152
return false;
153
for (int i = 0; i < keys.length; i++) {
154
if ((keys[i] != null) && keys[i].isValid())
155
return true;
156
}
157
return false;
158
}
159
}
160
161
162
// -- Registration --
163
164
public final boolean isRegistered() {
165
synchronized (keyLock) {
166
return keyCount != 0;
167
}
168
}
169
170
public final SelectionKey keyFor(Selector sel) {
171
synchronized (keyLock) {
172
return findKey(sel);
173
}
174
}
175
176
/**
177
* Invokes an action for each key.
178
*
179
* This method is invoked by DatagramChannelImpl::disconnect.
180
*/
181
private void forEach(Consumer<SelectionKey> action) {
182
synchronized (keyLock) {
183
SelectionKey[] keys = this.keys;
184
if (keys != null) {
185
Arrays.stream(keys).filter(k -> k != null).forEach(action::accept);
186
}
187
}
188
}
189
190
/**
191
* Registers this channel with the given selector, returning a selection key.
192
*
193
* <p> This method first verifies that this channel is open and that the
194
* given initial interest set is valid.
195
*
196
* <p> If this channel is already registered with the given selector then
197
* the selection key representing that registration is returned after
198
* setting its interest set to the given value.
199
*
200
* <p> Otherwise this channel has not yet been registered with the given
201
* selector, so the {@link AbstractSelector#register register} method of
202
* the selector is invoked while holding the appropriate locks. The
203
* resulting key is added to this channel's key set before being returned.
204
* </p>
205
*
206
* @throws ClosedSelectorException {@inheritDoc}
207
*
208
* @throws IllegalBlockingModeException {@inheritDoc}
209
*
210
* @throws IllegalSelectorException {@inheritDoc}
211
*
212
* @throws CancelledKeyException {@inheritDoc}
213
*
214
* @throws IllegalArgumentException {@inheritDoc}
215
*/
216
public final SelectionKey register(Selector sel, int ops, Object att)
217
throws ClosedChannelException
218
{
219
if ((ops & ~validOps()) != 0)
220
throw new IllegalArgumentException();
221
if (!isOpen())
222
throw new ClosedChannelException();
223
synchronized (regLock) {
224
if (isBlocking())
225
throw new IllegalBlockingModeException();
226
synchronized (keyLock) {
227
// re-check if channel has been closed
228
if (!isOpen())
229
throw new ClosedChannelException();
230
SelectionKey k = findKey(sel);
231
if (k != null) {
232
k.attach(att);
233
k.interestOps(ops);
234
} else {
235
// New registration
236
k = ((AbstractSelector)sel).register(this, ops, att);
237
addKey(k);
238
}
239
return k;
240
}
241
}
242
}
243
244
245
// -- Closing --
246
247
/**
248
* Closes this channel.
249
*
250
* <p> This method, which is specified in the {@link
251
* AbstractInterruptibleChannel} class and is invoked by the {@link
252
* java.nio.channels.Channel#close close} method, in turn invokes the
253
* {@link #implCloseSelectableChannel implCloseSelectableChannel} method in
254
* order to perform the actual work of closing this channel. It then
255
* cancels all of this channel's keys. </p>
256
*/
257
protected final void implCloseChannel() throws IOException {
258
implCloseSelectableChannel();
259
260
// clone keys to avoid calling cancel when holding keyLock
261
SelectionKey[] copyOfKeys = null;
262
synchronized (keyLock) {
263
if (keys != null) {
264
copyOfKeys = keys.clone();
265
}
266
}
267
268
if (copyOfKeys != null) {
269
for (SelectionKey k : copyOfKeys) {
270
if (k != null) {
271
k.cancel(); // invalidate and adds key to cancelledKey set
272
}
273
}
274
}
275
}
276
277
/**
278
* Closes this selectable channel.
279
*
280
* <p> This method is invoked by the {@link java.nio.channels.Channel#close
281
* close} method in order to perform the actual work of closing the
282
* channel. This method is only invoked if the channel has not yet been
283
* closed, and it is never invoked more than once.
284
*
285
* <p> An implementation of this method must arrange for any other thread
286
* that is blocked in an I/O operation upon this channel to return
287
* immediately, either by throwing an exception or by returning normally.
288
* </p>
289
*
290
* @throws IOException
291
* If an I/O error occurs
292
*/
293
protected abstract void implCloseSelectableChannel() throws IOException;
294
295
296
// -- Blocking --
297
298
public final boolean isBlocking() {
299
return !nonBlocking;
300
}
301
302
public final Object blockingLock() {
303
return regLock;
304
}
305
306
/**
307
* Adjusts this channel's blocking mode.
308
*
309
* <p> If the given blocking mode is different from the current blocking
310
* mode then this method invokes the {@link #implConfigureBlocking
311
* implConfigureBlocking} method, while holding the appropriate locks, in
312
* order to change the mode. </p>
313
*/
314
public final SelectableChannel configureBlocking(boolean block)
315
throws IOException
316
{
317
synchronized (regLock) {
318
if (!isOpen())
319
throw new ClosedChannelException();
320
boolean blocking = !nonBlocking;
321
if (block != blocking) {
322
if (block && haveValidKeys())
323
throw new IllegalBlockingModeException();
324
implConfigureBlocking(block);
325
nonBlocking = !block;
326
}
327
}
328
return this;
329
}
330
331
/**
332
* Adjusts this channel's blocking mode.
333
*
334
* <p> This method is invoked by the {@link #configureBlocking
335
* configureBlocking} method in order to perform the actual work of
336
* changing the blocking mode. This method is only invoked if the new mode
337
* is different from the current mode. </p>
338
*
339
* @param block If {@code true} then this channel will be placed in
340
* blocking mode; if {@code false} then it will be placed
341
* non-blocking mode
342
*
343
* @throws IOException
344
* If an I/O error occurs
345
*/
346
protected abstract void implConfigureBlocking(boolean block)
347
throws IOException;
348
349
}
350
351