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