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 next(int i)67 private int next(int i) { 68 return (i + 1) % TEMP_BUF_POOL_SIZE; 69 } 70 BufferCache()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 */ get(int size)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 offerFirst(ByteBuffer buf)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 offerLast(ByteBuffer buf)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 isEmpty()138 boolean isEmpty() { 139 return count == 0; 140 } 141 removeFirst()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 */ getTemporaryDirectBuffer(int size)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 */ releaseTemporaryDirectBuffer(ByteBuffer buf)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 */ offerFirstTemporaryDirectBuffer(ByteBuffer buf)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 */ offerLastTemporaryDirectBuffer(ByteBuffer buf)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 */ free(ByteBuffer buf)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 subsequence(ByteBuffer[] bs, int offset, int length)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 ungrowableSet(final Set<E> s)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