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
21 import java.lang.reflect.Field;
22 import java.lang.reflect.Method;
23 import java.nio.ByteBuffer;
24 import java.security.AccessController;
25 import java.security.PrivilegedAction;
26
27
28
29
30
31
32
33
34 final class CleanerJava6 implements Cleaner {
35 private static final long CLEANER_FIELD_OFFSET;
36 private static final Method CLEAN_METHOD;
37 private static final Field CLEANER_FIELD;
38
39 private static final InternalLogger logger = InternalLoggerFactory.getInstance(CleanerJava6.class);
40
41 static {
42 long fieldOffset;
43 Method clean;
44 Field cleanerField;
45 Throwable error = null;
46 final ByteBuffer direct = ByteBuffer.allocateDirect(1);
47 try {
48 Object mayBeCleanerField = AccessController.doPrivileged(new PrivilegedAction<Object>() {
49 @Override
50 public Object run() {
51 try {
52 Field cleanerField = direct.getClass().getDeclaredField("cleaner");
53 if (!PlatformDependent.hasUnsafe()) {
54
55
56 cleanerField.setAccessible(true);
57 }
58 return cleanerField;
59 } catch (Throwable cause) {
60 return cause;
61 }
62 }
63 });
64 if (mayBeCleanerField instanceof Throwable) {
65 throw (Throwable) mayBeCleanerField;
66 }
67
68 cleanerField = (Field) mayBeCleanerField;
69
70 final Object cleaner;
71
72
73
74 if (PlatformDependent.hasUnsafe()) {
75 fieldOffset = PlatformDependent0.objectFieldOffset(cleanerField);
76 cleaner = PlatformDependent0.getObject(direct, fieldOffset);
77 } else {
78 fieldOffset = -1;
79 cleaner = cleanerField.get(direct);
80 }
81 clean = cleaner.getClass().getDeclaredMethod("clean");
82 clean.invoke(cleaner);
83 } catch (Throwable t) {
84
85 fieldOffset = -1;
86 clean = null;
87 error = t;
88 cleanerField = null;
89 }
90
91 if (error == null) {
92 logger.debug("java.nio.ByteBuffer.cleaner(): available");
93 } else {
94 logger.debug("java.nio.ByteBuffer.cleaner(): unavailable", error);
95 }
96 CLEANER_FIELD = cleanerField;
97 CLEANER_FIELD_OFFSET = fieldOffset;
98 CLEAN_METHOD = clean;
99 }
100
101 static boolean isSupported() {
102 return CLEANER_FIELD_OFFSET != -1 || CLEANER_FIELD != null;
103 }
104
105 @Override
106 public void freeDirectBuffer(ByteBuffer buffer) {
107 if (!buffer.isDirect()) {
108 return;
109 }
110 if (System.getSecurityManager() == null) {
111 try {
112 freeDirectBuffer0(buffer);
113 } catch (Throwable cause) {
114 PlatformDependent0.throwException(cause);
115 }
116 } else {
117 freeDirectBufferPrivileged(buffer);
118 }
119 }
120
121 private static void freeDirectBufferPrivileged(final ByteBuffer buffer) {
122 Throwable cause = AccessController.doPrivileged(new PrivilegedAction<Throwable>() {
123 @Override
124 public Throwable run() {
125 try {
126 freeDirectBuffer0(buffer);
127 return null;
128 } catch (Throwable cause) {
129 return cause;
130 }
131 }
132 });
133 if (cause != null) {
134 PlatformDependent0.throwException(cause);
135 }
136 }
137
138 private static void freeDirectBuffer0(ByteBuffer buffer) throws Exception {
139 final Object cleaner;
140
141
142 if (CLEANER_FIELD_OFFSET == -1) {
143 cleaner = CLEANER_FIELD.get(buffer);
144 } else {
145 cleaner = PlatformDependent0.getObject(buffer, CLEANER_FIELD_OFFSET);
146 }
147 if (cleaner != null) {
148 CLEAN_METHOD.invoke(cleaner);
149 }
150 }
151 }