< prev index next >

src/java.base/share/classes/sun/nio/ch/Util.java

Print this page

 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.io.FileDescriptor;
 29 import java.io.IOException;
 30 import java.lang.reflect.Constructor;
 31 import java.lang.reflect.InvocationTargetException;
 32 import java.nio.ByteBuffer;
 33 import java.nio.MappedByteBuffer;
 34 import java.security.AccessController;
 35 import java.security.PrivilegedAction;
 36 import java.util.Collection;
 37 import java.util.Iterator;
 38 import java.util.Set;
 39 


 40 import jdk.internal.access.foreign.MemorySegmentProxy;
 41 import jdk.internal.misc.TerminatingThreadLocal;
 42 import jdk.internal.misc.Unsafe;
 43 import sun.security.action.GetPropertyAction;
 44 
 45 public class Util {

 46 
 47     // -- Caches --
 48 
 49     // The number of temp buffers in our pool
 50     private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX;
 51 
 52     // The max size allowed for a cached temp buffer, in bytes
 53     private static final long MAX_CACHED_BUFFER_SIZE = getMaxCachedBufferSize();
 54 
 55     // Per-thread cache of temporary direct buffers
 56     private static ThreadLocal<BufferCache> bufferCache = new TerminatingThreadLocal<>() {
 57         @Override
 58         protected BufferCache initialValue() {
 59             return new BufferCache();
 60         }
 61         @Override
 62         protected void threadTerminated(BufferCache cache) { // will never be null
 63             while (!cache.isEmpty()) {
 64                 ByteBuffer bb = cache.removeFirst();
 65                 free(bb);
 66             }
 67         }
 68     };
 69 
 70     /**
 71      * Returns the max size allowed for a cached temp buffers, in
 72      * bytes. It defaults to Long.MAX_VALUE. It can be set with the
 73      * jdk.nio.maxCachedBufferSize property. Even though
 74      * ByteBuffer.capacity() returns an int, we're using a long here
 75      * for potential future-proofing.
 76      */
 77     private static long getMaxCachedBufferSize() {
 78         String s = GetPropertyAction
 79                 .privilegedGetProperty("jdk.nio.maxCachedBufferSize");
 80         if (s != null) {
 81             try {
 82                 long m = Long.parseLong(s);
 83                 if (m >= 0) {
 84                     return m;
 85                 } else {
 86                     // if it's negative, ignore the system property
 87                 }
 88             } catch (NumberFormatException e) {
 89                 // if the string is not well formed, ignore the system property
 90             }
 91         }
 92         return Long.MAX_VALUE;
 93     }
 94 
 95     /**
 96      * Returns true if a buffer of this size is too large to be
 97      * added to the buffer cache, false otherwise.
 98      */
 99     private static boolean isBufferTooLarge(int size) {

211             buffers[start] = null;
212             start = next(start);
213             count--;
214             return buf;
215         }
216     }
217 
218     /**
219      * Returns a temporary buffer of at least the given size
220      */
221     public static ByteBuffer getTemporaryDirectBuffer(int size) {
222         // If a buffer of this size is too large for the cache, there
223         // should not be a buffer in the cache that is at least as
224         // large. So we'll just create a new one. Also, we don't have
225         // to remove the buffer from the cache (as this method does
226         // below) given that we won't put the new buffer in the cache.
227         if (isBufferTooLarge(size)) {
228             return ByteBuffer.allocateDirect(size);
229         }
230 
231         BufferCache cache = bufferCache.get();
232         ByteBuffer buf = cache.get(size);
233         if (buf != null) {
234             return buf;
235         } else {
236             // No suitable buffer in the cache so we need to allocate a new
237             // one. To avoid the cache growing then we remove the first
238             // buffer from the cache and free it.
239             if (!cache.isEmpty()) {
240                 buf = cache.removeFirst();
241                 free(buf);
242             }
243             return ByteBuffer.allocateDirect(size);
244         }
245     }
246 
247     /**
248      * Returns a temporary buffer of at least the given size and
249      * aligned to the alignment
250      */
251     public static ByteBuffer getTemporaryAlignedDirectBuffer(int size,
252                                                              int alignment) {
253         if (isBufferTooLarge(size)) {
254             return ByteBuffer.allocateDirect(size + alignment - 1)
255                     .alignedSlice(alignment);
256         }
257 
258         BufferCache cache = bufferCache.get();
259         ByteBuffer buf = cache.get(size);
260         if (buf != null) {
261             if (buf.alignmentOffset(0, alignment) == 0) {
262                 return buf;
263             }
264         } else {
265             if (!cache.isEmpty()) {
266                 buf = cache.removeFirst();
267                 free(buf);
268             }
269         }
270         return ByteBuffer.allocateDirect(size + alignment - 1)
271                 .alignedSlice(alignment);
272     }
273 
274     /**
275      * Releases a temporary buffer by returning to the cache or freeing it.
276      */
277     public static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
278         offerFirstTemporaryDirectBuffer(buf);
279     }
280 
281     /**
282      * Releases a temporary buffer by returning to the cache or freeing it. If
283      * returning to the cache then insert it at the start so that it is
284      * likely to be returned by a subsequent call to getTemporaryDirectBuffer.
285      */
286     static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) {
287         // If the buffer is too large for the cache we don't have to
288         // check the cache. We'll just free it.
289         if (isBufferTooLarge(buf)) {
290             free(buf);
291             return;
292         }
293 
294         assert buf != null;
295         BufferCache cache = bufferCache.get();
296         if (!cache.offerFirst(buf)) {
297             // cache is full
298             free(buf);
299         }
300     }
301 
302     /**
303      * Releases a temporary buffer by returning to the cache or freeing it. If
304      * returning to the cache then insert it at the end. This makes it
305      * suitable for scatter/gather operations where the buffers are returned to
306      * cache in same order that they were obtained.
307      */
308     static void offerLastTemporaryDirectBuffer(ByteBuffer buf) {
309         // If the buffer is too large for the cache we don't have to
310         // check the cache. We'll just free it.
311         if (isBufferTooLarge(buf)) {
312             free(buf);
313             return;
314         }
315 
316         assert buf != null;
317         BufferCache cache = bufferCache.get();
318         if (!cache.offerLast(buf)) {
319             // cache is full
320             free(buf);
321         }
322     }
323 
324     /**
325      * Frees the memory for the given direct buffer
326      */
327     private static void free(ByteBuffer buf) {
328         ((DirectBuffer)buf).cleaner().clean();
329     }
330 
331 
332     // -- Random stuff --
333 
334     static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) {
335         if ((offset == 0) && (length == bs.length))
336             return bs;
337         int n = length;

 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.io.FileDescriptor;
 29 import java.io.IOException;
 30 import java.lang.reflect.Constructor;
 31 import java.lang.reflect.InvocationTargetException;
 32 import java.nio.ByteBuffer;
 33 import java.nio.MappedByteBuffer;
 34 import java.security.AccessController;
 35 import java.security.PrivilegedAction;
 36 import java.util.Collection;
 37 import java.util.Iterator;
 38 import java.util.Set;
 39 
 40 import jdk.internal.access.JavaLangAccess;
 41 import jdk.internal.access.SharedSecrets;
 42 import jdk.internal.access.foreign.MemorySegmentProxy;
 43 import jdk.internal.misc.TerminatingThreadLocal;
 44 import jdk.internal.misc.Unsafe;
 45 import sun.security.action.GetPropertyAction;
 46 
 47 public class Util {
 48     private static JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 49 
 50     // -- Caches --
 51 
 52     // The number of temp buffers in our pool
 53     private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX;
 54 
 55     // The max size allowed for a cached temp buffer, in bytes
 56     private static final long MAX_CACHED_BUFFER_SIZE = getMaxCachedBufferSize();
 57 
 58     // Per-thread cache of temporary direct buffers
 59     private static ThreadLocal<BufferCache> bufferCache = new TerminatingThreadLocal<>() {
 60         @Override
 61         protected BufferCache initialValue() {
 62             return new BufferCache();
 63         }
 64         @Override
 65         protected void threadTerminated(BufferCache cache) { // will never be null
 66             while (!cache.isEmpty()) {
 67                 ByteBuffer bb = cache.removeFirst();
 68                 free(bb);
 69             }
 70         }
 71     };
 72 
 73     /**
 74      * Returns the max size allowed for a cached temp buffers, in
 75      * bytes. It defaults to Long.MAX_VALUE. It can be set with the
 76      * jdk.nio.maxCachedBufferSize property. Even though
 77      * ByteBuffer.capacity() returns an int, we're using a long here
 78      * for potential future-proofing.
 79      */
 80     private static long getMaxCachedBufferSize() {
 81         String s = GetPropertyAction.privilegedGetProperty("jdk.nio.maxCachedBufferSize");

 82         if (s != null) {
 83             try {
 84                 long m = Long.parseLong(s);
 85                 if (m >= 0) {
 86                     return m;
 87                 } else {
 88                     // if it's negative, ignore the system property
 89                 }
 90             } catch (NumberFormatException e) {
 91                 // if the string is not well formed, ignore the system property
 92             }
 93         }
 94         return Long.MAX_VALUE;
 95     }
 96 
 97     /**
 98      * Returns true if a buffer of this size is too large to be
 99      * added to the buffer cache, false otherwise.
100      */
101     private static boolean isBufferTooLarge(int size) {

213             buffers[start] = null;
214             start = next(start);
215             count--;
216             return buf;
217         }
218     }
219 
220     /**
221      * Returns a temporary buffer of at least the given size
222      */
223     public static ByteBuffer getTemporaryDirectBuffer(int size) {
224         // If a buffer of this size is too large for the cache, there
225         // should not be a buffer in the cache that is at least as
226         // large. So we'll just create a new one. Also, we don't have
227         // to remove the buffer from the cache (as this method does
228         // below) given that we won't put the new buffer in the cache.
229         if (isBufferTooLarge(size)) {
230             return ByteBuffer.allocateDirect(size);
231         }
232 
233         BufferCache cache = JLA.getCarrierThreadLocal(bufferCache);
234         ByteBuffer buf = cache.get(size);
235         if (buf != null) {
236             return buf;
237         } else {
238             // No suitable buffer in the cache so we need to allocate a new
239             // one. To avoid the cache growing then we remove the first
240             // buffer from the cache and free it.
241             if (!cache.isEmpty()) {
242                 buf = cache.removeFirst();
243                 free(buf);
244             }
245             return ByteBuffer.allocateDirect(size);
246         }
247     }
248 
249     /**
250      * Returns a temporary buffer of at least the given size and
251      * aligned to the alignment
252      */
253     public static ByteBuffer getTemporaryAlignedDirectBuffer(int size,
254                                                              int alignment) {
255         if (isBufferTooLarge(size)) {
256             return ByteBuffer.allocateDirect(size + alignment - 1)
257                     .alignedSlice(alignment);
258         }
259 
260         BufferCache cache = JLA.getCarrierThreadLocal(bufferCache);
261         ByteBuffer buf = cache.get(size);
262         if (buf != null) {
263             if (buf.alignmentOffset(0, alignment) == 0) {
264                 return buf;
265             }
266         } else {
267             if (!cache.isEmpty()) {
268                 buf = cache.removeFirst();
269                 free(buf);
270             }
271         }
272         return ByteBuffer.allocateDirect(size + alignment - 1)
273                 .alignedSlice(alignment);
274     }
275 
276     /**
277      * Releases a temporary buffer by returning to the cache or freeing it.
278      */
279     public static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
280         offerFirstTemporaryDirectBuffer(buf);
281     }
282 
283     /**
284      * Releases a temporary buffer by returning to the cache or freeing it. If
285      * returning to the cache then insert it at the start so that it is
286      * likely to be returned by a subsequent call to getTemporaryDirectBuffer.
287      */
288     static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) {
289         // If the buffer is too large for the cache we don't have to
290         // check the cache. We'll just free it.
291         if (isBufferTooLarge(buf)) {
292             free(buf);
293             return;
294         }
295 
296         assert buf != null;
297         BufferCache cache = JLA.getCarrierThreadLocal(bufferCache);
298         if (!cache.offerFirst(buf)) {
299             // cache is full
300             free(buf);
301         }
302     }
303 
304     /**
305      * Releases a temporary buffer by returning to the cache or freeing it. If
306      * returning to the cache then insert it at the end. This makes it
307      * suitable for scatter/gather operations where the buffers are returned to
308      * cache in same order that they were obtained.
309      */
310     static void offerLastTemporaryDirectBuffer(ByteBuffer buf) {
311         // If the buffer is too large for the cache we don't have to
312         // check the cache. We'll just free it.
313         if (isBufferTooLarge(buf)) {
314             free(buf);
315             return;
316         }
317 
318         assert buf != null;
319         BufferCache cache = JLA.getCarrierThreadLocal(bufferCache);
320         if (!cache.offerLast(buf)) {
321             // cache is full
322             free(buf);
323         }
324     }
325 
326     /**
327      * Frees the memory for the given direct buffer
328      */
329     private static void free(ByteBuffer buf) {
330         ((DirectBuffer)buf).cleaner().clean();
331     }
332 
333 
334     // -- Random stuff --
335 
336     static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) {
337         if ((offset == 0) && (length == bs.length))
338             return bs;
339         int n = length;
< prev index next >