Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/nio/ch/Util.java
38918 views
1
/*
2
* Copyright (c) 2000, 2016, 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.lang.ref.SoftReference;
29
import java.lang.reflect.*;
30
import java.io.IOException;
31
import java.io.FileDescriptor;
32
import java.nio.ByteBuffer;
33
import java.nio.MappedByteBuffer;
34
import java.nio.channels.*;
35
import java.security.AccessController;
36
import java.security.PrivilegedAction;
37
import java.util.*;
38
import sun.misc.Unsafe;
39
import sun.misc.Cleaner;
40
import sun.security.action.GetPropertyAction;
41
42
43
public class Util {
44
45
// -- Caches --
46
47
// The number of temp buffers in our pool
48
private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX;
49
50
// The max size allowed for a cached temp buffer, in bytes
51
private static final long MAX_CACHED_BUFFER_SIZE = getMaxCachedBufferSize();
52
53
// Per-thread cache of temporary direct buffers
54
private static ThreadLocal<BufferCache> bufferCache =
55
new ThreadLocal<BufferCache>()
56
{
57
@Override
58
protected BufferCache initialValue() {
59
return new BufferCache();
60
}
61
};
62
63
/**
64
* Returns the max size allowed for a cached temp buffers, in
65
* bytes. It defaults to Long.MAX_VALUE. It can be set with the
66
* jdk.nio.maxCachedBufferSize property. Even though
67
* ByteBuffer.capacity() returns an int, we're using a long here
68
* for potential future-proofing.
69
*/
70
private static long getMaxCachedBufferSize() {
71
String s = java.security.AccessController.doPrivileged(
72
new PrivilegedAction<String>() {
73
@Override
74
public String run() {
75
return System.getProperty("jdk.nio.maxCachedBufferSize");
76
}
77
});
78
if (s != null) {
79
try {
80
long m = Long.parseLong(s);
81
if (m >= 0) {
82
return m;
83
} else {
84
// if it's negative, ignore the system property
85
}
86
} catch (NumberFormatException e) {
87
// if the string is not well formed, ignore the system property
88
}
89
}
90
return Long.MAX_VALUE;
91
}
92
93
/**
94
* Returns true if a buffer of this size is too large to be
95
* added to the buffer cache, false otherwise.
96
*/
97
private static boolean isBufferTooLarge(int size) {
98
return size > MAX_CACHED_BUFFER_SIZE;
99
}
100
101
/**
102
* Returns true if the buffer is too large to be added to the
103
* buffer cache, false otherwise.
104
*/
105
private static boolean isBufferTooLarge(ByteBuffer buf) {
106
return isBufferTooLarge(buf.capacity());
107
}
108
109
/**
110
* A simple cache of direct buffers.
111
*/
112
private static class BufferCache {
113
// the array of buffers
114
private ByteBuffer[] buffers;
115
116
// the number of buffers in the cache
117
private int count;
118
119
// the index of the first valid buffer (undefined if count == 0)
120
private int start;
121
122
private int next(int i) {
123
return (i + 1) % TEMP_BUF_POOL_SIZE;
124
}
125
126
BufferCache() {
127
buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE];
128
}
129
130
/**
131
* Removes and returns a buffer from the cache of at least the given
132
* size (or null if no suitable buffer is found).
133
*/
134
ByteBuffer get(int size) {
135
// Don't call this if the buffer would be too large.
136
assert !isBufferTooLarge(size);
137
138
if (count == 0)
139
return null; // cache is empty
140
141
ByteBuffer[] buffers = this.buffers;
142
143
// search for suitable buffer (often the first buffer will do)
144
ByteBuffer buf = buffers[start];
145
if (buf.capacity() < size) {
146
buf = null;
147
int i = start;
148
while ((i = next(i)) != start) {
149
ByteBuffer bb = buffers[i];
150
if (bb == null)
151
break;
152
if (bb.capacity() >= size) {
153
buf = bb;
154
break;
155
}
156
}
157
if (buf == null)
158
return null;
159
// move first element to here to avoid re-packing
160
buffers[i] = buffers[start];
161
}
162
163
// remove first element
164
buffers[start] = null;
165
start = next(start);
166
count--;
167
168
// prepare the buffer and return it
169
buf.rewind();
170
buf.limit(size);
171
return buf;
172
}
173
174
boolean offerFirst(ByteBuffer buf) {
175
// Don't call this if the buffer is too large.
176
assert !isBufferTooLarge(buf);
177
178
if (count >= TEMP_BUF_POOL_SIZE) {
179
return false;
180
} else {
181
start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE;
182
buffers[start] = buf;
183
count++;
184
return true;
185
}
186
}
187
188
boolean offerLast(ByteBuffer buf) {
189
// Don't call this if the buffer is too large.
190
assert !isBufferTooLarge(buf);
191
192
if (count >= TEMP_BUF_POOL_SIZE) {
193
return false;
194
} else {
195
int next = (start + count) % TEMP_BUF_POOL_SIZE;
196
buffers[next] = buf;
197
count++;
198
return true;
199
}
200
}
201
202
boolean isEmpty() {
203
return count == 0;
204
}
205
206
ByteBuffer removeFirst() {
207
assert count > 0;
208
ByteBuffer buf = buffers[start];
209
buffers[start] = null;
210
start = next(start);
211
count--;
212
return buf;
213
}
214
}
215
216
/**
217
* Returns a temporary buffer of at least the given size
218
*/
219
public static ByteBuffer getTemporaryDirectBuffer(int size) {
220
// If a buffer of this size is too large for the cache, there
221
// should not be a buffer in the cache that is at least as
222
// large. So we'll just create a new one. Also, we don't have
223
// to remove the buffer from the cache (as this method does
224
// below) given that we won't put the new buffer in the cache.
225
if (isBufferTooLarge(size)) {
226
return ByteBuffer.allocateDirect(size);
227
}
228
229
BufferCache cache = bufferCache.get();
230
ByteBuffer buf = cache.get(size);
231
if (buf != null) {
232
return buf;
233
} else {
234
// No suitable buffer in the cache so we need to allocate a new
235
// one. To avoid the cache growing then we remove the first
236
// buffer from the cache and free it.
237
if (!cache.isEmpty()) {
238
buf = cache.removeFirst();
239
free(buf);
240
}
241
return ByteBuffer.allocateDirect(size);
242
}
243
}
244
245
/**
246
* Releases a temporary buffer by returning to the cache or freeing it.
247
*/
248
public static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
249
offerFirstTemporaryDirectBuffer(buf);
250
}
251
252
/**
253
* Releases a temporary buffer by returning to the cache or freeing it. If
254
* returning to the cache then insert it at the start so that it is
255
* likely to be returned by a subsequent call to getTemporaryDirectBuffer.
256
*/
257
static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) {
258
// If the buffer is too large for the cache we don't have to
259
// check the cache. We'll just free it.
260
if (isBufferTooLarge(buf)) {
261
free(buf);
262
return;
263
}
264
265
assert buf != null;
266
BufferCache cache = bufferCache.get();
267
if (!cache.offerFirst(buf)) {
268
// cache is full
269
free(buf);
270
}
271
}
272
273
/**
274
* Releases a temporary buffer by returning to the cache or freeing it. If
275
* returning to the cache then insert it at the end. This makes it
276
* suitable for scatter/gather operations where the buffers are returned to
277
* cache in same order that they were obtained.
278
*/
279
static void offerLastTemporaryDirectBuffer(ByteBuffer buf) {
280
// If the buffer is too large for the cache we don't have to
281
// check the cache. We'll just free it.
282
if (isBufferTooLarge(buf)) {
283
free(buf);
284
return;
285
}
286
287
assert buf != null;
288
BufferCache cache = bufferCache.get();
289
if (!cache.offerLast(buf)) {
290
// cache is full
291
free(buf);
292
}
293
}
294
295
/**
296
* Frees the memory for the given direct buffer
297
*/
298
private static void free(ByteBuffer buf) {
299
((DirectBuffer)buf).cleaner().clean();
300
}
301
302
303
// -- Random stuff --
304
305
static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) {
306
if ((offset == 0) && (length == bs.length))
307
return bs;
308
int n = length;
309
ByteBuffer[] bs2 = new ByteBuffer[n];
310
for (int i = 0; i < n; i++)
311
bs2[i] = bs[offset + i];
312
return bs2;
313
}
314
315
static <E> Set<E> ungrowableSet(final Set<E> s) {
316
return new Set<E>() {
317
318
public int size() { return s.size(); }
319
public boolean isEmpty() { return s.isEmpty(); }
320
public boolean contains(Object o) { return s.contains(o); }
321
public Object[] toArray() { return s.toArray(); }
322
public <T> T[] toArray(T[] a) { return s.toArray(a); }
323
public String toString() { return s.toString(); }
324
public Iterator<E> iterator() { return s.iterator(); }
325
public boolean equals(Object o) { return s.equals(o); }
326
public int hashCode() { return s.hashCode(); }
327
public void clear() { s.clear(); }
328
public boolean remove(Object o) { return s.remove(o); }
329
330
public boolean containsAll(Collection<?> coll) {
331
return s.containsAll(coll);
332
}
333
public boolean removeAll(Collection<?> coll) {
334
return s.removeAll(coll);
335
}
336
public boolean retainAll(Collection<?> coll) {
337
return s.retainAll(coll);
338
}
339
340
public boolean add(E o){
341
throw new UnsupportedOperationException();
342
}
343
public boolean addAll(Collection<? extends E> coll) {
344
throw new UnsupportedOperationException();
345
}
346
347
};
348
}
349
350
351
// -- Unsafe access --
352
353
private static Unsafe unsafe = Unsafe.getUnsafe();
354
355
private static byte _get(long a) {
356
return unsafe.getByte(a);
357
}
358
359
private static void _put(long a, byte b) {
360
unsafe.putByte(a, b);
361
}
362
363
static void erase(ByteBuffer bb) {
364
unsafe.setMemory(((DirectBuffer)bb).address(), bb.capacity(), (byte)0);
365
}
366
367
static Unsafe unsafe() {
368
return unsafe;
369
}
370
371
private static int pageSize = -1;
372
373
static int pageSize() {
374
if (pageSize == -1)
375
pageSize = unsafe().pageSize();
376
return pageSize;
377
}
378
379
private static volatile Constructor<?> directByteBufferConstructor = null;
380
381
private static void initDBBConstructor() {
382
AccessController.doPrivileged(new PrivilegedAction<Void>() {
383
public Void run() {
384
try {
385
Class<?> cl = Class.forName("java.nio.DirectByteBuffer");
386
Constructor<?> ctor = cl.getDeclaredConstructor(
387
new Class<?>[] { int.class,
388
long.class,
389
FileDescriptor.class,
390
Runnable.class });
391
ctor.setAccessible(true);
392
directByteBufferConstructor = ctor;
393
} catch (ClassNotFoundException |
394
NoSuchMethodException |
395
IllegalArgumentException |
396
ClassCastException x) {
397
throw new InternalError(x);
398
}
399
return null;
400
}});
401
}
402
403
static MappedByteBuffer newMappedByteBuffer(int size, long addr,
404
FileDescriptor fd,
405
Runnable unmapper)
406
{
407
MappedByteBuffer dbb;
408
if (directByteBufferConstructor == null)
409
initDBBConstructor();
410
try {
411
dbb = (MappedByteBuffer)directByteBufferConstructor.newInstance(
412
new Object[] { new Integer(size),
413
new Long(addr),
414
fd,
415
unmapper });
416
} catch (InstantiationException |
417
IllegalAccessException |
418
InvocationTargetException e) {
419
throw new InternalError(e);
420
}
421
return dbb;
422
}
423
424
private static volatile Constructor<?> directByteBufferRConstructor = null;
425
426
private static void initDBBRConstructor() {
427
AccessController.doPrivileged(new PrivilegedAction<Void>() {
428
public Void run() {
429
try {
430
Class<?> cl = Class.forName("java.nio.DirectByteBufferR");
431
Constructor<?> ctor = cl.getDeclaredConstructor(
432
new Class<?>[] { int.class,
433
long.class,
434
FileDescriptor.class,
435
Runnable.class });
436
ctor.setAccessible(true);
437
directByteBufferRConstructor = ctor;
438
} catch (ClassNotFoundException |
439
NoSuchMethodException |
440
IllegalArgumentException |
441
ClassCastException x) {
442
throw new InternalError(x);
443
}
444
return null;
445
}});
446
}
447
448
static MappedByteBuffer newMappedByteBufferR(int size, long addr,
449
FileDescriptor fd,
450
Runnable unmapper)
451
{
452
MappedByteBuffer dbb;
453
if (directByteBufferRConstructor == null)
454
initDBBRConstructor();
455
try {
456
dbb = (MappedByteBuffer)directByteBufferRConstructor.newInstance(
457
new Object[] { new Integer(size),
458
new Long(addr),
459
fd,
460
unmapper });
461
} catch (InstantiationException |
462
IllegalAccessException |
463
InvocationTargetException e) {
464
throw new InternalError(e);
465
}
466
return dbb;
467
}
468
469
470
// -- Bug compatibility --
471
472
private static volatile String bugLevel = null;
473
474
static boolean atBugLevel(String bl) { // package-private
475
if (bugLevel == null) {
476
if (!sun.misc.VM.isBooted())
477
return false;
478
String value = AccessController.doPrivileged(
479
new GetPropertyAction("sun.nio.ch.bugLevel"));
480
bugLevel = (value != null) ? value : "";
481
}
482
return bugLevel.equals(bl);
483
}
484
485
}
486
487