private boolean waitSelect(final int operations, final boolean blocking) throws IOException {
if (!(io.getChannel() instanceof SelectableChannel)) {
return true;
}
final Ruby runtime = getRuntime();
RubyThread thread = runtime.getCurrentContext().getThread();
SelectableChannel selectable = (SelectableChannel)io.getChannel();
selectable.configureBlocking(false);
final Selector selector = runtime.getSelectorPool().get();
final SelectionKey key = selectable.register(selector, operations);
try {
io.addBlockingThread(thread);
final int[] result = new int[1];
thread.executeBlockingTask(new RubyThread.BlockingTask() {
public void run() throws InterruptedException {
try {
if (!blocking) {
result[0] = selector.selectNow();
if (result[0] == 0) {
if ((operations & SelectionKey.OP_READ) != 0 && (operations & SelectionKey.OP_WRITE) != 0) {
if (key.isReadable()) {
writeWouldBlock();
} else if (key.isWritable()) {
readWouldBlock();
} else { //neither, pick one
readWouldBlock();
}
} else if ((operations & SelectionKey.OP_READ) != 0) {
readWouldBlock();
} else if ((operations & SelectionKey.OP_WRITE) != 0) {
writeWouldBlock();
}
}
} else {
result[0] = selector.select();
}
} catch (IOException ioe) {
throw runtime.newRuntimeError("Error with selector: " + ioe.getMessage());
}
}
public void wakeup() {
selector.wakeup();
}
});
if (result[0] >= 1) {
Set<SelectionKey> keySet = selector.selectedKeys();
if (keySet.iterator().next() == key) {
return true;
}
}
return false;
} catch (InterruptedException ie) {
return false;
} finally {
// Note: I don't like ignoring these exceptions, but it's
// unclear how likely they are to happen or what damage we
// might do by ignoring them. Note that the pieces are separate
// so that we can ensure one failing does not affect the others
// running.
// clean up the key in the selector
try {
if (key != null) key.cancel();
if (selector != null) selector.selectNow();
} catch (Exception e) {
// ignore
}
// shut down and null out the selector
try {
if (selector != null) {
runtime.getSelectorPool().put(selector);
}
} catch (Exception e) {
// ignore
}
// remove this thread as a blocker against the given IO
io.removeBlockingThread(thread);
// clear thread state from blocking call
thread.afterBlockingCall();
}
}