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.ref.SoftReference; 29 import java.lang.reflect.*; 30 import java.io.IOException; 31 import java.io.FileDescriptor; 32 import java.nio.ByteBuffer; 33 import java.nio.MappedByteBuffer; 34 import java.nio.channels.*; 35 import java.security.AccessController; 36 import java.security.PrivilegedAction; 37 import java.util.*; 38 import jdk.internal.misc.Unsafe; 39 import sun.misc.Cleaner; 40 import sun.security.action.GetPropertyAction; 41 42 43 public class Util { 44 45 // -- Caches -- 46 47 // The number of temp buffers in our pool 48 private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX; 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 * A simple cache of direct buffers. 62 */ 63 private static class BufferCache { 64 // the array of buffers 65 private ByteBuffer[] buffers; 66 67 // the number of buffers in the cache 68 private int count; 69 70 // the index of the first valid buffer (undefined if count == 0) 71 private int start; 72 73 private int next(int i) { 74 return (i + 1) % TEMP_BUF_POOL_SIZE; 75 } 76 77 BufferCache() { 78 buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE]; 79 } 80 81 /** 82 * Removes and returns a buffer from the cache of at least the given 83 * size (or null if no suitable buffer is found). 84 */ 85 ByteBuffer get(int size) { 86 if (count == 0) 87 return null; // cache is empty 88 89 ByteBuffer[] buffers = this.buffers; 90 91 // search for suitable buffer (often the first buffer will do) 92 ByteBuffer buf = buffers[start]; 93 if (buf.capacity() < size) { 94 buf = null; 95 int i = start; 96 while ((i = next(i)) != start) { 97 ByteBuffer bb = buffers[i]; 98 if (bb == null) 99 break; 100 if (bb.capacity() >= size) { 101 buf = bb; 102 break; 103 } 104 } 105 if (buf == null) 106 return null; 107 // move first element to here to avoid re-packing 108 buffers[i] = buffers[start]; 109 } 110 111 // remove first element 112 buffers[start] = null; 113 start = next(start); 114 count--; 115 116 // prepare the buffer and return it 117 buf.rewind(); 118 buf.limit(size); 119 return buf; 120 } 121 122 boolean offerFirst(ByteBuffer buf) { 123 if (count >= TEMP_BUF_POOL_SIZE) { 124 return false; 125 } else { 126 start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE; 127 buffers[start] = buf; 128 count++; 129 return true; 130 } 131 } 132 133 boolean offerLast(ByteBuffer buf) { 134 if (count >= TEMP_BUF_POOL_SIZE) { 135 return false; 136 } else { 137 int next = (start + count) % TEMP_BUF_POOL_SIZE; 138 buffers[next] = buf; 139 count++; 140 return true; 141 } 142 } 143 144 boolean isEmpty() { 145 return count == 0; 146 } 147 148 ByteBuffer removeFirst() { 149 assert count > 0; 150 ByteBuffer buf = buffers[start]; 151 buffers[start] = null; 152 start = next(start); 153 count--; 154 return buf; 155 } 156 } 157 158 /** 159 * Returns a temporary buffer of at least the given size 160 */ 161 public static ByteBuffer getTemporaryDirectBuffer(int size) { 162 BufferCache cache = bufferCache.get(); 163 ByteBuffer buf = cache.get(size); 164 if (buf != null) { 165 return buf; 166 } else { 167 // No suitable buffer in the cache so we need to allocate a new 168 // one. To avoid the cache growing then we remove the first 169 // buffer from the cache and free it. 170 if (!cache.isEmpty()) { 171 buf = cache.removeFirst(); 172 free(buf); 173 } 174 return ByteBuffer.allocateDirect(size); 175 } 176 } 177 178 /** 179 * Releases a temporary buffer by returning to the cache or freeing it. 180 */ 181 public static void releaseTemporaryDirectBuffer(ByteBuffer buf) { 182 offerFirstTemporaryDirectBuffer(buf); 183 } 184 185 /** 186 * Releases a temporary buffer by returning to the cache or freeing it. If 187 * returning to the cache then insert it at the start so that it is 188 * likely to be returned by a subsequent call to getTemporaryDirectBuffer. 189 */ 190 static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) { 191 assert buf != null; 192 BufferCache cache = bufferCache.get(); 193 if (!cache.offerFirst(buf)) { 194 // cache is full 195 free(buf); 196 } 197 } 198 199 /** 200 * Releases a temporary buffer by returning to the cache or freeing it. If 201 * returning to the cache then insert it at the end. This makes it 202 * suitable for scatter/gather operations where the buffers are returned to 203 * cache in same order that they were obtained. 204 */ 205 static void offerLastTemporaryDirectBuffer(ByteBuffer buf) { 206 assert buf != null; 207 BufferCache cache = bufferCache.get(); 208 if (!cache.offerLast(buf)) { 209 // cache is full 210 free(buf); 211 } 212 } 213 214 /** 215 * Frees the memory for the given direct buffer 216 */ 217 private static void free(ByteBuffer buf) { 218 ((DirectBuffer)buf).cleaner().clean(); 219 } 220 221 222 // -- Random stuff -- 223 224 static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) { 225 if ((offset == 0) && (length == bs.length)) 226 return bs; 227 int n = length; 228 ByteBuffer[] bs2 = new ByteBuffer[n]; 229 for (int i = 0; i < n; i++) 230 bs2[i] = bs[offset + i]; 231 return bs2; 232 } 233 234 static <E> Set<E> ungrowableSet(final Set<E> s) { 235 return new Set<E>() { 236 237 public int size() { return s.size(); } 238 public boolean isEmpty() { return s.isEmpty(); } 239 public boolean contains(Object o) { return s.contains(o); } 240 public Object[] toArray() { return s.toArray(); } 241 public <T> T[] toArray(T[] a) { return s.toArray(a); } 242 public String toString() { return s.toString(); } 243 public Iterator<E> iterator() { return s.iterator(); } 244 public boolean equals(Object o) { return s.equals(o); } 245 public int hashCode() { return s.hashCode(); } 246 public void clear() { s.clear(); } 247 public boolean remove(Object o) { return s.remove(o); } 248 249 public boolean containsAll(Collection<?> coll) { 250 return s.containsAll(coll); 251 } 252 public boolean removeAll(Collection<?> coll) { 253 return s.removeAll(coll); 254 } 255 public boolean retainAll(Collection<?> coll) { 256 return s.retainAll(coll); 257 } 258 259 public boolean add(E o){ 260 throw new UnsupportedOperationException(); 261 } 262 public boolean addAll(Collection<? extends E> coll) { 263 throw new UnsupportedOperationException(); 264 } 265 266 }; 267 } 268 269 270 // -- Unsafe access -- 271 272 private static Unsafe unsafe = Unsafe.getUnsafe(); 273 274 private static byte _get(long a) { 275 return unsafe.getByte(a); 276 } 277 278 private static void _put(long a, byte b) { 279 unsafe.putByte(a, b); 280 } 281 282 static void erase(ByteBuffer bb) { 283 unsafe.setMemory(((DirectBuffer)bb).address(), bb.capacity(), (byte)0); 284 } 285 286 static Unsafe unsafe() { 287 return unsafe; 288 } 289 290 private static int pageSize = -1; 291 292 static int pageSize() { 293 if (pageSize == -1) 294 pageSize = unsafe().pageSize(); 295 return pageSize; 296 } 297 298 private static volatile Constructor<?> directByteBufferConstructor = null; 299 300 private static void initDBBConstructor() { 301 AccessController.doPrivileged(new PrivilegedAction<Void>() { 302 public Void run() { 303 try { 304 Class<?> cl = Class.forName("java.nio.DirectByteBuffer"); 305 Constructor<?> ctor = cl.getDeclaredConstructor( 306 new Class<?>[] { int.class, 307 long.class, 308 FileDescriptor.class, 309 Runnable.class }); 310 ctor.setAccessible(true); 311 directByteBufferConstructor = ctor; 312 } catch (ClassNotFoundException | 313 NoSuchMethodException | 314 IllegalArgumentException | 315 ClassCastException x) { 316 throw new InternalError(x); 317 } 318 return null; 319 }}); 320 } 321 322 static MappedByteBuffer newMappedByteBuffer(int size, long addr, 323 FileDescriptor fd, 324 Runnable unmapper) 325 { 326 MappedByteBuffer dbb; 327 if (directByteBufferConstructor == null) 328 initDBBConstructor(); 329 try { 330 dbb = (MappedByteBuffer)directByteBufferConstructor.newInstance( 331 new Object[] { size, 332 addr, 333 fd, 334 unmapper }); 335 } catch (InstantiationException | 336 IllegalAccessException | 337 InvocationTargetException e) { 338 throw new InternalError(e); 339 } 340 return dbb; 341 } 342 343 private static volatile Constructor<?> directByteBufferRConstructor = null; 344 345 private static void initDBBRConstructor() { 346 AccessController.doPrivileged(new PrivilegedAction<Void>() { 347 public Void run() { 348 try { 349 Class<?> cl = Class.forName("java.nio.DirectByteBufferR"); 350 Constructor<?> ctor = cl.getDeclaredConstructor( 351 new Class<?>[] { int.class, 352 long.class, 353 FileDescriptor.class, 354 Runnable.class }); 355 ctor.setAccessible(true); 356 directByteBufferRConstructor = ctor; 357 } catch (ClassNotFoundException | 358 NoSuchMethodException | 359 IllegalArgumentException | 360 ClassCastException x) { 361 throw new InternalError(x); 362 } 363 return null; 364 }}); 365 } 366 367 static MappedByteBuffer newMappedByteBufferR(int size, long addr, 368 FileDescriptor fd, 369 Runnable unmapper) 370 { 371 MappedByteBuffer dbb; 372 if (directByteBufferRConstructor == null) 373 initDBBRConstructor(); 374 try { 375 dbb = (MappedByteBuffer)directByteBufferRConstructor.newInstance( 376 new Object[] { size, 377 addr, 378 fd, 379 unmapper }); 380 } catch (InstantiationException | 381 IllegalAccessException | 382 InvocationTargetException e) { 383 throw new InternalError(e); 384 } 385 return dbb; 386 } 387 388 389 // -- Bug compatibility -- 390 391 private static volatile String bugLevel = null; 392 393 static boolean atBugLevel(String bl) { // package-private 394 if (bugLevel == null) { 395 if (!sun.misc.VM.isBooted()) 396 return false; 397 String value = AccessController.doPrivileged( 398 new GetPropertyAction("sun.nio.ch.bugLevel")); 399 bugLevel = (value != null) ? value : ""; 400 } 401 return bugLevel.equals(bl); 402 } 403 404 }