Home | History | Annotate | Download | only in ch
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 2000, 2013, 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.nio.ByteBuffer;
     30 import java.security.AccessController;
     31 import java.util.*;
     32 import sun.misc.Unsafe;
     33 import sun.misc.Cleaner;
     34 import sun.security.action.GetPropertyAction;
     35 
     36 
     37 public class Util {
     38 
     39     // -- Caches --
     40 
     41     // The number of temp buffers in our pool
     42     private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX;
     43 
     44     // Per-thread cache of temporary direct buffers
     45     private static ThreadLocal<BufferCache> bufferCache =
     46         new ThreadLocal<BufferCache>()
     47     {
     48         @Override
     49         protected BufferCache initialValue() {
     50             return new BufferCache();
     51         }
     52     };
     53 
     54     /**
     55      * A simple cache of direct buffers.
     56      */
     57     private static class BufferCache {
     58         // the array of buffers
     59         private ByteBuffer[] buffers;
     60 
     61         // the number of buffers in the cache
     62         private int count;
     63 
     64         // the index of the first valid buffer (undefined if count == 0)
     65         private int start;
     66 
     67         private int next(int i) {
     68             return (i + 1) % TEMP_BUF_POOL_SIZE;
     69         }
     70 
     71         BufferCache() {
     72             buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE];
     73         }
     74 
     75         /**
     76          * Removes and returns a buffer from the cache of at least the given
     77          * size (or null if no suitable buffer is found).
     78          */
     79         ByteBuffer get(int size) {
     80             if (count == 0)
     81                 return null;  // cache is empty
     82 
     83             ByteBuffer[] buffers = this.buffers;
     84 
     85             // search for suitable buffer (often the first buffer will do)
     86             ByteBuffer buf = buffers[start];
     87             if (buf.capacity() < size) {
     88                 buf = null;
     89                 int i = start;
     90                 while ((i = next(i)) != start) {
     91                     ByteBuffer bb = buffers[i];
     92                     if (bb == null)
     93                         break;
     94                     if (bb.capacity() >= size) {
     95                         buf = bb;
     96                         break;
     97                     }
     98                 }
     99                 if (buf == null)
    100                     return null;
    101                 // move first element to here to avoid re-packing
    102                 buffers[i] = buffers[start];
    103             }
    104 
    105             // remove first element
    106             buffers[start] = null;
    107             start = next(start);
    108             count--;
    109 
    110             // prepare the buffer and return it
    111             buf.rewind();
    112             buf.limit(size);
    113             return buf;
    114         }
    115 
    116         boolean offerFirst(ByteBuffer buf) {
    117             if (count >= TEMP_BUF_POOL_SIZE) {
    118                 return false;
    119             } else {
    120                 start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE;
    121                 buffers[start] = buf;
    122                 count++;
    123                 return true;
    124             }
    125         }
    126 
    127         boolean offerLast(ByteBuffer buf) {
    128             if (count >= TEMP_BUF_POOL_SIZE) {
    129                 return false;
    130             } else {
    131                 int next = (start + count) % TEMP_BUF_POOL_SIZE;
    132                 buffers[next] = buf;
    133                 count++;
    134                 return true;
    135             }
    136         }
    137 
    138         boolean isEmpty() {
    139             return count == 0;
    140         }
    141 
    142         ByteBuffer removeFirst() {
    143             assert count > 0;
    144             ByteBuffer buf = buffers[start];
    145             buffers[start] = null;
    146             start = next(start);
    147             count--;
    148             return buf;
    149         }
    150     }
    151 
    152     /**
    153      * Returns a temporary buffer of at least the given size
    154      */
    155     public static ByteBuffer getTemporaryDirectBuffer(int size) {
    156         BufferCache cache = bufferCache.get();
    157         ByteBuffer buf = cache.get(size);
    158         if (buf != null) {
    159             return buf;
    160         } else {
    161             // No suitable buffer in the cache so we need to allocate a new
    162             // one. To avoid the cache growing then we remove the first
    163             // buffer from the cache and free it.
    164             if (!cache.isEmpty()) {
    165                 buf = cache.removeFirst();
    166                 free(buf);
    167             }
    168             return ByteBuffer.allocateDirect(size);
    169         }
    170     }
    171 
    172     /**
    173      * Releases a temporary buffer by returning to the cache or freeing it.
    174      */
    175     public static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
    176         offerFirstTemporaryDirectBuffer(buf);
    177     }
    178 
    179     /**
    180      * Releases a temporary buffer by returning to the cache or freeing it. If
    181      * returning to the cache then insert it at the start so that it is
    182      * likely to be returned by a subsequent call to getTemporaryDirectBuffer.
    183      */
    184     static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) {
    185         assert buf != null;
    186         BufferCache cache = bufferCache.get();
    187         if (!cache.offerFirst(buf)) {
    188             // cache is full
    189             free(buf);
    190         }
    191     }
    192 
    193     /**
    194      * Releases a temporary buffer by returning to the cache or freeing it. If
    195      * returning to the cache then insert it at the end. This makes it
    196      * suitable for scatter/gather operations where the buffers are returned to
    197      * cache in same order that they were obtained.
    198      */
    199     static void offerLastTemporaryDirectBuffer(ByteBuffer buf) {
    200         assert buf != null;
    201         BufferCache cache = bufferCache.get();
    202         if (!cache.offerLast(buf)) {
    203             // cache is full
    204             free(buf);
    205         }
    206     }
    207 
    208     /**
    209      * Frees the memory for the given direct buffer
    210      */
    211     private static void free(ByteBuffer buf) {
    212         Cleaner cleaner = ((DirectBuffer)buf).cleaner();
    213         if (cleaner != null) {
    214             cleaner.clean();
    215         }
    216     }
    217 
    218 
    219     // -- Random stuff --
    220 
    221     static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) {
    222         if ((offset == 0) && (length == bs.length))
    223             return bs;
    224         int n = length;
    225         ByteBuffer[] bs2 = new ByteBuffer[n];
    226         for (int i = 0; i < n; i++)
    227             bs2[i] = bs[offset + i];
    228         return bs2;
    229     }
    230 
    231     static <E> Set<E> ungrowableSet(final Set<E> s) {
    232         return new Set<E>() {
    233 
    234                 public int size()                 { return s.size(); }
    235                 public boolean isEmpty()          { return s.isEmpty(); }
    236                 public boolean contains(Object o) { return s.contains(o); }
    237                 public Object[] toArray()         { return s.toArray(); }
    238                 public <T> T[] toArray(T[] a)     { return s.toArray(a); }
    239                 public String toString()          { return s.toString(); }
    240                 public Iterator<E> iterator()     { return s.iterator(); }
    241                 public boolean equals(Object o)   { return s.equals(o); }
    242                 public int hashCode()             { return s.hashCode(); }
    243                 public void clear()               { s.clear(); }
    244                 public boolean remove(Object o)   { return s.remove(o); }
    245 
    246                 public boolean containsAll(Collection<?> coll) {
    247                     return s.containsAll(coll);
    248                 }
    249                 public boolean removeAll(Collection<?> coll) {
    250                     return s.removeAll(coll);
    251                 }
    252                 public boolean retainAll(Collection<?> coll) {
    253                     return s.retainAll(coll);
    254                 }
    255 
    256                 public boolean add(E o){
    257                     throw new UnsupportedOperationException();
    258                 }
    259                 public boolean addAll(Collection<? extends E> coll) {
    260                     throw new UnsupportedOperationException();
    261                 }
    262 
    263         };
    264     }
    265 
    266 
    267     // -- Unsafe access --
    268 
    269     private static Unsafe unsafe = Unsafe.getUnsafe();
    270 
    271     private static byte _get(long a) {
    272         return unsafe.getByte(a);
    273     }
    274 
    275     private static void _put(long a, byte b) {
    276         unsafe.putByte(a, b);
    277     }
    278 
    279     static void erase(ByteBuffer bb) {
    280         unsafe.setMemory(((DirectBuffer)bb).address(), bb.capacity(), (byte)0);
    281     }
    282 
    283     static Unsafe unsafe() {
    284         return unsafe;
    285     }
    286 
    287     private static int pageSize = -1;
    288 
    289     static int pageSize() {
    290         if (pageSize == -1)
    291             pageSize = unsafe().pageSize();
    292         return pageSize;
    293     }
    294 
    295     // -- Bug compatibility --
    296     private static volatile String bugLevel = null;
    297 
    298     static boolean atBugLevel(String bl) {              // package-private
    299         if (bugLevel == null) {
    300             if (!sun.misc.VM.isBooted())
    301                 return false;
    302             String value = AccessController.doPrivileged(
    303                 new GetPropertyAction("sun.nio.ch.bugLevel"));
    304             bugLevel = (value != null) ? value : "";
    305         }
    306         return bugLevel.equals(bl);
    307     }
    308 
    309 }
    310