}
else if (o instanceof ChangeSelectableChannel)
{
// finish accepting/connecting this connection
final ChangeSelectableChannel asc = (ChangeSelectableChannel)o;
final SelectableChannel channel=asc._channel;
final Object att = asc._attachment;
if ((channel instanceof SocketChannel) && ((SocketChannel)channel).isConnected())
{
key = channel.register(selector,SelectionKey.OP_READ,att);
SelectChannelEndPoint endpoint = newEndPoint((SocketChannel)channel,this,key);
key.attach(endpoint);
endpoint.dispatch();
}
else if (channel.isOpen())
{
channel.register(selector,SelectionKey.OP_CONNECT,att);
}
}
else if (o instanceof SocketChannel)
{
final SocketChannel channel=(SocketChannel)o;
if (channel.isConnected())
{
key = channel.register(selector,SelectionKey.OP_READ,null);
SelectChannelEndPoint endpoint = newEndPoint(channel,this,key);
key.attach(endpoint);
endpoint.dispatch();
}
else
{
channel.register(selector,SelectionKey.OP_CONNECT,null);
}
}
else if (o instanceof ServerSocketChannel)
{
ServerSocketChannel channel = (ServerSocketChannel)o;
channel.register(getSelector(),SelectionKey.OP_ACCEPT);
}
else if (o instanceof ChangeTask)
{
((ChangeTask)o).run();
}
else
throw new IllegalArgumentException(o.toString());
}
catch (CancelledKeyException e)
{
if (isRunning())
Log.warn(e);
else
Log.debug(e);
}
}
changes.clear();
long idle_next = 0;
long retry_next = 0;
long now=System.currentTimeMillis();
synchronized (this)
{
_idleTimeout.setNow(now);
_retryTimeout.setNow(now);
if (_lowResourcesConnections>0 && selector.keys().size()>_lowResourcesConnections)
_idleTimeout.setDuration(_lowResourcesMaxIdleTime);
else
_idleTimeout.setDuration(_maxIdleTime);
idle_next=_idleTimeout.getTimeToNext();
retry_next=_retryTimeout.getTimeToNext();
}
// workout how low to wait in select
long wait = 1000L; // not getMaxIdleTime() as the now value of the idle timers needs to be updated.
if (idle_next >= 0 && wait > idle_next)
wait = idle_next;
if (wait > 0 && retry_next >= 0 && wait > retry_next)
wait = retry_next;
// Do the select.
if (wait > 10) // TODO tune or configure this
{
long before=now;
int selected=selector.select(wait);
now = System.currentTimeMillis();
_idleTimeout.setNow(now);
_retryTimeout.setNow(now);
// Look for JVM bugs
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6403933
// http://bugs.sun.com/view_bug.do?bug_id=6693490
if (__JVMBUG_THRESHHOLD>0 && selected==0 && wait>__JVMBUG_THRESHHOLD && (now-before)<(wait/2) )
{
_jvmBug++;
if (_jvmBug>=(__JVMBUG_THRESHHOLD2))
{
synchronized (this)
{
// BLOODY SUN BUG !!! Try refreshing the entire selector.
if (_jvmBug1)
Log.debug("seeing JVM BUG(s) - recreating selector");
else
{
_jvmBug1=true;
Log.info("seeing JVM BUG(s) - recreating selector");
}
final Selector new_selector = Selector.open();
Iterator iterator = _selector.keys().iterator();
while (iterator.hasNext())
{
SelectionKey k = (SelectionKey)iterator.next();
if (!k.isValid() || k.interestOps()==0)
continue;
final SelectableChannel channel = k.channel();
final Object attachment = k.attachment();
if (attachment==null)
addChange(channel);
else
addChange(channel,attachment);
}
_selector.close();
_selector=new_selector;
_jvmBug=0;
return;
}
}
else if (_jvmBug==__JVMBUG_THRESHHOLD || _jvmBug==__JVMBUG_THRESHHOLD1)
{
// Cancel keys with 0 interested ops
if (_jvmBug0)
Log.debug("seeing JVM BUG(s) - cancelling interestOps==0");
else
{
_jvmBug0=true;
Log.info("seeing JVM BUG(s) - cancelling interestOps==0");
}
Iterator iter = selector.keys().iterator();
while(iter.hasNext())
{
SelectionKey k = (SelectionKey) iter.next();
if (k.isValid()&&k.interestOps()==0)
{
k.cancel();
}
}
return;
}
}
else
_jvmBug=0;
}
else
{
selector.selectNow();
_jvmBug=0;
}
// have we been destroyed while sleeping
if (_selector==null || !selector.isOpen())
return;
// Look for things to do
Iterator iter = selector.selectedKeys().iterator();
while (iter.hasNext())
{
key = (SelectionKey) iter.next();
try
{
if (!key.isValid())
{
key.cancel();
SelectChannelEndPoint endpoint = (SelectChannelEndPoint)key.attachment();
if (endpoint != null)
endpoint.doUpdateKey();
continue;
}
Object att = key.attachment();
if (att instanceof SelectChannelEndPoint)
{
SelectChannelEndPoint endpoint = (SelectChannelEndPoint)att;
endpoint.dispatch();
}
else if (key.isAcceptable())
{
SocketChannel channel = acceptChannel(key);
if (channel==null)
continue;
channel.configureBlocking(false);
// TODO make it reluctant to leave 0
_nextSet=++_nextSet%_selectSet.length;
// Is this for this selectset
if (_nextSet==_setID)
{
// bind connections to this select set.
SelectionKey cKey = channel.register(_selectSet[_nextSet].getSelector(), SelectionKey.OP_READ);
SelectChannelEndPoint endpoint=newEndPoint(channel,_selectSet[_nextSet],cKey);
cKey.attach(endpoint);
if (endpoint != null)
endpoint.dispatch();
}
else
{
// nope - give it to another.
_selectSet[_nextSet].addChange(channel);
_selectSet[_nextSet].wakeup();
}
}
else if (key.isConnectable())
{
// Complete a connection of a registered channel
SocketChannel channel = (SocketChannel)key.channel();
boolean connected=false;
try
{
connected=channel.finishConnect();
}
catch(Exception e)
{
connectionFailed(channel,e,att);
}