1
18
19
20 package org.xnio.nio;
21
22 import java.io.Closeable;
23 import java.io.IOException;
24 import java.nio.channels.Selector;
25 import java.nio.channels.spi.SelectorProvider;
26 import java.security.AccessController;
27 import java.security.PrivilegedAction;
28 import java.lang.reflect.Constructor;
29 import java.lang.reflect.InvocationTargetException;
30 import org.xnio.FileSystemWatcher;
31 import org.xnio.IoUtils;
32 import org.xnio.Options;
33 import org.xnio.ReadPropertyAction;
34 import org.xnio.Xnio;
35 import org.xnio.OptionMap;
36 import org.xnio.XnioWorker;
37 import org.xnio.management.XnioProviderMXBean;
38 import org.xnio.management.XnioServerMXBean;
39 import org.xnio.management.XnioWorkerMXBean;
40
41 import static org.xnio.nio.Log.log;
42
43
46 final class NioXnio extends Xnio {
47
48 static final boolean IS_HP_UX;
49 static final boolean HAS_BUGGY_EVENT_PORT;
50
51 interface SelectorCreator {
52 Selector open() throws IOException;
53 }
54
55 final SelectorCreator tempSelectorCreator;
56 final SelectorCreator mainSelectorCreator;
57
58 static {
59 log.greeting(Version.getVersionString());
60 IS_HP_UX = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
61 public Boolean run() {
62 final String bugLevel = System.getProperty("sun.nio.ch.bugLevel");
63 if (bugLevel == null) System.setProperty("sun.nio.ch.bugLevel", "");
64 return Boolean.valueOf(System.getProperty("os.name", "unknown").equalsIgnoreCase("hp-ux"));
65 }
66 }).booleanValue();
67
68 HAS_BUGGY_EVENT_PORT = true;
69 }
70
71
74 NioXnio() {
75 super("nio");
76 final Object[] objects = AccessController.doPrivileged(
77 new PrivilegedAction<Object[]>() {
78 public Object[] run() {
79 String jdkVersion = System.getProperty("java.specification.version", "1.8");
80 final boolean jdk9 = ! (jdkVersion.equals("1.8") || jdkVersion.equals("8"));
81 final SelectorProvider defaultProvider = SelectorProvider.provider();
82 final String chosenProvider = System.getProperty("xnio.nio.selector.provider");
83 SelectorProvider provider = null;
84 if (chosenProvider != null) {
85 try {
86 provider = Class.forName(chosenProvider, true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
87 provider.openSelector().close();
88 } catch (Throwable e) {
89
90 provider = null;
91 }
92 }
93 if (! jdk9) {
94
95 if (provider == null) {
96 try {
97
98 provider = Class.forName("sun.nio.ch.KQueueSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
99 provider.openSelector().close();
100 } catch (Throwable e) {
101
102 provider = null;
103 }
104 }
105 if (provider == null) {
106 try {
107
108 provider = Class.forName("sun.nio.ch.EPollSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
109 provider.openSelector().close();
110 } catch (Throwable e) {
111
112 provider = null;
113 }
114 }
115 if (provider == null && ! HAS_BUGGY_EVENT_PORT) {
116 try {
117
118 provider = Class.forName("sun.nio.ch.EventPortSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
119 provider.openSelector().close();
120 } catch (Throwable e) {
121
122 provider = null;
123 }
124 }
125 if (provider == null) {
126 try {
127
128 provider = Class.forName("sun.nio.ch.DevPollSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
129 provider.openSelector().close();
130 } catch (Throwable e) {
131
132 provider = null;
133 }
134 }
135 if (provider == null) {
136 try {
137
138 provider = Class.forName("sun.nio.ch.EventPortSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
139 provider.openSelector().close();
140 } catch (Throwable e) {
141
142 provider = null;
143 }
144 }
145 if (provider == null) {
146 try {
147
148 provider = Class.forName("sun.nio.ch.PollsetSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
149 provider.openSelector().close();
150 } catch (Throwable e) {
151
152 provider = null;
153 }
154 }
155 }
156 if (provider == null) {
157 try {
158 defaultProvider.openSelector().close();
159 provider = defaultProvider;
160 } catch (Throwable e) {
161
162 }
163 }
164 if (provider == null) {
165 try {
166
167 provider = Class.forName("sun.nio.ch.PollSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
168 provider.openSelector().close();
169 } catch (Throwable e) {
170
171 provider = null;
172 }
173 }
174 if (provider == null) {
175 throw log.noSelectorProvider();
176 }
177 log.selectorProvider(provider);
178 final boolean defaultIsPoll = "sun.nio.ch.PollSelectorProvider".equals(provider.getClass().getName());
179 final String chosenMainSelector = System.getProperty("xnio.nio.selector.main");
180 final String chosenTempSelector = System.getProperty("xnio.nio.selector.temp");
181 final SelectorCreator defaultSelectorCreator = new DefaultSelectorCreator(provider);
182 final Object[] objects = new Object[3];
183 objects[0] = provider;
184 if (chosenTempSelector != null) try {
185 final ConstructorSelectorCreator creator = new ConstructorSelectorCreator(chosenTempSelector, provider);
186 IoUtils.safeClose(creator.open());
187 objects[1] = creator;
188 } catch (Exception e) {
189
190 }
191 if (chosenMainSelector != null) try {
192 final ConstructorSelectorCreator creator = new ConstructorSelectorCreator(chosenMainSelector, provider);
193 IoUtils.safeClose(creator.open());
194 objects[2] = creator;
195 } catch (Exception e) {
196
197 }
198 if (! defaultIsPoll && ! jdk9) {
199
200 if (objects[1] == null) try {
201 SelectorProvider pollSelectorProvider = Class.forName("sun.nio.ch.PollSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
202 pollSelectorProvider.openSelector().close();
203 objects[1] = new DefaultSelectorCreator(provider);
204 } catch (Exception e) {
205
206 }
207 }
208 if (objects[1] == null) {
209 objects[1] = defaultSelectorCreator;
210 }
211 if (objects[2] == null) {
212 objects[2] = defaultSelectorCreator;
213 }
214 return objects;
215 }
216 }
217 );
218 tempSelectorCreator = (SelectorCreator) objects[1];
219 mainSelectorCreator = (SelectorCreator) objects[2];
220 log.selectors(mainSelectorCreator, tempSelectorCreator);
221 register(new XnioProviderMXBean() {
222 public String getName() {
223 return "nio";
224 }
225
226 public String getVersion() {
227 return Version.getVersionString();
228 }
229 });
230 }
231
232 protected XnioWorker build(final XnioWorker.Builder builder) {
233 final NioXnioWorker worker = new NioXnioWorker(builder);
234 worker.start();
235 return worker;
236 }
237
238 @Override
239 public FileSystemWatcher createFileSystemWatcher(String name, OptionMap options) {
240 try {
241 boolean daemonThread = options.get(Options.THREAD_DAEMON, true);
242 return new WatchServiceFileSystemWatcher(name, daemonThread);
243 } catch (LinkageError e) {
244
245 }
246 return super.createFileSystemWatcher(name, options);
247 }
248
249 private final ThreadLocal<FinalizableSelectorHolder> selectorThreadLocal = new ThreadLocal<FinalizableSelectorHolder>() {
250 public void remove() {
251
252 FinalizableSelectorHolder holder = get();
253 if(holder != null) {
254 IoUtils.safeClose(holder.selector);
255 }
256 super.remove();
257 }
258 };
259
260 Selector getSelector() throws IOException {
261 final ThreadLocal<FinalizableSelectorHolder> threadLocal = selectorThreadLocal;
262 FinalizableSelectorHolder holder = threadLocal.get();
263 if (holder == null) {
264 holder = new FinalizableSelectorHolder(tempSelectorCreator.open());
265 threadLocal.set(holder);
266 }
267 return holder.selector;
268 }
269
270 private static class DefaultSelectorCreator implements SelectorCreator {
271 private final SelectorProvider provider;
272
273 private DefaultSelectorCreator(final SelectorProvider provider) {
274 this.provider = provider;
275 }
276
277 public Selector open() throws IOException {
278 return provider.openSelector();
279 }
280
281 public String toString() {
282 return "Default system selector creator for provider " + provider.getClass();
283 }
284 }
285
286 private static class ConstructorSelectorCreator implements SelectorCreator {
287
288 private final Constructor<? extends Selector> constructor;
289 private final SelectorProvider provider;
290
291 public ConstructorSelectorCreator(final String name, final SelectorProvider provider) throws ClassNotFoundException, NoSuchMethodException {
292 this.provider = provider;
293 final Class<? extends Selector> selectorImplClass = Class.forName(name, true, null).asSubclass(Selector.class);
294 final Constructor<? extends Selector> constructor = selectorImplClass.getDeclaredConstructor(SelectorProvider.class);
295 constructor.setAccessible(true);
296 this.constructor = constructor;
297 }
298
299 public Selector open() throws IOException {
300 try {
301 return constructor.newInstance(provider);
302 } catch (InstantiationException e) {
303 return Selector.open();
304 } catch (IllegalAccessException e) {
305 return Selector.open();
306 } catch (InvocationTargetException e) {
307 try {
308 throw e.getTargetException();
309 } catch (IOException | Error | RuntimeException e2) {
310 throw e2;
311 } catch (Throwable t) {
312 throw log.unexpectedSelectorOpenProblem(t);
313 }
314 }
315 }
316
317 public String toString() {
318 return String.format("Selector creator %s for provider %s", constructor.getDeclaringClass(), provider.getClass());
319 }
320 }
321
322 protected static Closeable register(XnioWorkerMXBean workerMXBean) {
323 return Xnio.register(workerMXBean);
324 }
325
326 protected static Closeable register(XnioServerMXBean serverMXBean) {
327 return Xnio.register(serverMXBean);
328 }
329
330 private static final class FinalizableSelectorHolder {
331 final Selector selector;
332
333
334 private FinalizableSelectorHolder(Selector selector) {
335 this.selector = selector;
336 }
337
338 @Override
339 protected void finalize() throws Throwable {
340 IoUtils.safeClose(selector);
341 }
342 }
343 }
344