View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.util.internal;
17  
18  import io.netty.util.internal.logging.InternalLogger;
19  import io.netty.util.internal.logging.InternalLoggerFactory;
20  import org.jctools.queues.MpscArrayQueue;
21  import org.jctools.queues.MpscChunkedArrayQueue;
22  import org.jctools.queues.MpscUnboundedArrayQueue;
23  import org.jctools.queues.SpscLinkedQueue;
24  import org.jctools.queues.atomic.MpscAtomicArrayQueue;
25  import org.jctools.queues.atomic.MpscGrowableAtomicArrayQueue;
26  import org.jctools.queues.atomic.MpscUnboundedAtomicArrayQueue;
27  import org.jctools.queues.atomic.SpscLinkedAtomicQueue;
28  import org.jctools.util.Pow2;
29  import org.jctools.util.UnsafeAccess;
30  
31  import java.io.File;
32  import java.lang.reflect.Method;
33  import java.nio.ByteBuffer;
34  import java.nio.ByteOrder;
35  import java.security.AccessController;
36  import java.security.PrivilegedAction;
37  import java.util.Deque;
38  import java.util.List;
39  import java.util.Locale;
40  import java.util.Map;
41  import java.util.Queue;
42  import java.util.Random;
43  import java.util.concurrent.ConcurrentHashMap;
44  import java.util.concurrent.ConcurrentLinkedDeque;
45  import java.util.concurrent.ConcurrentMap;
46  import java.util.concurrent.LinkedBlockingDeque;
47  import java.util.concurrent.atomic.AtomicLong;
48  import java.util.regex.Matcher;
49  import java.util.regex.Pattern;
50  
51  import static java.lang.Math.max;
52  import static java.lang.Math.min;
53  
54  /**
55   * Utility that detects various properties specific to the current runtime
56   * environment, such as Java version and the availability of the
57   * {@code sun.misc.Unsafe} object.
58   * <p>
59   * You can disable the use of {@code sun.misc.Unsafe} if you specify
60   * the system property <strong>io.netty.noUnsafe</strong>.
61   */
62  public final class PlatformDependent {
63  
64      private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent.class);
65  
66      private static final Pattern MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN = Pattern.compile(
67              "\\s*-XX:MaxDirectMemorySize\\s*=\\s*([0-9]+)\\s*([kKmMgG]?)\\s*$");
68  
69      private static final boolean IS_WINDOWS = isWindows0();
70      private static final boolean IS_OSX = isOsx0();
71  
72      private static final boolean MAYBE_SUPER_USER;
73  
74      private static final boolean CAN_ENABLE_TCP_NODELAY_BY_DEFAULT = !isAndroid();
75  
76      private static final boolean HAS_UNSAFE = hasUnsafe0();
77      private static final boolean DIRECT_BUFFER_PREFERRED =
78              HAS_UNSAFE && !SystemPropertyUtil.getBoolean("io.netty.noPreferDirect", false);
79      private static final long MAX_DIRECT_MEMORY = maxDirectMemory0();
80  
81      private static final int MPSC_CHUNK_SIZE =  1024;
82      private static final int MIN_MAX_MPSC_CAPACITY =  MPSC_CHUNK_SIZE * 2;
83      private static final int MAX_ALLOWED_MPSC_CAPACITY = Pow2.MAX_POW2;
84  
85      private static final long ARRAY_BASE_OFFSET = arrayBaseOffset0();
86  
87      private static final File TMPDIR = tmpdir0();
88  
89      private static final int BIT_MODE = bitMode0();
90      private static final String NORMALIZED_ARCH = normalizeArch(SystemPropertyUtil.get("os.arch", ""));
91      private static final String NORMALIZED_OS = normalizeOs(SystemPropertyUtil.get("os.name", ""));
92  
93      private static final int ADDRESS_SIZE = addressSize0();
94      private static final boolean USE_DIRECT_BUFFER_NO_CLEANER;
95      private static final AtomicLong DIRECT_MEMORY_COUNTER;
96      private static final long DIRECT_MEMORY_LIMIT;
97      private static final ThreadLocalRandomProvider RANDOM_PROVIDER;
98      private static final Cleaner CLEANER;
99      private static final int UNINITIALIZED_ARRAY_ALLOCATION_THRESHOLD;
100 
101     public static final boolean BIG_ENDIAN_NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
102 
103     private static final Cleaner NOOP = new Cleaner() {
104         @Override
105         public void freeDirectBuffer(ByteBuffer buffer) {
106             // NOOP
107         }
108     };
109 
110     static {
111         if (javaVersion() >= 7) {
112             RANDOM_PROVIDER = new ThreadLocalRandomProvider() {
113                 @Override
114                 public Random current() {
115                     return java.util.concurrent.ThreadLocalRandom.current();
116                 }
117             };
118         } else {
119             RANDOM_PROVIDER = new ThreadLocalRandomProvider() {
120                 @Override
121                 public Random current() {
122                     return ThreadLocalRandom.current();
123                 }
124             };
125         }
126         if (logger.isDebugEnabled()) {
127             logger.debug("-Dio.netty.noPreferDirect: {}", !DIRECT_BUFFER_PREFERRED);
128         }
129 
130         /*
131          * We do not want to log this message if unsafe is explicitly disabled. Do not remove the explicit no unsafe
132          * guard.
133          */
134         if (!hasUnsafe() && !isAndroid() && !PlatformDependent0.isExplicitNoUnsafe()) {
135             logger.info(
136                     "Your platform does not provide complete low-level API for accessing direct buffers reliably. " +
137                     "Unless explicitly requested, heap buffer will always be preferred to avoid potential system " +
138                     "instability.");
139         }
140 
141         // Here is how the system property is used:
142         //
143         // * <  0  - Don't use cleaner, and inherit max direct memory from java. In this case the
144         //           "practical max direct memory" would be 2 * max memory as defined by the JDK.
145         // * == 0  - Use cleaner, Netty will not enforce max memory, and instead will defer to JDK.
146         // * >  0  - Don't use cleaner. This will limit Netty's total direct memory
147         //           (note: that JDK's direct memory limit is independent of this).
148         long maxDirectMemory = SystemPropertyUtil.getLong("io.netty.maxDirectMemory", -1);
149 
150         if (maxDirectMemory == 0 || !hasUnsafe() || !PlatformDependent0.hasDirectBufferNoCleanerConstructor()) {
151             USE_DIRECT_BUFFER_NO_CLEANER = false;
152             DIRECT_MEMORY_COUNTER = null;
153         } else {
154             USE_DIRECT_BUFFER_NO_CLEANER = true;
155             if (maxDirectMemory < 0) {
156                 maxDirectMemory = maxDirectMemory0();
157                 if (maxDirectMemory <= 0) {
158                     DIRECT_MEMORY_COUNTER = null;
159                 } else {
160                     DIRECT_MEMORY_COUNTER = new AtomicLong();
161                 }
162             } else {
163                 DIRECT_MEMORY_COUNTER = new AtomicLong();
164             }
165         }
166         DIRECT_MEMORY_LIMIT = maxDirectMemory;
167         logger.debug("-Dio.netty.maxDirectMemory: {} bytes", maxDirectMemory);
168 
169         int tryAllocateUninitializedArray =
170                 SystemPropertyUtil.getInt("io.netty.uninitializedArrayAllocationThreshold", 1024);
171         UNINITIALIZED_ARRAY_ALLOCATION_THRESHOLD = javaVersion() >= 9 && PlatformDependent0.hasAllocateArrayMethod() ?
172                 tryAllocateUninitializedArray : -1;
173         logger.debug("-Dio.netty.uninitializedArrayAllocationThreshold: {}", UNINITIALIZED_ARRAY_ALLOCATION_THRESHOLD);
174 
175         MAYBE_SUPER_USER = maybeSuperUser0();
176 
177         if (!isAndroid() && hasUnsafe()) {
178             // only direct to method if we are not running on android.
179             // See https://github.com/netty/netty/issues/2604
180             if (javaVersion() >= 9) {
181                 CLEANER = CleanerJava9.isSupported() ? new CleanerJava9() : NOOP;
182             } else {
183                 CLEANER = CleanerJava6.isSupported() ? new CleanerJava6() : NOOP;
184             }
185         } else {
186             CLEANER = NOOP;
187         }
188     }
189 
190     public static boolean hasDirectBufferNoCleanerConstructor() {
191         return PlatformDependent0.hasDirectBufferNoCleanerConstructor();
192     }
193 
194     public static byte[] allocateUninitializedArray(int size) {
195         return UNINITIALIZED_ARRAY_ALLOCATION_THRESHOLD < 0 || UNINITIALIZED_ARRAY_ALLOCATION_THRESHOLD > size ?
196                 new byte[size] : PlatformDependent0.allocateUninitializedArray(size);
197     }
198 
199     /**
200      * Returns {@code true} if and only if the current platform is Android
201      */
202     public static boolean isAndroid() {
203         return PlatformDependent0.isAndroid();
204     }
205 
206     /**
207      * Return {@code true} if the JVM is running on Windows
208      */
209     public static boolean isWindows() {
210         return IS_WINDOWS;
211     }
212 
213     /**
214      * Return {@code true} if the JVM is running on OSX / MacOS
215      */
216     public static boolean isOsx() {
217         return IS_OSX;
218     }
219 
220     /**
221      * Return {@code true} if the current user may be a super-user. Be aware that this is just an hint and so it may
222      * return false-positives.
223      */
224     public static boolean maybeSuperUser() {
225         return MAYBE_SUPER_USER;
226     }
227 
228     /**
229      * Return the version of Java under which this library is used.
230      */
231     public static int javaVersion() {
232         return PlatformDependent0.javaVersion();
233     }
234 
235     /**
236      * Returns {@code true} if and only if it is fine to enable TCP_NODELAY socket option by default.
237      */
238     public static boolean canEnableTcpNoDelayByDefault() {
239         return CAN_ENABLE_TCP_NODELAY_BY_DEFAULT;
240     }
241 
242     /**
243      * Return {@code true} if {@code sun.misc.Unsafe} was found on the classpath and can be used for accelerated
244      * direct memory access.
245      */
246     public static boolean hasUnsafe() {
247         return HAS_UNSAFE;
248     }
249 
250     /**
251      * Return the reason (if any) why {@code sun.misc.Unsafe} was not available.
252      */
253     public static Throwable getUnsafeUnavailabilityCause() {
254         return PlatformDependent0.getUnsafeUnavailabilityCause();
255     }
256 
257     /**
258      * {@code true} if and only if the platform supports unaligned access.
259      *
260      * @see <a href="http://en.wikipedia.org/wiki/Segmentation_fault#Bus_error">Wikipedia on segfault</a>
261      */
262     public static boolean isUnaligned() {
263         return PlatformDependent0.isUnaligned();
264     }
265 
266     /**
267      * Returns {@code true} if the platform has reliable low-level direct buffer access API and a user has not specified
268      * {@code -Dio.netty.noPreferDirect} option.
269      */
270     public static boolean directBufferPreferred() {
271         return DIRECT_BUFFER_PREFERRED;
272     }
273 
274     /**
275      * Returns the maximum memory reserved for direct buffer allocation.
276      */
277     public static long maxDirectMemory() {
278         return MAX_DIRECT_MEMORY;
279     }
280 
281     /**
282      * Returns the temporary directory.
283      */
284     public static File tmpdir() {
285         return TMPDIR;
286     }
287 
288     /**
289      * Returns the bit mode of the current VM (usually 32 or 64.)
290      */
291     public static int bitMode() {
292         return BIT_MODE;
293     }
294 
295     /**
296      * Return the address size of the OS.
297      * 4 (for 32 bits systems ) and 8 (for 64 bits systems).
298      */
299     public static int addressSize() {
300         return ADDRESS_SIZE;
301     }
302 
303     public static long allocateMemory(long size) {
304         return PlatformDependent0.allocateMemory(size);
305     }
306 
307     public static void freeMemory(long address) {
308         PlatformDependent0.freeMemory(address);
309     }
310 
311     /**
312      * Raises an exception bypassing compiler checks for checked exceptions.
313      */
314     public static void throwException(Throwable t) {
315         if (hasUnsafe()) {
316             PlatformDependent0.throwException(t);
317         } else {
318             PlatformDependent.<RuntimeException>throwException0(t);
319         }
320     }
321 
322     @SuppressWarnings("unchecked")
323     private static <E extends Throwable> void throwException0(Throwable t) throws E {
324         throw (E) t;
325     }
326 
327     /**
328      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
329      */
330     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap() {
331         return new ConcurrentHashMap<K, V>();
332     }
333 
334     /**
335      * Creates a new fastest {@link LongCounter} implementation for the current platform.
336      */
337     public static LongCounter newLongCounter() {
338         if (javaVersion() >= 8) {
339             return new LongAdderCounter();
340         } else {
341             return new AtomicLongCounter();
342         }
343     }
344 
345     /**
346      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
347      */
348     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap(int initialCapacity) {
349         return new ConcurrentHashMap<K, V>(initialCapacity);
350     }
351 
352     /**
353      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
354      */
355     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap(int initialCapacity, float loadFactor) {
356         return new ConcurrentHashMap<K, V>(initialCapacity, loadFactor);
357     }
358 
359     /**
360      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
361      */
362     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap(
363             int initialCapacity, float loadFactor, int concurrencyLevel) {
364         return new ConcurrentHashMap<K, V>(initialCapacity, loadFactor, concurrencyLevel);
365     }
366 
367     /**
368      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
369      */
370     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap(Map<? extends K, ? extends V> map) {
371         return new ConcurrentHashMap<K, V>(map);
372     }
373 
374     /**
375      * Try to deallocate the specified direct {@link ByteBuffer}. Please note this method does nothing if
376      * the current platform does not support this operation or the specified buffer is not a direct buffer.
377      */
378     public static void freeDirectBuffer(ByteBuffer buffer) {
379         CLEANER.freeDirectBuffer(buffer);
380     }
381 
382     public static long directBufferAddress(ByteBuffer buffer) {
383         return PlatformDependent0.directBufferAddress(buffer);
384     }
385 
386     public static ByteBuffer directBuffer(long memoryAddress, int size) {
387         if (PlatformDependent0.hasDirectBufferNoCleanerConstructor()) {
388             return PlatformDependent0.newDirectBuffer(memoryAddress, size);
389         }
390         throw new UnsupportedOperationException(
391                 "sun.misc.Unsafe or java.nio.DirectByteBuffer.<init>(long, int) not available");
392     }
393 
394     public static int getInt(Object object, long fieldOffset) {
395         return PlatformDependent0.getInt(object, fieldOffset);
396     }
397 
398     public static byte getByte(long address) {
399         return PlatformDependent0.getByte(address);
400     }
401 
402     public static short getShort(long address) {
403         return PlatformDependent0.getShort(address);
404     }
405 
406     public static int getInt(long address) {
407         return PlatformDependent0.getInt(address);
408     }
409 
410     public static long getLong(long address) {
411         return PlatformDependent0.getLong(address);
412     }
413 
414     public static byte getByte(byte[] data, int index) {
415         return PlatformDependent0.getByte(data, index);
416     }
417 
418     public static short getShort(byte[] data, int index) {
419         return PlatformDependent0.getShort(data, index);
420     }
421 
422     public static int getInt(byte[] data, int index) {
423         return PlatformDependent0.getInt(data, index);
424     }
425 
426     public static long getLong(byte[] data, int index) {
427         return PlatformDependent0.getLong(data, index);
428     }
429 
430     public static void putByte(long address, byte value) {
431         PlatformDependent0.putByte(address, value);
432     }
433 
434     public static void putShort(long address, short value) {
435         PlatformDependent0.putShort(address, value);
436     }
437 
438     public static void putInt(long address, int value) {
439         PlatformDependent0.putInt(address, value);
440     }
441 
442     public static void putLong(long address, long value) {
443         PlatformDependent0.putLong(address, value);
444     }
445 
446     public static void putByte(byte[] data, int index, byte value) {
447         PlatformDependent0.putByte(data, index, value);
448     }
449 
450     public static void putShort(byte[] data, int index, short value) {
451         PlatformDependent0.putShort(data, index, value);
452     }
453 
454     public static void putInt(byte[] data, int index, int value) {
455         PlatformDependent0.putInt(data, index, value);
456     }
457 
458     public static void putLong(byte[] data, int index, long value) {
459         PlatformDependent0.putLong(data, index, value);
460     }
461 
462     public static void copyMemory(long srcAddr, long dstAddr, long length) {
463         PlatformDependent0.copyMemory(srcAddr, dstAddr, length);
464     }
465 
466     public static void copyMemory(byte[] src, int srcIndex, long dstAddr, long length) {
467         PlatformDependent0.copyMemory(src, ARRAY_BASE_OFFSET + srcIndex, null, dstAddr, length);
468     }
469 
470     public static void copyMemory(long srcAddr, byte[] dst, int dstIndex, long length) {
471         PlatformDependent0.copyMemory(null, srcAddr, dst, ARRAY_BASE_OFFSET + dstIndex, length);
472     }
473 
474     public static void setMemory(byte[] dst, int dstIndex, long bytes, byte value) {
475         PlatformDependent0.setMemory(dst, ARRAY_BASE_OFFSET + dstIndex, bytes, value);
476     }
477 
478     public static void setMemory(long address, long bytes, byte value) {
479         PlatformDependent0.setMemory(address, bytes, value);
480     }
481 
482     /**
483      * Allocate a new {@link ByteBuffer} with the given {@code capacity}. {@link ByteBuffer}s allocated with
484      * this method <strong>MUST</strong> be deallocated via {@link #freeDirectNoCleaner(ByteBuffer)}.
485      */
486     public static ByteBuffer allocateDirectNoCleaner(int capacity) {
487         assert USE_DIRECT_BUFFER_NO_CLEANER;
488 
489         incrementMemoryCounter(capacity);
490         try {
491             return PlatformDependent0.allocateDirectNoCleaner(capacity);
492         } catch (Throwable e) {
493             decrementMemoryCounter(capacity);
494             throwException(e);
495             return null;
496         }
497     }
498 
499     /**
500      * Reallocate a new {@link ByteBuffer} with the given {@code capacity}. {@link ByteBuffer}s reallocated with
501      * this method <strong>MUST</strong> be deallocated via {@link #freeDirectNoCleaner(ByteBuffer)}.
502      */
503     public static ByteBuffer reallocateDirectNoCleaner(ByteBuffer buffer, int capacity) {
504         assert USE_DIRECT_BUFFER_NO_CLEANER;
505 
506         int len = capacity - buffer.capacity();
507         incrementMemoryCounter(len);
508         try {
509             return PlatformDependent0.reallocateDirectNoCleaner(buffer, capacity);
510         } catch (Throwable e) {
511             decrementMemoryCounter(len);
512             throwException(e);
513             return null;
514         }
515     }
516 
517     /**
518      * This method <strong>MUST</strong> only be called for {@link ByteBuffer}s that were allocated via
519      * {@link #allocateDirectNoCleaner(int)}.
520      */
521     public static void freeDirectNoCleaner(ByteBuffer buffer) {
522         assert USE_DIRECT_BUFFER_NO_CLEANER;
523 
524         int capacity = buffer.capacity();
525         PlatformDependent0.freeMemory(PlatformDependent0.directBufferAddress(buffer));
526         decrementMemoryCounter(capacity);
527     }
528 
529     private static void incrementMemoryCounter(int capacity) {
530         if (DIRECT_MEMORY_COUNTER != null) {
531             for (;;) {
532                 long usedMemory = DIRECT_MEMORY_COUNTER.get();
533                 long newUsedMemory = usedMemory + capacity;
534                 if (newUsedMemory > DIRECT_MEMORY_LIMIT) {
535                     throw new OutOfDirectMemoryError("failed to allocate " + capacity
536                             + " byte(s) of direct memory (used: " + usedMemory + ", max: " + DIRECT_MEMORY_LIMIT + ')');
537                 }
538                 if (DIRECT_MEMORY_COUNTER.compareAndSet(usedMemory, newUsedMemory)) {
539                     break;
540                 }
541             }
542         }
543     }
544 
545     private static void decrementMemoryCounter(int capacity) {
546         if (DIRECT_MEMORY_COUNTER != null) {
547             long usedMemory = DIRECT_MEMORY_COUNTER.addAndGet(-capacity);
548             assert usedMemory >= 0;
549         }
550     }
551 
552     public static boolean useDirectBufferNoCleaner() {
553         return USE_DIRECT_BUFFER_NO_CLEANER;
554     }
555 
556     /**
557      * Determine if a subsection of an array is zero.
558      * @param bytes The byte array.
559      * @param startPos The starting index (inclusive) in {@code bytes}.
560      * @param length The amount of bytes to check for zero.
561      * @return {@code false} if {@code bytes[startPos:startsPos+length)} contains a value other than zero.
562      */
563     public static boolean isZero(byte[] bytes, int startPos, int length) {
564         return !hasUnsafe() || !isUnaligned() ?
565                 isZeroSafe(bytes, startPos, length) :
566                 PlatformDependent0.isZero(bytes, startPos, length);
567     }
568 
569     private static final class Mpsc {
570         private static final boolean USE_MPSC_CHUNKED_ARRAY_QUEUE;
571 
572         private Mpsc() {
573         }
574 
575         static {
576             Object unsafe = null;
577             if (hasUnsafe()) {
578                 // jctools goes through its own process of initializing unsafe; of
579                 // course, this requires permissions which might not be granted to calling code, so we
580                 // must mark this block as privileged too
581                 unsafe = AccessController.doPrivileged(new PrivilegedAction<Object>() {
582                     @Override
583                     public Object run() {
584                         // force JCTools to initialize unsafe
585                         return UnsafeAccess.UNSAFE;
586                     }
587                 });
588             }
589 
590             if (unsafe == null) {
591                 logger.debug("org.jctools-core.MpscChunkedArrayQueue: unavailable");
592                 USE_MPSC_CHUNKED_ARRAY_QUEUE = false;
593             } else {
594                 logger.debug("org.jctools-core.MpscChunkedArrayQueue: available");
595                 USE_MPSC_CHUNKED_ARRAY_QUEUE = true;
596             }
597         }
598 
599         static <T> Queue<T> newMpscQueue(final int maxCapacity) {
600             // Calculate the max capacity which can not be bigger then MAX_ALLOWED_MPSC_CAPACITY.
601             // This is forced by the MpscChunkedArrayQueue implementation as will try to round it
602             // up to the next power of two and so will overflow otherwise.
603             final int capacity = max(min(maxCapacity, MAX_ALLOWED_MPSC_CAPACITY), MIN_MAX_MPSC_CAPACITY);
604             return USE_MPSC_CHUNKED_ARRAY_QUEUE ? new MpscChunkedArrayQueue<T>(MPSC_CHUNK_SIZE, capacity)
605                                                 : new MpscGrowableAtomicArrayQueue<T>(MPSC_CHUNK_SIZE, capacity);
606         }
607 
608         static <T> Queue<T> newMpscQueue() {
609             return USE_MPSC_CHUNKED_ARRAY_QUEUE ? new MpscUnboundedArrayQueue<T>(MPSC_CHUNK_SIZE)
610                                                 : new MpscUnboundedAtomicArrayQueue<T>(MPSC_CHUNK_SIZE);
611         }
612     }
613 
614     /**
615      * Create a new {@link Queue} which is safe to use for multiple producers (different threads) and a single
616      * consumer (one thread!).
617      * @return A MPSC queue which may be unbounded.
618      */
619     public static <T> Queue<T> newMpscQueue() {
620         return Mpsc.newMpscQueue();
621     }
622 
623     /**
624      * Create a new {@link Queue} which is safe to use for multiple producers (different threads) and a single
625      * consumer (one thread!).
626      */
627     public static <T> Queue<T> newMpscQueue(final int maxCapacity) {
628         return Mpsc.newMpscQueue(maxCapacity);
629     }
630 
631     /**
632      * Create a new {@link Queue} which is safe to use for single producer (one thread!) and a single
633      * consumer (one thread!).
634      */
635     public static <T> Queue<T> newSpscQueue() {
636         return hasUnsafe() ? new SpscLinkedQueue<T>() : new SpscLinkedAtomicQueue<T>();
637     }
638 
639     /**
640      * Create a new {@link Queue} which is safe to use for multiple producers (different threads) and a single
641      * consumer (one thread!) with the given fixes {@code capacity}.
642      */
643     public static <T> Queue<T> newFixedMpscQueue(int capacity) {
644         return hasUnsafe() ? new MpscArrayQueue<T>(capacity) : new MpscAtomicArrayQueue<T>(capacity);
645     }
646 
647     /**
648      * Return the {@link ClassLoader} for the given {@link Class}.
649      */
650     public static ClassLoader getClassLoader(final Class<?> clazz) {
651         return PlatformDependent0.getClassLoader(clazz);
652     }
653 
654     /**
655      * Return the context {@link ClassLoader} for the current {@link Thread}.
656      */
657     public static ClassLoader getContextClassLoader() {
658         return PlatformDependent0.getContextClassLoader();
659     }
660 
661     /**
662      * Return the system {@link ClassLoader}.
663      */
664     public static ClassLoader getSystemClassLoader() {
665         return PlatformDependent0.getSystemClassLoader();
666     }
667 
668     /**
669      * Returns a new concurrent {@link Deque}.
670      */
671     public static <C> Deque<C> newConcurrentDeque() {
672         if (javaVersion() < 7) {
673             return new LinkedBlockingDeque<C>();
674         } else {
675             return new ConcurrentLinkedDeque<C>();
676         }
677     }
678 
679     /**
680      * Return a {@link Random} which is not-threadsafe and so can only be used from the same thread.
681      */
682     public static Random threadLocalRandom() {
683         return RANDOM_PROVIDER.current();
684     }
685 
686     private static boolean isWindows0() {
687         boolean windows = SystemPropertyUtil.get("os.name", "").toLowerCase(Locale.US).contains("win");
688         if (windows) {
689             logger.debug("Platform: Windows");
690         }
691         return windows;
692     }
693 
694     private static boolean isOsx0() {
695         String osname = SystemPropertyUtil.get("os.name", "").toLowerCase(Locale.US)
696                 .replaceAll("[^a-z0-9]+", "");
697         boolean osx = osname.startsWith("macosx") || osname.startsWith("osx");
698 
699         if (osx) {
700             logger.debug("Platform: MacOS");
701         }
702         return osx;
703     }
704 
705     private static boolean maybeSuperUser0() {
706         String username = SystemPropertyUtil.get("user.name");
707         if (isWindows()) {
708             return "Administrator".equals(username);
709         }
710         // Check for root and toor as some BSDs have a toor user that is basically the same as root.
711         return "root".equals(username) || "toor".equals(username);
712     }
713 
714     private static boolean hasUnsafe0() {
715         if (isAndroid()) {
716             logger.debug("sun.misc.Unsafe: unavailable (Android)");
717             return false;
718         }
719 
720         if (PlatformDependent0.isExplicitNoUnsafe()) {
721             return false;
722         }
723 
724         try {
725             boolean hasUnsafe = PlatformDependent0.hasUnsafe();
726             logger.debug("sun.misc.Unsafe: {}", hasUnsafe ? "available" : "unavailable");
727             return hasUnsafe;
728         } catch (Throwable t) {
729             logger.trace("Could not determine if Unsafe is available", t);
730             // Probably failed to initialize PlatformDependent0.
731             return false;
732         }
733     }
734 
735     private static long arrayBaseOffset0() {
736         if (!hasUnsafe()) {
737             return -1;
738         }
739 
740         return PlatformDependent0.arrayBaseOffset();
741     }
742 
743     private static long maxDirectMemory0() {
744         long maxDirectMemory = 0;
745         ClassLoader systemClassLoader = null;
746         try {
747             // Try to get from sun.misc.VM.maxDirectMemory() which should be most accurate.
748             systemClassLoader = getSystemClassLoader();
749             Class<?> vmClass = Class.forName("sun.misc.VM", true, systemClassLoader);
750             Method m = vmClass.getDeclaredMethod("maxDirectMemory");
751             maxDirectMemory = ((Number) m.invoke(null)).longValue();
752         } catch (Throwable ignored) {
753             // Ignore
754         }
755 
756         if (maxDirectMemory > 0) {
757             return maxDirectMemory;
758         }
759 
760         try {
761             // Now try to get the JVM option (-XX:MaxDirectMemorySize) and parse it.
762             // Note that we are using reflection because Android doesn't have these classes.
763             Class<?> mgmtFactoryClass = Class.forName(
764                     "java.lang.management.ManagementFactory", true, systemClassLoader);
765             Class<?> runtimeClass = Class.forName(
766                     "java.lang.management.RuntimeMXBean", true, systemClassLoader);
767 
768             Object runtime = mgmtFactoryClass.getDeclaredMethod("getRuntimeMXBean").invoke(null);
769 
770             @SuppressWarnings("unchecked")
771             List<String> vmArgs = (List<String>) runtimeClass.getDeclaredMethod("getInputArguments").invoke(runtime);
772             for (int i = vmArgs.size() - 1; i >= 0; i --) {
773                 Matcher m = MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN.matcher(vmArgs.get(i));
774                 if (!m.matches()) {
775                     continue;
776                 }
777 
778                 maxDirectMemory = Long.parseLong(m.group(1));
779                 switch (m.group(2).charAt(0)) {
780                     case 'k': case 'K':
781                         maxDirectMemory *= 1024;
782                         break;
783                     case 'm': case 'M':
784                         maxDirectMemory *= 1024 * 1024;
785                         break;
786                     case 'g': case 'G':
787                         maxDirectMemory *= 1024 * 1024 * 1024;
788                         break;
789                 }
790                 break;
791             }
792         } catch (Throwable ignored) {
793             // Ignore
794         }
795 
796         if (maxDirectMemory <= 0) {
797             maxDirectMemory = Runtime.getRuntime().maxMemory();
798             logger.debug("maxDirectMemory: {} bytes (maybe)", maxDirectMemory);
799         } else {
800             logger.debug("maxDirectMemory: {} bytes", maxDirectMemory);
801         }
802 
803         return maxDirectMemory;
804     }
805 
806     private static File tmpdir0() {
807         File f;
808         try {
809             f = toDirectory(SystemPropertyUtil.get("io.netty.tmpdir"));
810             if (f != null) {
811                 logger.debug("-Dio.netty.tmpdir: {}", f);
812                 return f;
813             }
814 
815             f = toDirectory(SystemPropertyUtil.get("java.io.tmpdir"));
816             if (f != null) {
817                 logger.debug("-Dio.netty.tmpdir: {} (java.io.tmpdir)", f);
818                 return f;
819             }
820 
821             // This shouldn't happen, but just in case ..
822             if (isWindows()) {
823                 f = toDirectory(System.getenv("TEMP"));
824                 if (f != null) {
825                     logger.debug("-Dio.netty.tmpdir: {} (%TEMP%)", f);
826                     return f;
827                 }
828 
829                 String userprofile = System.getenv("USERPROFILE");
830                 if (userprofile != null) {
831                     f = toDirectory(userprofile + "\\AppData\\Local\\Temp");
832                     if (f != null) {
833                         logger.debug("-Dio.netty.tmpdir: {} (%USERPROFILE%\\AppData\\Local\\Temp)", f);
834                         return f;
835                     }
836 
837                     f = toDirectory(userprofile + "\\Local Settings\\Temp");
838                     if (f != null) {
839                         logger.debug("-Dio.netty.tmpdir: {} (%USERPROFILE%\\Local Settings\\Temp)", f);
840                         return f;
841                     }
842                 }
843             } else {
844                 f = toDirectory(System.getenv("TMPDIR"));
845                 if (f != null) {
846                     logger.debug("-Dio.netty.tmpdir: {} ($TMPDIR)", f);
847                     return f;
848                 }
849             }
850         } catch (Throwable ignored) {
851             // Environment variable inaccessible
852         }
853 
854         // Last resort.
855         if (isWindows()) {
856             f = new File("C:\\Windows\\Temp");
857         } else {
858             f = new File("/tmp");
859         }
860 
861         logger.warn("Failed to get the temporary directory; falling back to: {}", f);
862         return f;
863     }
864 
865     @SuppressWarnings("ResultOfMethodCallIgnored")
866     private static File toDirectory(String path) {
867         if (path == null) {
868             return null;
869         }
870 
871         File f = new File(path);
872         f.mkdirs();
873 
874         if (!f.isDirectory()) {
875             return null;
876         }
877 
878         try {
879             return f.getAbsoluteFile();
880         } catch (Exception ignored) {
881             return f;
882         }
883     }
884 
885     private static int bitMode0() {
886         // Check user-specified bit mode first.
887         int bitMode = SystemPropertyUtil.getInt("io.netty.bitMode", 0);
888         if (bitMode > 0) {
889             logger.debug("-Dio.netty.bitMode: {}", bitMode);
890             return bitMode;
891         }
892 
893         // And then the vendor specific ones which is probably most reliable.
894         bitMode = SystemPropertyUtil.getInt("sun.arch.data.model", 0);
895         if (bitMode > 0) {
896             logger.debug("-Dio.netty.bitMode: {} (sun.arch.data.model)", bitMode);
897             return bitMode;
898         }
899         bitMode = SystemPropertyUtil.getInt("com.ibm.vm.bitmode", 0);
900         if (bitMode > 0) {
901             logger.debug("-Dio.netty.bitMode: {} (com.ibm.vm.bitmode)", bitMode);
902             return bitMode;
903         }
904 
905         // os.arch also gives us a good hint.
906         String arch = SystemPropertyUtil.get("os.arch", "").toLowerCase(Locale.US).trim();
907         if ("amd64".equals(arch) || "x86_64".equals(arch)) {
908             bitMode = 64;
909         } else if ("i386".equals(arch) || "i486".equals(arch) || "i586".equals(arch) || "i686".equals(arch)) {
910             bitMode = 32;
911         }
912 
913         if (bitMode > 0) {
914             logger.debug("-Dio.netty.bitMode: {} (os.arch: {})", bitMode, arch);
915         }
916 
917         // Last resort: guess from VM name and then fall back to most common 64-bit mode.
918         String vm = SystemPropertyUtil.get("java.vm.name", "").toLowerCase(Locale.US);
919         Pattern BIT_PATTERN = Pattern.compile("([1-9][0-9]+)-?bit");
920         Matcher m = BIT_PATTERN.matcher(vm);
921         if (m.find()) {
922             return Integer.parseInt(m.group(1));
923         } else {
924             return 64;
925         }
926     }
927 
928     private static int addressSize0() {
929         if (!hasUnsafe()) {
930             return -1;
931         }
932         return PlatformDependent0.addressSize();
933     }
934 
935     private static boolean isZeroSafe(byte[] bytes, int startPos, int length) {
936         final int end = startPos + length;
937         for (; startPos < end; ++startPos) {
938             if (bytes[startPos] != 0) {
939                 return false;
940             }
941         }
942         return true;
943     }
944 
945     public static String normalizedArch() {
946         return NORMALIZED_ARCH;
947     }
948 
949     public static String normalizedOs() {
950         return NORMALIZED_OS;
951     }
952 
953     private static String normalize(String value) {
954         return value.toLowerCase(Locale.US).replaceAll("[^a-z0-9]+", "");
955     }
956 
957     private static String normalizeArch(String value) {
958         value = normalize(value);
959         if (value.matches("^(x8664|amd64|ia32e|em64t|x64)$")) {
960             return "x86_64";
961         }
962         if (value.matches("^(x8632|x86|i[3-6]86|ia32|x32)$")) {
963             return "x86_32";
964         }
965         if (value.matches("^(ia64|itanium64)$")) {
966             return "itanium_64";
967         }
968         if (value.matches("^(sparc|sparc32)$")) {
969             return "sparc_32";
970         }
971         if (value.matches("^(sparcv9|sparc64)$")) {
972             return "sparc_64";
973         }
974         if (value.matches("^(arm|arm32)$")) {
975             return "arm_32";
976         }
977         if ("aarch64".equals(value)) {
978             return "aarch_64";
979         }
980         if (value.matches("^(ppc|ppc32)$")) {
981             return "ppc_32";
982         }
983         if ("ppc64".equals(value)) {
984             return "ppc_64";
985         }
986         if ("ppc64le".equals(value)) {
987             return "ppcle_64";
988         }
989         if ("s390".equals(value)) {
990             return "s390_32";
991         }
992         if ("s390x".equals(value)) {
993             return "s390_64";
994         }
995 
996         return "unknown";
997     }
998 
999     private static String normalizeOs(String value) {
1000         value = normalize(value);
1001         if (value.startsWith("aix")) {
1002             return "aix";
1003         }
1004         if (value.startsWith("hpux")) {
1005             return "hpux";
1006         }
1007         if (value.startsWith("os400")) {
1008             // Avoid the names such as os4000
1009             if (value.length() <= 5 || !Character.isDigit(value.charAt(5))) {
1010                 return "os400";
1011             }
1012         }
1013         if (value.startsWith("linux")) {
1014             return "linux";
1015         }
1016         if (value.startsWith("macosx") || value.startsWith("osx")) {
1017             return "osx";
1018         }
1019         if (value.startsWith("freebsd")) {
1020             return "freebsd";
1021         }
1022         if (value.startsWith("openbsd")) {
1023             return "openbsd";
1024         }
1025         if (value.startsWith("netbsd")) {
1026             return "netbsd";
1027         }
1028         if (value.startsWith("solaris") || value.startsWith("sunos")) {
1029             return "sunos";
1030         }
1031         if (value.startsWith("windows")) {
1032             return "windows";
1033         }
1034 
1035         return "unknown";
1036     }
1037 
1038     private static final class AtomicLongCounter extends AtomicLong implements LongCounter {
1039         @Override
1040         public void add(long delta) {
1041             addAndGet(delta);
1042         }
1043 
1044         @Override
1045         public void increment() {
1046             incrementAndGet();
1047         }
1048 
1049         @Override
1050         public void decrement() {
1051             decrementAndGet();
1052         }
1053 
1054         @Override
1055         public long value() {
1056             return get();
1057         }
1058     }
1059 
1060     private interface ThreadLocalRandomProvider {
1061         Random current();
1062     }
1063 
1064     private PlatformDependent() {
1065         // only static method supported
1066     }
1067 }