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 { 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 */ allocNativeBuffer(int size)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 */ getNativeBufferFromCache(int size)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 */ getNativeBuffer(int size)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 */ releaseNativeBuffer(NativeBuffer buffer)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 */ copyCStringToNativeBuffer(byte[] cstr, NativeBuffer buffer)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 131 /** 132 * Copies a byte array and zero terminator into a native buffer, returning 133 * the buffer. 134 */ asNativeBuffer(byte[] cstr)135 static NativeBuffer asNativeBuffer(byte[] cstr) { 136 NativeBuffer buffer = getNativeBuffer(cstr.length+1); 137 copyCStringToNativeBuffer(cstr, buffer); 138 return buffer; 139 } 140 } 141