0N/A/*
3261N/A * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.nio.ch;
0N/A
0N/Aimport java.lang.ref.SoftReference;
0N/Aimport java.lang.reflect.*;
0N/Aimport java.io.IOException;
2984N/Aimport java.io.FileDescriptor;
0N/Aimport java.nio.ByteBuffer;
0N/Aimport java.nio.MappedByteBuffer;
0N/Aimport java.nio.channels.*;
0N/Aimport java.security.AccessController;
0N/Aimport java.security.PrivilegedAction;
0N/Aimport java.util.*;
0N/Aimport sun.misc.Unsafe;
0N/Aimport sun.misc.Cleaner;
0N/Aimport sun.security.action.GetPropertyAction;
0N/A
0N/A
0N/Aclass Util {
0N/A
0N/A // -- Caches --
0N/A
0N/A // The number of temp buffers in our pool
5204N/A private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX;
0N/A
2655N/A // Per-thread cache of temporary direct buffers
2655N/A private static ThreadLocal<BufferCache> bufferCache =
2655N/A new ThreadLocal<BufferCache>()
2655N/A {
2655N/A @Override
2655N/A protected BufferCache initialValue() {
2655N/A return new BufferCache();
2655N/A }
2655N/A };
2655N/A
2655N/A /**
2655N/A * A simple cache of direct buffers.
2655N/A */
2655N/A private static class BufferCache {
2655N/A // the array of buffers
2655N/A private ByteBuffer[] buffers;
0N/A
2655N/A // the number of buffers in the cache
2655N/A private int count;
2655N/A
2655N/A // the index of the first valid buffer (undefined if count == 0)
2655N/A private int start;
2655N/A
2655N/A private int next(int i) {
2655N/A return (i + 1) % TEMP_BUF_POOL_SIZE;
2655N/A }
2655N/A
2655N/A BufferCache() {
2655N/A buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE];
2655N/A }
2655N/A
2655N/A /**
2655N/A * Removes and returns a buffer from the cache of at least the given
2655N/A * size (or null if no suitable buffer is found).
2655N/A */
2655N/A ByteBuffer get(int size) {
2655N/A if (count == 0)
2655N/A return null; // cache is empty
438N/A
2655N/A ByteBuffer[] buffers = this.buffers;
0N/A
2655N/A // search for suitable buffer (often the first buffer will do)
2655N/A ByteBuffer buf = buffers[start];
2655N/A if (buf.capacity() < size) {
2655N/A buf = null;
2655N/A int i = start;
2655N/A while ((i = next(i)) != start) {
2655N/A ByteBuffer bb = buffers[i];
2655N/A if (bb == null)
2655N/A break;
2655N/A if (bb.capacity() >= size) {
2655N/A buf = bb;
2655N/A break;
2655N/A }
2655N/A }
2655N/A if (buf == null)
2655N/A return null;
2655N/A // move first element to here to avoid re-packing
2655N/A buffers[i] = buffers[start];
2655N/A }
2655N/A
2655N/A // remove first element
2655N/A buffers[start] = null;
2655N/A start = next(start);
2655N/A count--;
2655N/A
2655N/A // prepare the buffer and return it
2655N/A buf.rewind();
2655N/A buf.limit(size);
2655N/A return buf;
2655N/A }
2655N/A
2655N/A boolean offerFirst(ByteBuffer buf) {
2655N/A if (count >= TEMP_BUF_POOL_SIZE) {
2655N/A return false;
2655N/A } else {
2655N/A start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE;
2655N/A buffers[start] = buf;
2655N/A count++;
2655N/A return true;
0N/A }
0N/A }
0N/A
2655N/A boolean offerLast(ByteBuffer buf) {
2655N/A if (count >= TEMP_BUF_POOL_SIZE) {
2655N/A return false;
2655N/A } else {
2655N/A int next = (start + count) % TEMP_BUF_POOL_SIZE;
2655N/A buffers[next] = buf;
2655N/A count++;
2655N/A return true;
0N/A }
0N/A }
893N/A
2655N/A boolean isEmpty() {
2655N/A return count == 0;
2655N/A }
2655N/A
2655N/A ByteBuffer removeFirst() {
2655N/A assert count > 0;
2655N/A ByteBuffer buf = buffers[start];
2655N/A buffers[start] = null;
2655N/A start = next(start);
2655N/A count--;
2655N/A return buf;
2655N/A }
2655N/A }
2655N/A
2655N/A /**
2655N/A * Returns a temporary buffer of at least the given size
2655N/A */
2655N/A static ByteBuffer getTemporaryDirectBuffer(int size) {
2655N/A BufferCache cache = bufferCache.get();
2655N/A ByteBuffer buf = cache.get(size);
2655N/A if (buf != null) {
2655N/A return buf;
2655N/A } else {
2655N/A // No suitable buffer in the cache so we need to allocate a new
2655N/A // one. To avoid the cache growing then we remove the first
2655N/A // buffer from the cache and free it.
2655N/A if (!cache.isEmpty()) {
2655N/A buf = cache.removeFirst();
2655N/A free(buf);
2655N/A }
2655N/A return ByteBuffer.allocateDirect(size);
2655N/A }
2655N/A }
2655N/A
2655N/A /**
2655N/A * Releases a temporary buffer by returning to the cache or freeing it.
2655N/A */
2655N/A static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
2655N/A offerFirstTemporaryDirectBuffer(buf);
2655N/A }
2655N/A
2655N/A /**
2655N/A * Releases a temporary buffer by returning to the cache or freeing it. If
2655N/A * returning to the cache then insert it at the start so that it is
2655N/A * likely to be returned by a subsequent call to getTemporaryDirectBuffer.
2655N/A */
2655N/A static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) {
2655N/A assert buf != null;
2655N/A BufferCache cache = bufferCache.get();
2655N/A if (!cache.offerFirst(buf)) {
2655N/A // cache is full
2655N/A free(buf);
2655N/A }
2655N/A }
2655N/A
2655N/A /**
2655N/A * Releases a temporary buffer by returning to the cache or freeing it. If
2655N/A * returning to the cache then insert it at the end. This makes it
2655N/A * suitable for scatter/gather operations where the buffers are returned to
2655N/A * cache in same order that they were obtained.
2655N/A */
2655N/A static void offerLastTemporaryDirectBuffer(ByteBuffer buf) {
2655N/A assert buf != null;
2655N/A BufferCache cache = bufferCache.get();
2655N/A if (!cache.offerLast(buf)) {
2655N/A // cache is full
2655N/A free(buf);
2655N/A }
2655N/A }
2655N/A
2655N/A /**
2655N/A * Frees the memory for the given direct buffer
2655N/A */
2655N/A private static void free(ByteBuffer buf) {
2655N/A ((DirectBuffer)buf).cleaner().clean();
0N/A }
0N/A
0N/A private static class SelectorWrapper {
0N/A private Selector sel;
0N/A private SelectorWrapper (Selector sel) {
0N/A this.sel = sel;
0N/A Cleaner.create(this, new Closer(sel));
0N/A }
0N/A private static class Closer implements Runnable {
0N/A private Selector sel;
0N/A private Closer (Selector sel) {
0N/A this.sel = sel;
0N/A }
0N/A public void run () {
0N/A try {
0N/A sel.close();
0N/A } catch (Throwable th) {
0N/A throw new Error(th);
0N/A }
0N/A }
0N/A }
0N/A public Selector get() { return sel;}
0N/A }
0N/A
0N/A // Per-thread cached selector
28N/A private static ThreadLocal<SoftReference<SelectorWrapper>> localSelector
28N/A = new ThreadLocal<SoftReference<SelectorWrapper>>();
0N/A // Hold a reference to the selWrapper object to prevent it from
0N/A // being cleaned when the temporary selector wrapped is on lease.
28N/A private static ThreadLocal<SelectorWrapper> localSelectorWrapper
28N/A = new ThreadLocal<SelectorWrapper>();
0N/A
0N/A // When finished, invoker must ensure that selector is empty
0N/A // by cancelling any related keys and explicitly releasing
0N/A // the selector by invoking releaseTemporarySelector()
0N/A static Selector getTemporarySelector(SelectableChannel sc)
0N/A throws IOException
0N/A {
28N/A SoftReference<SelectorWrapper> ref = localSelector.get();
0N/A SelectorWrapper selWrapper = null;
0N/A Selector sel = null;
0N/A if (ref == null
28N/A || ((selWrapper = ref.get()) == null)
0N/A || ((sel = selWrapper.get()) == null)
0N/A || (sel.provider() != sc.provider())) {
0N/A sel = sc.provider().openSelector();
386N/A selWrapper = new SelectorWrapper(sel);
386N/A localSelector.set(new SoftReference<SelectorWrapper>(selWrapper));
0N/A }
386N/A localSelectorWrapper.set(selWrapper);
0N/A return sel;
0N/A }
0N/A
0N/A static void releaseTemporarySelector(Selector sel)
0N/A throws IOException
0N/A {
0N/A // Selector should be empty
0N/A sel.selectNow(); // Flush cancelled keys
0N/A assert sel.keys().isEmpty() : "Temporary selector not empty";
0N/A localSelectorWrapper.set(null);
0N/A }
0N/A
0N/A
0N/A // -- Random stuff --
0N/A
0N/A static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) {
0N/A if ((offset == 0) && (length == bs.length))
0N/A return bs;
0N/A int n = length;
0N/A ByteBuffer[] bs2 = new ByteBuffer[n];
0N/A for (int i = 0; i < n; i++)
0N/A bs2[i] = bs[offset + i];
0N/A return bs2;
0N/A }
0N/A
0N/A static <E> Set<E> ungrowableSet(final Set<E> s) {
0N/A return new Set<E>() {
0N/A
0N/A public int size() { return s.size(); }
0N/A public boolean isEmpty() { return s.isEmpty(); }
0N/A public boolean contains(Object o) { return s.contains(o); }
0N/A public Object[] toArray() { return s.toArray(); }
0N/A public <T> T[] toArray(T[] a) { return s.toArray(a); }
0N/A public String toString() { return s.toString(); }
0N/A public Iterator<E> iterator() { return s.iterator(); }
0N/A public boolean equals(Object o) { return s.equals(o); }
0N/A public int hashCode() { return s.hashCode(); }
0N/A public void clear() { s.clear(); }
0N/A public boolean remove(Object o) { return s.remove(o); }
0N/A
0N/A public boolean containsAll(Collection<?> coll) {
0N/A return s.containsAll(coll);
0N/A }
0N/A public boolean removeAll(Collection<?> coll) {
0N/A return s.removeAll(coll);
0N/A }
0N/A public boolean retainAll(Collection<?> coll) {
0N/A return s.retainAll(coll);
0N/A }
0N/A
0N/A public boolean add(E o){
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A public boolean addAll(Collection<? extends E> coll) {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A
0N/A };
0N/A }
0N/A
0N/A
0N/A // -- Unsafe access --
0N/A
0N/A private static Unsafe unsafe = Unsafe.getUnsafe();
0N/A
0N/A private static byte _get(long a) {
0N/A return unsafe.getByte(a);
0N/A }
0N/A
0N/A private static void _put(long a, byte b) {
0N/A unsafe.putByte(a, b);
0N/A }
0N/A
0N/A static void erase(ByteBuffer bb) {
0N/A unsafe.setMemory(((DirectBuffer)bb).address(), bb.capacity(), (byte)0);
0N/A }
0N/A
0N/A static Unsafe unsafe() {
0N/A return unsafe;
0N/A }
0N/A
0N/A private static int pageSize = -1;
0N/A
0N/A static int pageSize() {
0N/A if (pageSize == -1)
0N/A pageSize = unsafe().pageSize();
0N/A return pageSize;
0N/A }
0N/A
0N/A private static volatile Constructor directByteBufferConstructor = null;
0N/A
0N/A private static void initDBBConstructor() {
28N/A AccessController.doPrivileged(new PrivilegedAction<Void>() {
28N/A public Void run() {
0N/A try {
28N/A Class<?> cl = Class.forName("java.nio.DirectByteBuffer");
0N/A Constructor ctor = cl.getDeclaredConstructor(
0N/A new Class[] { int.class,
0N/A long.class,
2984N/A FileDescriptor.class,
0N/A Runnable.class });
0N/A ctor.setAccessible(true);
0N/A directByteBufferConstructor = ctor;
0N/A } catch (ClassNotFoundException x) {
0N/A throw new InternalError();
0N/A } catch (NoSuchMethodException x) {
0N/A throw new InternalError();
0N/A } catch (IllegalArgumentException x) {
0N/A throw new InternalError();
0N/A } catch (ClassCastException x) {
0N/A throw new InternalError();
0N/A }
0N/A return null;
0N/A }});
0N/A }
0N/A
0N/A static MappedByteBuffer newMappedByteBuffer(int size, long addr,
2984N/A FileDescriptor fd,
0N/A Runnable unmapper)
0N/A {
0N/A MappedByteBuffer dbb;
0N/A if (directByteBufferConstructor == null)
0N/A initDBBConstructor();
0N/A try {
0N/A dbb = (MappedByteBuffer)directByteBufferConstructor.newInstance(
0N/A new Object[] { new Integer(size),
0N/A new Long(addr),
2984N/A fd,
0N/A unmapper });
0N/A } catch (InstantiationException e) {
0N/A throw new InternalError();
0N/A } catch (IllegalAccessException e) {
0N/A throw new InternalError();
0N/A } catch (InvocationTargetException e) {
0N/A throw new InternalError();
0N/A }
0N/A return dbb;
0N/A }
0N/A
0N/A private static volatile Constructor directByteBufferRConstructor = null;
0N/A
0N/A private static void initDBBRConstructor() {
28N/A AccessController.doPrivileged(new PrivilegedAction<Void>() {
28N/A public Void run() {
0N/A try {
28N/A Class<?> cl = Class.forName("java.nio.DirectByteBufferR");
0N/A Constructor ctor = cl.getDeclaredConstructor(
0N/A new Class[] { int.class,
0N/A long.class,
2984N/A FileDescriptor.class,
0N/A Runnable.class });
0N/A ctor.setAccessible(true);
0N/A directByteBufferRConstructor = ctor;
0N/A } catch (ClassNotFoundException x) {
0N/A throw new InternalError();
0N/A } catch (NoSuchMethodException x) {
0N/A throw new InternalError();
0N/A } catch (IllegalArgumentException x) {
0N/A throw new InternalError();
0N/A } catch (ClassCastException x) {
0N/A throw new InternalError();
0N/A }
0N/A return null;
0N/A }});
0N/A }
0N/A
0N/A static MappedByteBuffer newMappedByteBufferR(int size, long addr,
2984N/A FileDescriptor fd,
0N/A Runnable unmapper)
0N/A {
0N/A MappedByteBuffer dbb;
0N/A if (directByteBufferRConstructor == null)
0N/A initDBBRConstructor();
0N/A try {
0N/A dbb = (MappedByteBuffer)directByteBufferRConstructor.newInstance(
0N/A new Object[] { new Integer(size),
0N/A new Long(addr),
2984N/A fd,
0N/A unmapper });
0N/A } catch (InstantiationException e) {
0N/A throw new InternalError();
0N/A } catch (IllegalAccessException e) {
0N/A throw new InternalError();
0N/A } catch (InvocationTargetException e) {
0N/A throw new InternalError();
0N/A }
0N/A return dbb;
0N/A }
0N/A
0N/A
0N/A // -- Bug compatibility --
0N/A
0N/A private static volatile String bugLevel = null;
0N/A
0N/A static boolean atBugLevel(String bl) { // package-private
0N/A if (bugLevel == null) {
0N/A if (!sun.misc.VM.isBooted())
0N/A return false;
0N/A String value = AccessController.doPrivileged(
0N/A new GetPropertyAction("sun.nio.ch.bugLevel"));
0N/A bugLevel = (value != null) ? value : "";
0N/A }
0N/A return bugLevel.equals(bl);
0N/A }
0N/A
0N/A
0N/A
0N/A // -- Initialization --
0N/A
0N/A private static boolean loaded = false;
0N/A
0N/A static void load() {
0N/A synchronized (Util.class) {
0N/A if (loaded)
0N/A return;
0N/A loaded = true;
0N/A java.security.AccessController
0N/A .doPrivileged(new sun.security.action.LoadLibraryAction("net"));
0N/A java.security.AccessController
0N/A .doPrivileged(new sun.security.action.LoadLibraryAction("nio"));
0N/A // IOUtil must be initialized; Its native methods are called from
0N/A // other places in native nio code so they must be set up.
0N/A IOUtil.initIDs();
0N/A }
0N/A }
0N/A
0N/A}