1 /* 2 * Copyright (c) 2000, 2013, 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.ch; 27 28 import java.lang.reflect.*; 29 import java.io.FileDescriptor; 30 import java.nio.ByteBuffer; 31 import java.nio.MappedByteBuffer; 32 import java.security.AccessController; 33 import java.security.PrivilegedAction; 34 import java.util.*; 35 import jdk.internal.misc.Unsafe; 36 import jdk.internal.ref.Cleaner; 37 import sun.security.action.GetPropertyAction; 38 39 40 public class Util { 41 42 // -- Caches -- 43 44 // The number of temp buffers in our pool 45 private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX; 46 47 // Per-thread cache of temporary direct buffers 48 private static ThreadLocal<BufferCache> bufferCache = 49 new ThreadLocal<BufferCache>() 50 { 51 @Override 52 protected BufferCache initialValue() { 53 return new BufferCache(); 54 } 55 }; 56 57 /** 58 * A simple cache of direct buffers. 59 */ 60 private static class BufferCache { 61 // the array of buffers 62 private ByteBuffer[] buffers; 63 64 // the number of buffers in the cache 65 private int count; 66 67 // the index of the first valid buffer (undefined if count == 0) 68 private int start; 69 70 private int next(int i) { 71 return (i + 1) % TEMP_BUF_POOL_SIZE; 72 } 73 74 BufferCache() { 75 buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE]; 76 } 77 78 /** 79 * Removes and returns a buffer from the cache of at least the given 80 * size (or null if no suitable buffer is found). 81 */ 82 ByteBuffer get(int size) { 83 if (count == 0) 84 return null; // cache is empty 85 86 ByteBuffer[] buffers = this.buffers; 87 88 // search for suitable buffer (often the first buffer will do) 89 ByteBuffer buf = buffers[start]; 90 if (buf.capacity() < size) { 91 buf = null; 92 int i = start; 93 while ((i = next(i)) != start) { 94 ByteBuffer bb = buffers[i]; 95 if (bb == null) 96 break; 97 if (bb.capacity() >= size) { 98 buf = bb; 99 break; 100 } 101 } 102 if (buf == null) 103 return null; 104 // move first element to here to avoid re-packing 105 buffers[i] = buffers[start]; 106 } 107 108 // remove first element 109 buffers[start] = null; 110 start = next(start); 111 count--; 112 113 // prepare the buffer and return it 114 buf.rewind(); 115 buf.limit(size); 116 return buf; 117 } 118 119 boolean offerFirst(ByteBuffer buf) { 120 if (count >= TEMP_BUF_POOL_SIZE) { 121 return false; 122 } else { 123 start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE; 124 buffers[start] = buf; 125 count++; 126 return true; 127 } 128 } 129 130 boolean offerLast(ByteBuffer buf) { 131 if (count >= TEMP_BUF_POOL_SIZE) { 132 return false; 133 } else { 134 int next = (start + count) % TEMP_BUF_POOL_SIZE; 135 buffers[next] = buf; 136 count++; 137 return true; 138 } 139 } 140 141 boolean isEmpty() { 142 return count == 0; 143 } 144 145 ByteBuffer removeFirst() { 146 assert count > 0; 147 ByteBuffer buf = buffers[start]; 148 buffers[start] = null; 149 start = next(start); 150 count--; 151 return buf; 152 } 153 } 154 155 /** 156 * Returns a temporary buffer of at least the given size 157 */ 158 public static ByteBuffer getTemporaryDirectBuffer(int size) { 159 BufferCache cache = bufferCache.get(); 160 ByteBuffer buf = cache.get(size); 161 if (buf != null) { 162 return buf; 163 } else { 164 // No suitable buffer in the cache so we need to allocate a new 165 // one. To avoid the cache growing then we remove the first 166 // buffer from the cache and free it. 167 if (!cache.isEmpty()) { 168 buf = cache.removeFirst(); 169 free(buf); 170 } 171 return ByteBuffer.allocateDirect(size); 172 } 173 } 174 175 /** 176 * Releases a temporary buffer by returning to the cache or freeing it. 177 */ 178 public static void releaseTemporaryDirectBuffer(ByteBuffer buf) { 179 offerFirstTemporaryDirectBuffer(buf); 180 } 181 182 /** 183 * Releases a temporary buffer by returning to the cache or freeing it. If 184 * returning to the cache then insert it at the start so that it is 185 * likely to be returned by a subsequent call to getTemporaryDirectBuffer. 186 */ 187 static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) { 188 assert buf != null; 189 BufferCache cache = bufferCache.get(); 190 if (!cache.offerFirst(buf)) { 191 // cache is full 192 free(buf); 193 } 194 } 195 196 /** 197 * Releases a temporary buffer by returning to the cache or freeing it. If 198 * returning to the cache then insert it at the end. This makes it 199 * suitable for scatter/gather operations where the buffers are returned to 200 * cache in same order that they were obtained. 201 */ 202 static void offerLastTemporaryDirectBuffer(ByteBuffer buf) { 203 assert buf != null; 204 BufferCache cache = bufferCache.get(); 205 if (!cache.offerLast(buf)) { 206 // cache is full 207 free(buf); 208 } 209 } 210 211 /** 212 * Frees the memory for the given direct buffer 213 */ 214 private static void free(ByteBuffer buf) { 215 ((DirectBuffer)buf).cleaner().clean(); 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 private static volatile Constructor<?> directByteBufferConstructor; 296 297 private static void initDBBConstructor() { 298 AccessController.doPrivileged(new PrivilegedAction<Void>() { 299 public Void run() { 300 try { 301 Class<?> cl = Class.forName("java.nio.DirectByteBuffer"); 302 Constructor<?> ctor = cl.getDeclaredConstructor( 303 new Class<?>[] { int.class, 304 long.class, 305 FileDescriptor.class, 306 Runnable.class }); 307 ctor.setAccessible(true); 308 directByteBufferConstructor = ctor; 309 } catch (ClassNotFoundException | 310 NoSuchMethodException | 311 IllegalArgumentException | 312 ClassCastException x) { 313 throw new InternalError(x); 314 } 315 return null; 316 }}); 317 } 318 319 static MappedByteBuffer newMappedByteBuffer(int size, long addr, 320 FileDescriptor fd, 321 Runnable unmapper) 322 { 323 MappedByteBuffer dbb; 324 if (directByteBufferConstructor == null) 325 initDBBConstructor(); 326 try { 327 dbb = (MappedByteBuffer)directByteBufferConstructor.newInstance( 328 new Object[] { size, 329 addr, 330 fd, 331 unmapper }); 332 } catch (InstantiationException | 333 IllegalAccessException | 334 InvocationTargetException e) { 335 throw new InternalError(e); 336 } 337 return dbb; 338 } 339 340 private static volatile Constructor<?> directByteBufferRConstructor; 341 342 private static void initDBBRConstructor() { 343 AccessController.doPrivileged(new PrivilegedAction<Void>() { 344 public Void run() { 345 try { 346 Class<?> cl = Class.forName("java.nio.DirectByteBufferR"); 347 Constructor<?> ctor = cl.getDeclaredConstructor( 348 new Class<?>[] { int.class, 349 long.class, 350 FileDescriptor.class, 351 Runnable.class }); 352 ctor.setAccessible(true); 353 directByteBufferRConstructor = ctor; 354 } catch (ClassNotFoundException | 355 NoSuchMethodException | 356 IllegalArgumentException | 357 ClassCastException x) { 358 throw new InternalError(x); 359 } 360 return null; 361 }}); 362 } 363 364 static MappedByteBuffer newMappedByteBufferR(int size, long addr, 365 FileDescriptor fd, 366 Runnable unmapper) 367 { 368 MappedByteBuffer dbb; 369 if (directByteBufferRConstructor == null) 370 initDBBRConstructor(); 371 try { 372 dbb = (MappedByteBuffer)directByteBufferRConstructor.newInstance( 373 new Object[] { size, 374 addr, 375 fd, 376 unmapper }); 377 } catch (InstantiationException | 378 IllegalAccessException | 379 InvocationTargetException e) { 380 throw new InternalError(e); 381 } 382 return dbb; 383 } 384 385 386 // -- Bug compatibility -- 387 388 private static volatile String bugLevel; 389 390 static boolean atBugLevel(String bl) { // package-private 391 if (bugLevel == null) { 392 if (!jdk.internal.misc.VM.isBooted()) 393 return false; 394 String value = AccessController.doPrivileged( 395 new GetPropertyAction("sun.nio.ch.bugLevel")); 396 bugLevel = (value != null) ? value : ""; 397 } 398 return bugLevel.equals(bl); 399 } 400 401 }