1 /* 2 * Copyright (c) 2000, 2016, 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 // The max size allowed for a cached temp buffer, in bytes 48 private static final long MAX_CACHED_BUFFER_SIZE = getMaxCachedBufferSize(); 49 50 // Per-thread cache of temporary direct buffers 51 private static ThreadLocal<BufferCache> bufferCache = 52 new ThreadLocal<BufferCache>() 53 { 54 @Override 55 protected BufferCache initialValue() { 56 return new BufferCache(); 57 } 58 }; 59 60 /** 61 * Returns the max size allowed for a cached temp buffers, in 62 * bytes. It defaults to Long.MAX_VALUE. It can be set with the 63 * jdk.nio.maxCachedBufferSize property. Even though 64 * ByteBuffer.capacity() returns an int, we're using a long here 65 * for potential future-proofing. 66 */ 67 private static long getMaxCachedBufferSize() { 68 String s = java.security.AccessController.doPrivileged( 69 new PrivilegedAction<String>() { 70 @Override 71 public String run() { 72 return System.getProperty("jdk.nio.maxCachedBufferSize"); 73 } 74 }); 75 if (s != null) { 76 try { 77 long m = Long.parseLong(s); 78 if (m >= 0) { 79 return m; 80 } else { 81 // if it's negative, ignore the system property 82 } 83 } catch (NumberFormatException e) { 84 // if the string is not well formed, ignore the system property 85 } 86 } 87 return Long.MAX_VALUE; 88 } 89 90 /** 91 * Returns true if a buffer of this size is too large to be 92 * added to the buffer cache, false otherwise. 93 */ 94 private static boolean isBufferTooLarge(int size) { 95 return size > MAX_CACHED_BUFFER_SIZE; 96 } 97 98 /** 99 * Returns true if the buffer is too large to be added to the 100 * buffer cache, false otherwise. 101 */ 102 private static boolean isBufferTooLarge(ByteBuffer buf) { 103 return isBufferTooLarge(buf.capacity()); 104 } 105 106 /** 107 * A simple cache of direct buffers. 108 */ 109 private static class BufferCache { 110 // the array of buffers 111 private ByteBuffer[] buffers; 112 113 // the number of buffers in the cache 114 private int count; 115 116 // the index of the first valid buffer (undefined if count == 0) 117 private int start; 118 119 private int next(int i) { 120 return (i + 1) % TEMP_BUF_POOL_SIZE; 121 } 122 123 BufferCache() { 124 buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE]; 125 } 126 127 /** 128 * Removes and returns a buffer from the cache of at least the given 129 * size (or null if no suitable buffer is found). 130 */ 131 ByteBuffer get(int size) { 132 // Don't call this if the buffer would be too large. 133 assert !isBufferTooLarge(size); 134 135 if (count == 0) 136 return null; // cache is empty 137 138 ByteBuffer[] buffers = this.buffers; 139 140 // search for suitable buffer (often the first buffer will do) 141 ByteBuffer buf = buffers[start]; 142 if (buf.capacity() < size) { 143 buf = null; 144 int i = start; 145 while ((i = next(i)) != start) { 146 ByteBuffer bb = buffers[i]; 147 if (bb == null) 148 break; 149 if (bb.capacity() >= size) { 150 buf = bb; 151 break; 152 } 153 } 154 if (buf == null) 155 return null; 156 // move first element to here to avoid re-packing 157 buffers[i] = buffers[start]; 158 } 159 160 // remove first element 161 buffers[start] = null; 162 start = next(start); 163 count--; 164 165 // prepare the buffer and return it 166 buf.rewind(); 167 buf.limit(size); 168 return buf; 169 } 170 171 boolean offerFirst(ByteBuffer buf) { 172 // Don't call this if the buffer is too large. 173 assert !isBufferTooLarge(buf); 174 175 if (count >= TEMP_BUF_POOL_SIZE) { 176 return false; 177 } else { 178 start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE; 179 buffers[start] = buf; 180 count++; 181 return true; 182 } 183 } 184 185 boolean offerLast(ByteBuffer buf) { 186 // Don't call this if the buffer is too large. 187 assert !isBufferTooLarge(buf); 188 189 if (count >= TEMP_BUF_POOL_SIZE) { 190 return false; 191 } else { 192 int next = (start + count) % TEMP_BUF_POOL_SIZE; 193 buffers[next] = buf; 194 count++; 195 return true; 196 } 197 } 198 199 boolean isEmpty() { 200 return count == 0; 201 } 202 203 ByteBuffer removeFirst() { 204 assert count > 0; 205 ByteBuffer buf = buffers[start]; 206 buffers[start] = null; 207 start = next(start); 208 count--; 209 return buf; 210 } 211 } 212 213 /** 214 * Returns a temporary buffer of at least the given size 215 */ 216 public static ByteBuffer getTemporaryDirectBuffer(int size) { 217 // If a buffer of this size is too large for the cache, there 218 // should not be a buffer in the cache that is at least as 219 // large. So we'll just create a new one. Also, we don't have 220 // to remove the buffer from the cache (as this method does 221 // below) given that we won't put the new buffer in the cache. 222 if (isBufferTooLarge(size)) { 223 return ByteBuffer.allocateDirect(size); 224 } 225 226 BufferCache cache = bufferCache.get(); 227 ByteBuffer buf = cache.get(size); 228 if (buf != null) { 229 return buf; 230 } else { 231 // No suitable buffer in the cache so we need to allocate a new 232 // one. To avoid the cache growing then we remove the first 233 // buffer from the cache and free it. 234 if (!cache.isEmpty()) { 235 buf = cache.removeFirst(); 236 free(buf); 237 } 238 return ByteBuffer.allocateDirect(size); 239 } 240 } 241 242 /** 243 * Releases a temporary buffer by returning to the cache or freeing it. 244 */ 245 public static void releaseTemporaryDirectBuffer(ByteBuffer buf) { 246 offerFirstTemporaryDirectBuffer(buf); 247 } 248 249 /** 250 * Releases a temporary buffer by returning to the cache or freeing it. If 251 * returning to the cache then insert it at the start so that it is 252 * likely to be returned by a subsequent call to getTemporaryDirectBuffer. 253 */ 254 static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) { 255 // If the buffer is too large for the cache we don't have to 256 // check the cache. We'll just free it. 257 if (isBufferTooLarge(buf)) { 258 free(buf); 259 return; 260 } 261 262 assert buf != null; 263 BufferCache cache = bufferCache.get(); 264 if (!cache.offerFirst(buf)) { 265 // cache is full 266 free(buf); 267 } 268 } 269 270 /** 271 * Releases a temporary buffer by returning to the cache or freeing it. If 272 * returning to the cache then insert it at the end. This makes it 273 * suitable for scatter/gather operations where the buffers are returned to 274 * cache in same order that they were obtained. 275 */ 276 static void offerLastTemporaryDirectBuffer(ByteBuffer buf) { 277 // If the buffer is too large for the cache we don't have to 278 // check the cache. We'll just free it. 279 if (isBufferTooLarge(buf)) { 280 free(buf); 281 return; 282 } 283 284 assert buf != null; 285 BufferCache cache = bufferCache.get(); 286 if (!cache.offerLast(buf)) { 287 // cache is full 288 free(buf); 289 } 290 } 291 292 /** 293 * Frees the memory for the given direct buffer 294 */ 295 private static void free(ByteBuffer buf) { 296 ((DirectBuffer)buf).cleaner().clean(); 297 } 298 299 300 // -- Random stuff -- 301 302 static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) { 303 if ((offset == 0) && (length == bs.length)) 304 return bs; 305 int n = length; 306 ByteBuffer[] bs2 = new ByteBuffer[n]; 307 for (int i = 0; i < n; i++) 308 bs2[i] = bs[offset + i]; 309 return bs2; 310 } 311 312 static <E> Set<E> ungrowableSet(final Set<E> s) { 313 return new Set<E>() { 314 315 public int size() { return s.size(); } 316 public boolean isEmpty() { return s.isEmpty(); } 317 public boolean contains(Object o) { return s.contains(o); } 318 public Object[] toArray() { return s.toArray(); } 319 public <T> T[] toArray(T[] a) { return s.toArray(a); } 320 public String toString() { return s.toString(); } 321 public Iterator<E> iterator() { return s.iterator(); } 322 public boolean equals(Object o) { return s.equals(o); } 323 public int hashCode() { return s.hashCode(); } 324 public void clear() { s.clear(); } 325 public boolean remove(Object o) { return s.remove(o); } 326 327 public boolean containsAll(Collection<?> coll) { 328 return s.containsAll(coll); 329 } 330 public boolean removeAll(Collection<?> coll) { 331 return s.removeAll(coll); 332 } 333 public boolean retainAll(Collection<?> coll) { 334 return s.retainAll(coll); 335 } 336 337 public boolean add(E o){ 338 throw new UnsupportedOperationException(); 339 } 340 public boolean addAll(Collection<? extends E> coll) { 341 throw new UnsupportedOperationException(); 342 } 343 344 }; 345 } 346 347 348 // -- Unsafe access -- 349 350 private static Unsafe unsafe = Unsafe.getUnsafe(); 351 352 private static byte _get(long a) { 353 return unsafe.getByte(a); 354 } 355 356 private static void _put(long a, byte b) { 357 unsafe.putByte(a, b); 358 } 359 360 static void erase(ByteBuffer bb) { 361 unsafe.setMemory(((DirectBuffer)bb).address(), bb.capacity(), (byte)0); 362 } 363 364 static Unsafe unsafe() { 365 return unsafe; 366 } 367 368 private static int pageSize = -1; 369 370 static int pageSize() { 371 if (pageSize == -1) 372 pageSize = unsafe().pageSize(); 373 return pageSize; 374 } 375 376 private static volatile Constructor<?> directByteBufferConstructor; 377 378 private static void initDBBConstructor() { 379 AccessController.doPrivileged(new PrivilegedAction<Void>() { 380 public Void run() { 381 try { 382 Class<?> cl = Class.forName("java.nio.DirectByteBuffer"); 383 Constructor<?> ctor = cl.getDeclaredConstructor( 384 new Class<?>[] { int.class, 385 long.class, 386 FileDescriptor.class, 387 Runnable.class }); 388 ctor.setAccessible(true); 389 directByteBufferConstructor = ctor; 390 } catch (ClassNotFoundException | 391 NoSuchMethodException | 392 IllegalArgumentException | 393 ClassCastException x) { 394 throw new InternalError(x); 395 } 396 return null; 397 }}); 398 } 399 400 static MappedByteBuffer newMappedByteBuffer(int size, long addr, 401 FileDescriptor fd, 402 Runnable unmapper) 403 { 404 MappedByteBuffer dbb; 405 if (directByteBufferConstructor == null) 406 initDBBConstructor(); 407 try { 408 dbb = (MappedByteBuffer)directByteBufferConstructor.newInstance( 409 new Object[] { size, 410 addr, 411 fd, 412 unmapper }); 413 } catch (InstantiationException | 414 IllegalAccessException | 415 InvocationTargetException e) { 416 throw new InternalError(e); 417 } 418 return dbb; 419 } 420 421 private static volatile Constructor<?> directByteBufferRConstructor; 422 423 private static void initDBBRConstructor() { 424 AccessController.doPrivileged(new PrivilegedAction<Void>() { 425 public Void run() { 426 try { 427 Class<?> cl = Class.forName("java.nio.DirectByteBufferR"); 428 Constructor<?> ctor = cl.getDeclaredConstructor( 429 new Class<?>[] { int.class, 430 long.class, 431 FileDescriptor.class, 432 Runnable.class }); 433 ctor.setAccessible(true); 434 directByteBufferRConstructor = ctor; 435 } catch (ClassNotFoundException | 436 NoSuchMethodException | 437 IllegalArgumentException | 438 ClassCastException x) { 439 throw new InternalError(x); 440 } 441 return null; 442 }}); 443 } 444 445 static MappedByteBuffer newMappedByteBufferR(int size, long addr, 446 FileDescriptor fd, 447 Runnable unmapper) 448 { 449 MappedByteBuffer dbb; 450 if (directByteBufferRConstructor == null) 451 initDBBRConstructor(); 452 try { 453 dbb = (MappedByteBuffer)directByteBufferRConstructor.newInstance( 454 new Object[] { size, 455 addr, 456 fd, 457 unmapper }); 458 } catch (InstantiationException | 459 IllegalAccessException | 460 InvocationTargetException e) { 461 throw new InternalError(e); 462 } 463 return dbb; 464 } 465 466 467 // -- Bug compatibility -- 468 469 private static volatile String bugLevel; 470 471 static boolean atBugLevel(String bl) { // package-private 472 if (bugLevel == null) { 473 if (!jdk.internal.misc.VM.isBooted()) 474 return false; 475 String value = AccessController.doPrivileged( 476 new GetPropertyAction("sun.nio.ch.bugLevel")); 477 bugLevel = (value != null) ? value : ""; 478 } 479 return bugLevel.equals(bl); 480 } 481 482 }