Home | History | Annotate | Download | only in fs
      1 /*
      2  * Copyright (c) 2008, 2009, 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.fs;
     27 
     28 import sun.misc.Unsafe;
     29 
     30 /**
     31  * Factory for native buffers.
     32  */
     33 
     34 class NativeBuffers {
     35     private NativeBuffers() { }
     36 
     37     private static final Unsafe unsafe = Unsafe.getUnsafe();
     38 
     39     private static final int TEMP_BUF_POOL_SIZE = 3;
     40     private static ThreadLocal<NativeBuffer[]> threadLocal =
     41         new ThreadLocal<NativeBuffer[]>();
     42 
     43     /**
     44      * Allocates a native buffer, of at least the given size, from the heap.
     45      */
     46     static NativeBuffer allocNativeBuffer(int size) {
     47         // Make a new one of at least 2k
     48         if (size < 2048) size = 2048;
     49         return new NativeBuffer(size);
     50     }
     51 
     52     /**
     53      * Returns a native buffer, of at least the given size, from the thread
     54      * local cache.
     55      */
     56     static NativeBuffer getNativeBufferFromCache(int size) {
     57         // return from cache if possible
     58         NativeBuffer[] buffers = threadLocal.get();
     59         if (buffers != null) {
     60             for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
     61                 NativeBuffer buffer = buffers[i];
     62                 if (buffer != null && buffer.size() >= size) {
     63                     buffers[i] = null;
     64                     return buffer;
     65                 }
     66             }
     67         }
     68         return null;
     69     }
     70 
     71     /**
     72      * Returns a native buffer, of at least the given size. The native buffer
     73      * is taken from the thread local cache if possible; otherwise it is
     74      * allocated from the heap.
     75      */
     76     static NativeBuffer getNativeBuffer(int size) {
     77         NativeBuffer buffer = getNativeBufferFromCache(size);
     78         if (buffer != null) {
     79             buffer.setOwner(null);
     80             return buffer;
     81         } else {
     82             return allocNativeBuffer(size);
     83         }
     84     }
     85 
     86     /**
     87      * Releases the given buffer. If there is space in the thread local cache
     88      * then the buffer goes into the cache; otherwise the memory is deallocated.
     89      */
     90     static void releaseNativeBuffer(NativeBuffer buffer) {
     91         // create cache if it doesn't exist
     92         NativeBuffer[] buffers = threadLocal.get();
     93         if (buffers == null) {
     94             buffers = new NativeBuffer[TEMP_BUF_POOL_SIZE];
     95             buffers[0] = buffer;
     96             threadLocal.set(buffers);
     97             return;
     98         }
     99         // Put it in an empty slot if such exists
    100         for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
    101             if (buffers[i] == null) {
    102                 buffers[i] = buffer;
    103                 return;
    104             }
    105         }
    106         // Otherwise replace a smaller one in the cache if such exists
    107         for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
    108             NativeBuffer existing = buffers[i];
    109             if (existing.size() < buffer.size()) {
    110                 existing.cleaner().clean();
    111                 buffers[i] = buffer;
    112                 return;
    113             }
    114         }
    115 
    116         // free it
    117         buffer.cleaner().clean();
    118     }
    119 
    120     /**
    121      * Copies a byte array and zero terminator into a given native buffer.
    122      */
    123     static void copyCStringToNativeBuffer(byte[] cstr, NativeBuffer buffer) {
    124         // long offset = Unsafe.ARRAY_BYTE_BASE_OFFSET;
    125         // long len = cstr.length;
    126         // assert buffer.size() >= (len + 1);
    127         // unsafe.copyMemory(cstr, offset, null, buffer.address(), len);
    128         // unsafe.putByte(buffer.address() + len, (byte)0);
    129 
    130         // Android-changed: We don't have Unsafe.copyMemory yet, so we use putByte.
    131         long len = cstr.length;
    132         assert buffer.size() >= (len + 1);
    133         for (int i = 0; i < len; ++i) {
    134             unsafe.putByte(buffer.address() + i, cstr[i]);
    135         }
    136         unsafe.putByte(buffer.address() + len, (byte)0);
    137     }
    138 
    139     /**
    140      * Copies a byte array and zero terminator into a native buffer, returning
    141      * the buffer.
    142      */
    143     static NativeBuffer asNativeBuffer(byte[] cstr) {
    144         NativeBuffer buffer = getNativeBuffer(cstr.length+1);
    145         copyCStringToNativeBuffer(cstr, buffer);
    146         return buffer;
    147     }
    148 }
    149