Home | History | Annotate | Download | only in ch
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 
     27 package sun.nio.ch;
     28 
     29 import java.lang.ref.SoftReference;
     30 import java.lang.reflect.*;
     31 import java.io.IOException;
     32 import java.io.FileDescriptor;
     33 import java.nio.ByteBuffer;
     34 import java.nio.MappedByteBuffer;
     35 import java.nio.channels.*;
     36 import java.security.AccessController;
     37 import java.security.PrivilegedAction;
     38 import java.util.*;
     39 import sun.misc.Unsafe;
     40 import sun.misc.Cleaner;
     41 import sun.security.action.GetPropertyAction;
     42 
     43 
     44 class Util {
     45 
     46     // -- Caches --
     47 
     48     // The number of temp buffers in our pool
     49     private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX;
     50 
     51     // Per-thread cache of temporary direct buffers
     52     private static ThreadLocal<BufferCache> bufferCache =
     53         new ThreadLocal<BufferCache>()
     54     {
     55         @Override
     56         protected BufferCache initialValue() {
     57             return new BufferCache();
     58         }
     59     };
     60 
     61     /**
     62      * A simple cache of direct buffers.
     63      */
     64     private static class BufferCache {
     65         // the array of buffers
     66         private ByteBuffer[] buffers;
     67 
     68         // the number of buffers in the cache
     69         private int count;
     70 
     71         // the index of the first valid buffer (undefined if count == 0)
     72         private int start;
     73 
     74         private int next(int i) {
     75             return (i + 1) % TEMP_BUF_POOL_SIZE;
     76         }
     77 
     78         BufferCache() {
     79             buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE];
     80         }
     81 
     82         /**
     83          * Removes and returns a buffer from the cache of at least the given
     84          * size (or null if no suitable buffer is found).
     85          */
     86         ByteBuffer get(int size) {
     87             if (count == 0)
     88                 return null;  // cache is empty
     89 
     90             ByteBuffer[] buffers = this.buffers;
     91 
     92             // search for suitable buffer (often the first buffer will do)
     93             ByteBuffer buf = buffers[start];
     94             if (buf.capacity() < size) {
     95                 buf = null;
     96                 int i = start;
     97                 while ((i = next(i)) != start) {
     98                     ByteBuffer bb = buffers[i];
     99                     if (bb == null)
    100                         break;
    101                     if (bb.capacity() >= size) {
    102                         buf = bb;
    103                         break;
    104                     }
    105                 }
    106                 if (buf == null)
    107                     return null;
    108                 // move first element to here to avoid re-packing
    109                 buffers[i] = buffers[start];
    110             }
    111 
    112             // remove first element
    113             buffers[start] = null;
    114             start = next(start);
    115             count--;
    116 
    117             // prepare the buffer and return it
    118             buf.rewind();
    119             buf.limit(size);
    120             return buf;
    121         }
    122 
    123         boolean offerFirst(ByteBuffer buf) {
    124             if (count >= TEMP_BUF_POOL_SIZE) {
    125                 return false;
    126             } else {
    127                 start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE;
    128                 buffers[start] = buf;
    129                 count++;
    130                 return true;
    131             }
    132         }
    133 
    134         boolean offerLast(ByteBuffer buf) {
    135             if (count >= TEMP_BUF_POOL_SIZE) {
    136                 return false;
    137             } else {
    138                 int next = (start + count) % TEMP_BUF_POOL_SIZE;
    139                 buffers[next] = buf;
    140                 count++;
    141                 return true;
    142             }
    143         }
    144 
    145         boolean isEmpty() {
    146             return count == 0;
    147         }
    148 
    149         ByteBuffer removeFirst() {
    150             assert count > 0;
    151             ByteBuffer buf = buffers[start];
    152             buffers[start] = null;
    153             start = next(start);
    154             count--;
    155             return buf;
    156         }
    157     }
    158 
    159     /**
    160      * Returns a temporary buffer of at least the given size
    161      */
    162     static ByteBuffer getTemporaryDirectBuffer(int size) {
    163         BufferCache cache = bufferCache.get();
    164         ByteBuffer buf = cache.get(size);
    165         if (buf != null) {
    166             return buf;
    167         } else {
    168             // No suitable buffer in the cache so we need to allocate a new
    169             // one. To avoid the cache growing then we remove the first
    170             // buffer from the cache and free it.
    171             if (!cache.isEmpty()) {
    172                 buf = cache.removeFirst();
    173                 free(buf);
    174             }
    175             return ByteBuffer.allocateDirect(size);
    176         }
    177     }
    178 
    179     /**
    180      * Releases a temporary buffer by returning to the cache or freeing it.
    181      */
    182     static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
    183         offerFirstTemporaryDirectBuffer(buf);
    184     }
    185 
    186     /**
    187      * Releases a temporary buffer by returning to the cache or freeing it. If
    188      * returning to the cache then insert it at the start so that it is
    189      * likely to be returned by a subsequent call to getTemporaryDirectBuffer.
    190      */
    191     static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) {
    192         assert buf != null;
    193         BufferCache cache = bufferCache.get();
    194         if (!cache.offerFirst(buf)) {
    195             // cache is full
    196             free(buf);
    197         }
    198     }
    199 
    200     /**
    201      * Releases a temporary buffer by returning to the cache or freeing it. If
    202      * returning to the cache then insert it at the end. This makes it
    203      * suitable for scatter/gather operations where the buffers are returned to
    204      * cache in same order that they were obtained.
    205      */
    206     static void offerLastTemporaryDirectBuffer(ByteBuffer buf) {
    207         assert buf != null;
    208         BufferCache cache = bufferCache.get();
    209         if (!cache.offerLast(buf)) {
    210             // cache is full
    211             free(buf);
    212         }
    213     }
    214 
    215     /**
    216      * Frees the memory for the given direct buffer
    217      */
    218     private static void free(ByteBuffer buf) {
    219         Cleaner cleaner = ((DirectBuffer)buf).cleaner();
    220         if (cleaner != null) {
    221             cleaner.clean();
    222         }
    223     }
    224 
    225     private static class SelectorWrapper {
    226         private Selector sel;
    227         private SelectorWrapper (Selector sel) {
    228             this.sel = sel;
    229             Cleaner.create(this, new Closer(sel));
    230         }
    231         private static class Closer implements Runnable {
    232             private Selector sel;
    233             private Closer (Selector sel) {
    234                 this.sel = sel;
    235             }
    236             public void run () {
    237                 try {
    238                     sel.close();
    239                 } catch (Throwable th) {
    240                     throw new Error(th);
    241                 }
    242             }
    243         }
    244         public Selector get() { return sel;}
    245     }
    246 
    247     // Per-thread cached selector
    248     private static ThreadLocal<SoftReference<SelectorWrapper>> localSelector
    249         = new ThreadLocal<SoftReference<SelectorWrapper>>();
    250     // Hold a reference to the selWrapper object to prevent it from
    251     // being cleaned when the temporary selector wrapped is on lease.
    252     private static ThreadLocal<SelectorWrapper> localSelectorWrapper
    253         = new ThreadLocal<SelectorWrapper>();
    254 
    255     // When finished, invoker must ensure that selector is empty
    256     // by cancelling any related keys and explicitly releasing
    257     // the selector by invoking releaseTemporarySelector()
    258     static Selector getTemporarySelector(SelectableChannel sc)
    259         throws IOException
    260     {
    261         SoftReference<SelectorWrapper> ref = localSelector.get();
    262         SelectorWrapper selWrapper = null;
    263         Selector sel = null;
    264         if (ref == null
    265             || ((selWrapper = ref.get()) == null)
    266             || ((sel = selWrapper.get()) == null)
    267             || (sel.provider() != sc.provider())) {
    268             sel = sc.provider().openSelector();
    269             selWrapper = new SelectorWrapper(sel);
    270             localSelector.set(new SoftReference<SelectorWrapper>(selWrapper));
    271         }
    272         localSelectorWrapper.set(selWrapper);
    273         return sel;
    274     }
    275 
    276     static void releaseTemporarySelector(Selector sel)
    277         throws IOException
    278     {
    279         // Selector should be empty
    280         sel.selectNow();                // Flush cancelled keys
    281         assert sel.keys().isEmpty() : "Temporary selector not empty";
    282         localSelectorWrapper.set(null);
    283     }
    284 
    285 
    286     // -- Random stuff --
    287 
    288     static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) {
    289         if ((offset == 0) && (length == bs.length))
    290             return bs;
    291         int n = length;
    292         ByteBuffer[] bs2 = new ByteBuffer[n];
    293         for (int i = 0; i < n; i++)
    294             bs2[i] = bs[offset + i];
    295         return bs2;
    296     }
    297 
    298     static <E> Set<E> ungrowableSet(final Set<E> s) {
    299         return new Set<E>() {
    300 
    301                 public int size()                 { return s.size(); }
    302                 public boolean isEmpty()          { return s.isEmpty(); }
    303                 public boolean contains(Object o) { return s.contains(o); }
    304                 public Object[] toArray()         { return s.toArray(); }
    305                 public <T> T[] toArray(T[] a)     { return s.toArray(a); }
    306                 public String toString()          { return s.toString(); }
    307                 public Iterator<E> iterator()     { return s.iterator(); }
    308                 public boolean equals(Object o)   { return s.equals(o); }
    309                 public int hashCode()             { return s.hashCode(); }
    310                 public void clear()               { s.clear(); }
    311                 public boolean remove(Object o)   { return s.remove(o); }
    312 
    313                 public boolean containsAll(Collection<?> coll) {
    314                     return s.containsAll(coll);
    315                 }
    316                 public boolean removeAll(Collection<?> coll) {
    317                     return s.removeAll(coll);
    318                 }
    319                 public boolean retainAll(Collection<?> coll) {
    320                     return s.retainAll(coll);
    321                 }
    322 
    323                 public boolean add(E o){
    324                     throw new UnsupportedOperationException();
    325                 }
    326                 public boolean addAll(Collection<? extends E> coll) {
    327                     throw new UnsupportedOperationException();
    328                 }
    329 
    330         };
    331     }
    332 
    333 
    334     // -- Unsafe access --
    335 
    336     private static Unsafe unsafe = Unsafe.getUnsafe();
    337 
    338     private static byte _get(long a) {
    339         return unsafe.getByte(a);
    340     }
    341 
    342     private static void _put(long a, byte b) {
    343         unsafe.putByte(a, b);
    344     }
    345 
    346     static void erase(ByteBuffer bb) {
    347         unsafe.setMemory(((DirectBuffer) bb).address(), bb.capacity(), (byte) 0);
    348     }
    349 
    350     static Unsafe unsafe() {
    351         return unsafe;
    352     }
    353 
    354     private static int pageSize = -1;
    355 
    356     static int pageSize() {
    357         if (pageSize == -1)
    358             pageSize = unsafe().pageSize();
    359         return pageSize;
    360     }
    361 
    362     // -- Bug compatibility --
    363     private static volatile String bugLevel = null;
    364 
    365     static boolean atBugLevel(String bl) {              // package-private
    366         if (bugLevel == null) {
    367             if (!sun.misc.VM.isBooted())
    368                 return false;
    369             String value = AccessController.doPrivileged(
    370                 new GetPropertyAction("sun.nio.ch.bugLevel"));
    371             bugLevel = (value != null) ? value : "";
    372         }
    373         return bugLevel.equals(bl);
    374     }
    375 }
    376