return select(channel, io, ops, -1);
}
public boolean select(Channel channel, RubyIO io, int ops, long timeout) {
if (channel instanceof SelectableChannel) {
SelectableChannel selectable = (SelectableChannel)channel;
synchronized (selectable.blockingLock()) {
boolean oldBlocking = selectable.isBlocking();
SelectionKey key = null;
try {
selectable.configureBlocking(false);
if (io != null) io.addBlockingThread(this);
currentSelector = getRuntime().getSelectorPool().get(selectable.provider());
key = selectable.register(currentSelector, ops);
beforeBlockingCall();
int result;
if (timeout < 0) {
result = currentSelector.select();
} else if (timeout == 0) {
result = currentSelector.selectNow();
} else {
result = currentSelector.select(timeout);
}
// check for thread events, in case we've been woken up to die
pollThreadEvents();
if (result == 1) {
Set<SelectionKey> keySet = currentSelector.selectedKeys();
if (keySet.iterator().next() == key) {
return true;
}
}
return false;
} catch (IOException ioe) {
throw getRuntime().newIOErrorFromException(ioe);
} 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 (currentSelector != null) currentSelector.selectNow();
} catch (Exception e) {
// ignore
}
// shut down and null out the selector
try {
if (currentSelector != null) {
getRuntime().getSelectorPool().put(currentSelector);
}
} catch (Exception e) {
// ignore
} finally {
currentSelector = null;
}
// remove this thread as a blocker against the given IO
if (io != null) io.removeBlockingThread(this);
// go back to previous blocking state on the selectable
try {
selectable.configureBlocking(oldBlocking);
} catch (Exception e) {
// ignore
}
// clear thread state from blocking call