Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/nio/ch/Util.java
38918 views
/*1* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.ch;2627import java.lang.ref.SoftReference;28import java.lang.reflect.*;29import java.io.IOException;30import java.io.FileDescriptor;31import java.nio.ByteBuffer;32import java.nio.MappedByteBuffer;33import java.nio.channels.*;34import java.security.AccessController;35import java.security.PrivilegedAction;36import java.util.*;37import sun.misc.Unsafe;38import sun.misc.Cleaner;39import sun.security.action.GetPropertyAction;404142public class Util {4344// -- Caches --4546// The number of temp buffers in our pool47private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX;4849// The max size allowed for a cached temp buffer, in bytes50private static final long MAX_CACHED_BUFFER_SIZE = getMaxCachedBufferSize();5152// Per-thread cache of temporary direct buffers53private static ThreadLocal<BufferCache> bufferCache =54new ThreadLocal<BufferCache>()55{56@Override57protected BufferCache initialValue() {58return new BufferCache();59}60};6162/**63* Returns the max size allowed for a cached temp buffers, in64* bytes. It defaults to Long.MAX_VALUE. It can be set with the65* jdk.nio.maxCachedBufferSize property. Even though66* ByteBuffer.capacity() returns an int, we're using a long here67* for potential future-proofing.68*/69private static long getMaxCachedBufferSize() {70String s = java.security.AccessController.doPrivileged(71new PrivilegedAction<String>() {72@Override73public String run() {74return System.getProperty("jdk.nio.maxCachedBufferSize");75}76});77if (s != null) {78try {79long m = Long.parseLong(s);80if (m >= 0) {81return m;82} else {83// if it's negative, ignore the system property84}85} catch (NumberFormatException e) {86// if the string is not well formed, ignore the system property87}88}89return Long.MAX_VALUE;90}9192/**93* Returns true if a buffer of this size is too large to be94* added to the buffer cache, false otherwise.95*/96private static boolean isBufferTooLarge(int size) {97return size > MAX_CACHED_BUFFER_SIZE;98}99100/**101* Returns true if the buffer is too large to be added to the102* buffer cache, false otherwise.103*/104private static boolean isBufferTooLarge(ByteBuffer buf) {105return isBufferTooLarge(buf.capacity());106}107108/**109* A simple cache of direct buffers.110*/111private static class BufferCache {112// the array of buffers113private ByteBuffer[] buffers;114115// the number of buffers in the cache116private int count;117118// the index of the first valid buffer (undefined if count == 0)119private int start;120121private int next(int i) {122return (i + 1) % TEMP_BUF_POOL_SIZE;123}124125BufferCache() {126buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE];127}128129/**130* Removes and returns a buffer from the cache of at least the given131* size (or null if no suitable buffer is found).132*/133ByteBuffer get(int size) {134// Don't call this if the buffer would be too large.135assert !isBufferTooLarge(size);136137if (count == 0)138return null; // cache is empty139140ByteBuffer[] buffers = this.buffers;141142// search for suitable buffer (often the first buffer will do)143ByteBuffer buf = buffers[start];144if (buf.capacity() < size) {145buf = null;146int i = start;147while ((i = next(i)) != start) {148ByteBuffer bb = buffers[i];149if (bb == null)150break;151if (bb.capacity() >= size) {152buf = bb;153break;154}155}156if (buf == null)157return null;158// move first element to here to avoid re-packing159buffers[i] = buffers[start];160}161162// remove first element163buffers[start] = null;164start = next(start);165count--;166167// prepare the buffer and return it168buf.rewind();169buf.limit(size);170return buf;171}172173boolean offerFirst(ByteBuffer buf) {174// Don't call this if the buffer is too large.175assert !isBufferTooLarge(buf);176177if (count >= TEMP_BUF_POOL_SIZE) {178return false;179} else {180start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE;181buffers[start] = buf;182count++;183return true;184}185}186187boolean offerLast(ByteBuffer buf) {188// Don't call this if the buffer is too large.189assert !isBufferTooLarge(buf);190191if (count >= TEMP_BUF_POOL_SIZE) {192return false;193} else {194int next = (start + count) % TEMP_BUF_POOL_SIZE;195buffers[next] = buf;196count++;197return true;198}199}200201boolean isEmpty() {202return count == 0;203}204205ByteBuffer removeFirst() {206assert count > 0;207ByteBuffer buf = buffers[start];208buffers[start] = null;209start = next(start);210count--;211return buf;212}213}214215/**216* Returns a temporary buffer of at least the given size217*/218public static ByteBuffer getTemporaryDirectBuffer(int size) {219// If a buffer of this size is too large for the cache, there220// should not be a buffer in the cache that is at least as221// large. So we'll just create a new one. Also, we don't have222// to remove the buffer from the cache (as this method does223// below) given that we won't put the new buffer in the cache.224if (isBufferTooLarge(size)) {225return ByteBuffer.allocateDirect(size);226}227228BufferCache cache = bufferCache.get();229ByteBuffer buf = cache.get(size);230if (buf != null) {231return buf;232} else {233// No suitable buffer in the cache so we need to allocate a new234// one. To avoid the cache growing then we remove the first235// buffer from the cache and free it.236if (!cache.isEmpty()) {237buf = cache.removeFirst();238free(buf);239}240return ByteBuffer.allocateDirect(size);241}242}243244/**245* Releases a temporary buffer by returning to the cache or freeing it.246*/247public static void releaseTemporaryDirectBuffer(ByteBuffer buf) {248offerFirstTemporaryDirectBuffer(buf);249}250251/**252* Releases a temporary buffer by returning to the cache or freeing it. If253* returning to the cache then insert it at the start so that it is254* likely to be returned by a subsequent call to getTemporaryDirectBuffer.255*/256static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) {257// If the buffer is too large for the cache we don't have to258// check the cache. We'll just free it.259if (isBufferTooLarge(buf)) {260free(buf);261return;262}263264assert buf != null;265BufferCache cache = bufferCache.get();266if (!cache.offerFirst(buf)) {267// cache is full268free(buf);269}270}271272/**273* Releases a temporary buffer by returning to the cache or freeing it. If274* returning to the cache then insert it at the end. This makes it275* suitable for scatter/gather operations where the buffers are returned to276* cache in same order that they were obtained.277*/278static void offerLastTemporaryDirectBuffer(ByteBuffer buf) {279// If the buffer is too large for the cache we don't have to280// check the cache. We'll just free it.281if (isBufferTooLarge(buf)) {282free(buf);283return;284}285286assert buf != null;287BufferCache cache = bufferCache.get();288if (!cache.offerLast(buf)) {289// cache is full290free(buf);291}292}293294/**295* Frees the memory for the given direct buffer296*/297private static void free(ByteBuffer buf) {298((DirectBuffer)buf).cleaner().clean();299}300301302// -- Random stuff --303304static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) {305if ((offset == 0) && (length == bs.length))306return bs;307int n = length;308ByteBuffer[] bs2 = new ByteBuffer[n];309for (int i = 0; i < n; i++)310bs2[i] = bs[offset + i];311return bs2;312}313314static <E> Set<E> ungrowableSet(final Set<E> s) {315return new Set<E>() {316317public int size() { return s.size(); }318public boolean isEmpty() { return s.isEmpty(); }319public boolean contains(Object o) { return s.contains(o); }320public Object[] toArray() { return s.toArray(); }321public <T> T[] toArray(T[] a) { return s.toArray(a); }322public String toString() { return s.toString(); }323public Iterator<E> iterator() { return s.iterator(); }324public boolean equals(Object o) { return s.equals(o); }325public int hashCode() { return s.hashCode(); }326public void clear() { s.clear(); }327public boolean remove(Object o) { return s.remove(o); }328329public boolean containsAll(Collection<?> coll) {330return s.containsAll(coll);331}332public boolean removeAll(Collection<?> coll) {333return s.removeAll(coll);334}335public boolean retainAll(Collection<?> coll) {336return s.retainAll(coll);337}338339public boolean add(E o){340throw new UnsupportedOperationException();341}342public boolean addAll(Collection<? extends E> coll) {343throw new UnsupportedOperationException();344}345346};347}348349350// -- Unsafe access --351352private static Unsafe unsafe = Unsafe.getUnsafe();353354private static byte _get(long a) {355return unsafe.getByte(a);356}357358private static void _put(long a, byte b) {359unsafe.putByte(a, b);360}361362static void erase(ByteBuffer bb) {363unsafe.setMemory(((DirectBuffer)bb).address(), bb.capacity(), (byte)0);364}365366static Unsafe unsafe() {367return unsafe;368}369370private static int pageSize = -1;371372static int pageSize() {373if (pageSize == -1)374pageSize = unsafe().pageSize();375return pageSize;376}377378private static volatile Constructor<?> directByteBufferConstructor = null;379380private static void initDBBConstructor() {381AccessController.doPrivileged(new PrivilegedAction<Void>() {382public Void run() {383try {384Class<?> cl = Class.forName("java.nio.DirectByteBuffer");385Constructor<?> ctor = cl.getDeclaredConstructor(386new Class<?>[] { int.class,387long.class,388FileDescriptor.class,389Runnable.class });390ctor.setAccessible(true);391directByteBufferConstructor = ctor;392} catch (ClassNotFoundException |393NoSuchMethodException |394IllegalArgumentException |395ClassCastException x) {396throw new InternalError(x);397}398return null;399}});400}401402static MappedByteBuffer newMappedByteBuffer(int size, long addr,403FileDescriptor fd,404Runnable unmapper)405{406MappedByteBuffer dbb;407if (directByteBufferConstructor == null)408initDBBConstructor();409try {410dbb = (MappedByteBuffer)directByteBufferConstructor.newInstance(411new Object[] { new Integer(size),412new Long(addr),413fd,414unmapper });415} catch (InstantiationException |416IllegalAccessException |417InvocationTargetException e) {418throw new InternalError(e);419}420return dbb;421}422423private static volatile Constructor<?> directByteBufferRConstructor = null;424425private static void initDBBRConstructor() {426AccessController.doPrivileged(new PrivilegedAction<Void>() {427public Void run() {428try {429Class<?> cl = Class.forName("java.nio.DirectByteBufferR");430Constructor<?> ctor = cl.getDeclaredConstructor(431new Class<?>[] { int.class,432long.class,433FileDescriptor.class,434Runnable.class });435ctor.setAccessible(true);436directByteBufferRConstructor = ctor;437} catch (ClassNotFoundException |438NoSuchMethodException |439IllegalArgumentException |440ClassCastException x) {441throw new InternalError(x);442}443return null;444}});445}446447static MappedByteBuffer newMappedByteBufferR(int size, long addr,448FileDescriptor fd,449Runnable unmapper)450{451MappedByteBuffer dbb;452if (directByteBufferRConstructor == null)453initDBBRConstructor();454try {455dbb = (MappedByteBuffer)directByteBufferRConstructor.newInstance(456new Object[] { new Integer(size),457new Long(addr),458fd,459unmapper });460} catch (InstantiationException |461IllegalAccessException |462InvocationTargetException e) {463throw new InternalError(e);464}465return dbb;466}467468469// -- Bug compatibility --470471private static volatile String bugLevel = null;472473static boolean atBugLevel(String bl) { // package-private474if (bugLevel == null) {475if (!sun.misc.VM.isBooted())476return false;477String value = AccessController.doPrivileged(478new GetPropertyAction("sun.nio.ch.bugLevel"));479bugLevel = (value != null) ? value : "";480}481return bugLevel.equals(bl);482}483484}485486487