1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
56
57
58
59
60
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
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
132
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
142
143
144
145
146
147
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
179
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
201
202 public static boolean isAndroid() {
203 return PlatformDependent0.isAndroid();
204 }
205
206
207
208
209 public static boolean isWindows() {
210 return IS_WINDOWS;
211 }
212
213
214
215
216 public static boolean isOsx() {
217 return IS_OSX;
218 }
219
220
221
222
223
224 public static boolean maybeSuperUser() {
225 return MAYBE_SUPER_USER;
226 }
227
228
229
230
231 public static int javaVersion() {
232 return PlatformDependent0.javaVersion();
233 }
234
235
236
237
238 public static boolean canEnableTcpNoDelayByDefault() {
239 return CAN_ENABLE_TCP_NODELAY_BY_DEFAULT;
240 }
241
242
243
244
245
246 public static boolean hasUnsafe() {
247 return HAS_UNSAFE;
248 }
249
250
251
252
253 public static Throwable getUnsafeUnavailabilityCause() {
254 return PlatformDependent0.getUnsafeUnavailabilityCause();
255 }
256
257
258
259
260
261
262 public static boolean isUnaligned() {
263 return PlatformDependent0.isUnaligned();
264 }
265
266
267
268
269
270 public static boolean directBufferPreferred() {
271 return DIRECT_BUFFER_PREFERRED;
272 }
273
274
275
276
277 public static long maxDirectMemory() {
278 return MAX_DIRECT_MEMORY;
279 }
280
281
282
283
284 public static File tmpdir() {
285 return TMPDIR;
286 }
287
288
289
290
291 public static int bitMode() {
292 return BIT_MODE;
293 }
294
295
296
297
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
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
329
330 public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap() {
331 return new ConcurrentHashMap<K, V>();
332 }
333
334
335
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
347
348 public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap(int initialCapacity) {
349 return new ConcurrentHashMap<K, V>(initialCapacity);
350 }
351
352
353
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
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
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
376
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
484
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
501
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
519
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
558
559
560
561
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
579
580
581 unsafe = AccessController.doPrivileged(new PrivilegedAction<Object>() {
582 @Override
583 public Object run() {
584
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
601
602
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
616
617
618
619 public static <T> Queue<T> newMpscQueue() {
620 return Mpsc.newMpscQueue();
621 }
622
623
624
625
626
627 public static <T> Queue<T> newMpscQueue(final int maxCapacity) {
628 return Mpsc.newMpscQueue(maxCapacity);
629 }
630
631
632
633
634
635 public static <T> Queue<T> newSpscQueue() {
636 return hasUnsafe() ? new SpscLinkedQueue<T>() : new SpscLinkedAtomicQueue<T>();
637 }
638
639
640
641
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
649
650 public static ClassLoader getClassLoader(final Class<?> clazz) {
651 return PlatformDependent0.getClassLoader(clazz);
652 }
653
654
655
656
657 public static ClassLoader getContextClassLoader() {
658 return PlatformDependent0.getContextClassLoader();
659 }
660
661
662
663
664 public static ClassLoader getSystemClassLoader() {
665 return PlatformDependent0.getSystemClassLoader();
666 }
667
668
669
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
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
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
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
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
754 }
755
756 if (maxDirectMemory > 0) {
757 return maxDirectMemory;
758 }
759
760 try {
761
762
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
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
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
852 }
853
854
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
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
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
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
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
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
1066 }
1067 }