public void run() { int nHandles = 0; lastIdleCheckTime = System.currentTimeMillis(); // Release the lock lock.release(); while (selectable) { try { int selected = select(SELECT_TIMEOUT); nHandles += registerHandles(); if (nHandles == 0) { try { lock.acquire(); if (registerQueue.isEmpty() && cancelQueue.isEmpty()) { acceptor = null; break; } } finally { lock.release(); } } if (selected > 0) { processReadySessions(selectedHandles()); } long currentTime = System.currentTimeMillis(); flushSessions(currentTime); nHandles -= unregisterHandles(); notifyIdleSessions(currentTime); } catch (ClosedSelectorException cse) { // If the selector has been closed, we can exit the loop ExceptionMonitor.getInstance().exceptionCaught(cse); break; } catch (Exception e) { ExceptionMonitor.getInstance().exceptionCaught(e); try { Thread.sleep(1000); } catch (InterruptedException e1) { } } } if (selectable && isDisposing()) { selectable = false; try { destroy(); } catch (Exception e) { ExceptionMonitor.getInstance().exceptionCaught(e); } finally { disposalFuture.setValue(true); } } }
/** * Process a new session : - initialize it - create its chain - fire the CREATED listeners if any * * @param session The session to create * @return true if the session has been registered */ private boolean addNow(S session) { boolean registered = false; try { init(session); registered = true; // Build the filter chain of this session. IoFilterChainBuilder chainBuilder = session.getService().getFilterChainBuilder(); chainBuilder.buildFilterChain(session.getFilterChain()); // DefaultIoFilterChain.CONNECT_FUTURE is cleared inside here // in AbstractIoFilterChain.fireSessionOpened(). // Propagate the SESSION_CREATED event up to the chain IoServiceListenerSupport listeners = ((AbstractIoService) session.getService()).getListeners(); listeners.fireSessionCreated(session); } catch (Throwable e) { ExceptionMonitor.getInstance().exceptionCaught(e); try { destroy(session); } catch (Exception e1) { ExceptionMonitor.getInstance().exceptionCaught(e1); } finally { registered = false; } } return registered; }
private int unregisterHandles() { int nHandles = 0; for (; ; ) { AcceptorOperationFuture request = cancelQueue.poll(); if (request == null) { break; } // close the channels for (SocketAddress socketAddress : request.getLocalAddresses()) { DatagramChannel handle = boundHandles.remove(socketAddress); if (handle == null) { continue; } try { close(handle); wakeup(); // wake up again to trigger thread death } catch (Exception e) { ExceptionMonitor.getInstance().exceptionCaught(e); } finally { nHandles++; } } request.setDone(); } return nHandles; }
private IoSession newSessionWithoutLock(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception { DatagramChannel handle = boundHandles.get(localAddress); if (handle == null) { throw new IllegalArgumentException("Unknown local address: " + localAddress); } IoSession session; synchronized (sessionRecycler) { session = sessionRecycler.recycle(remoteAddress); if (session != null) { return session; } // If a new session needs to be created. NioSession newSession = newSession(this, handle, remoteAddress); getSessionRecycler().put(newSession); session = newSession; } initSession(session, null, null); try { this.getFilterChainBuilder().buildFilterChain(session.getFilterChain()); getListeners().fireSessionCreated(session); } catch (Exception e) { ExceptionMonitor.getInstance().exceptionCaught(e); } return session; }
/** Calls {@link IoServiceListener#sessionDestroyed(IoSession)} for all registered listeners. */ public void fireSessionDestroyed(IoSession session) { // Try to remove the remaining empty session set after removal. if (managedSessions.remove(Long.valueOf(session.getId())) == null) { return; } // Fire session events. session.getFilterChain().fireSessionClosed(); // Fire listener events. try { for (IoServiceListener l : listeners) { try { l.sessionDestroyed(session); } catch (Throwable e) { ExceptionMonitor.getInstance().exceptionCaught(e); } } } finally { // Fire a virtual service deactivation event for the last session of the connector. if (session.getService() instanceof IoConnector) { boolean lastSession = false; synchronized (managedSessions) { lastSession = managedSessions.isEmpty(); } if (lastSession) { fireServiceDeactivated(); } } } }
@SuppressWarnings("unchecked") private void notifyListener(IoFutureListener l) { try { l.operationComplete(this); } catch (Throwable t) { ExceptionMonitor.getInstance().exceptionCaught(t); } }
/** * Calls {@link IoServiceListener#serviceIdle(IoService, IdleStatus)} for all registered * listeners. */ public void fireServiceIdle(IdleStatus status) { if (!activated.get()) { return; } for (IoServiceListener l : listeners) { try { l.serviceIdle(service, status); } catch (Throwable e) { ExceptionMonitor.getInstance().exceptionCaught(e); } } }
/** Calls {@link IoServiceListener#serviceActivated(IoService)} for all registered listeners. */ public void fireServiceActivated() { if (!activated.compareAndSet(false, true)) { return; } activationTime = System.currentTimeMillis(); for (IoServiceListener l : listeners) { try { l.serviceActivated(service); } catch (Throwable e) { ExceptionMonitor.getInstance().exceptionCaught(e); } } }
/** Calls {@link IoServiceListener#serviceDeactivated(IoService)} for all registered listeners. */ public void fireServiceDeactivated() { if (!activated.compareAndSet(true, false)) { return; } try { for (IoServiceListener l : listeners) { try { l.serviceDeactivated(service); } catch (Throwable e) { ExceptionMonitor.getInstance().exceptionCaught(e); } } } finally { disconnectSessions(); } }
private int registerHandles() { for (; ; ) { AcceptorOperationFuture req = registerQueue.poll(); if (req == null) { break; } Map<SocketAddress, DatagramChannel> newHandles = new HashMap<SocketAddress, DatagramChannel>(); List<SocketAddress> localAddresses = req.getLocalAddresses(); try { for (SocketAddress socketAddress : localAddresses) { DatagramChannel handle = open(socketAddress); newHandles.put(localAddress(handle), handle); } boundHandles.putAll(newHandles); getListeners().fireServiceActivated(); req.setDone(); return newHandles.size(); } catch (Exception e) { req.setException(e); } finally { // Roll back if failed to bind all addresses. if (req.getException() != null) { for (DatagramChannel handle : newHandles.values()) { try { close(handle); } catch (Exception e) { ExceptionMonitor.getInstance().exceptionCaught(e); } } wakeup(); } } } return 0; }
/** Creates a new instance. */ private NioDatagramAcceptor(IoSessionConfig sessionConfig, Executor executor) { super(sessionConfig, executor); try { init(); selectable = true; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeIoException("Failed to initialize.", e); } finally { if (!selectable) { try { destroy(); } catch (Exception e) { ExceptionMonitor.getInstance().exceptionCaught(e); } } } }
private void processReadySessions(Set<SelectionKey> handles) { Iterator<SelectionKey> iterator = handles.iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); DatagramChannel handle = (DatagramChannel) key.channel(); iterator.remove(); try { if ((key != null) && key.isValid() && key.isReadable()) { readHandle(handle); } if ((key != null) && key.isValid() && key.isWritable()) { for (IoSession session : getManagedSessions().values()) { scheduleFlush((NioSession) session); } } } catch (Exception e) { ExceptionMonitor.getInstance().exceptionCaught(e); } } }
/** Calls {@link IoServiceListener#sessionCreated(IoSession)} for all registered listeners. */ public void fireSessionCreated(IoSession session) { boolean firstSession = false; if (session.getService() instanceof IoConnector) { synchronized (managedSessions) { firstSession = managedSessions.isEmpty(); } } // If already registered, ignore. if (managedSessions.putIfAbsent(Long.valueOf(session.getId()), session) != null) { return; } // If the first connector session, fire a virtual service activation event. if (firstSession) { fireServiceActivated(); } // Fire session events. session.getFilterChain().fireSessionCreated(); session.getFilterChain().fireSessionOpened(); int managedSessionCount = managedSessions.size(); if (managedSessionCount > largestManagedSessionCount) { largestManagedSessionCount = managedSessionCount; } cumulativeManagedSessionCount++; // Fire listener events. for (IoServiceListener l : listeners) { try { l.sessionCreated(session); } catch (Throwable e) { ExceptionMonitor.getInstance().exceptionCaught(e); } } }
public void run() { assert (processorRef.get() == this); int nSessions = 0; lastIdleCheckTime = System.currentTimeMillis(); for (; ; ) { try { // This select has a timeout so that we can manage // idle session when we get out of the select every // second. (note : this is a hack to avoid creating // a dedicated thread). long t0 = System.currentTimeMillis(); int selected = select(SELECT_TIMEOUT); long t1 = System.currentTimeMillis(); long delta = (t1 - t0); if ((selected == 0) && !wakeupCalled.get() && (delta < 100)) { // Last chance : the select() may have been // interrupted because we have had an closed channel. if (isBrokenConnection()) { LOG.warn("Broken connection"); // we can reselect immediately // set back the flag to false wakeupCalled.getAndSet(false); continue; } else { LOG.warn("Create a new selector. Selected is 0, delta = " + (t1 - t0)); // Ok, we are hit by the nasty epoll // spinning. // Basically, there is a race condition // which causes a closing file descriptor not to be // considered as available as a selected channel, but // it stopped the select. The next time we will // call select(), it will exit immediately for the same // reason, and do so forever, consuming 100% // CPU. // We have to destroy the selector, and // register all the socket on a new one. registerNewSelector(); } // Set back the flag to false wakeupCalled.getAndSet(false); // and continue the loop continue; } // Manage newly created session first nSessions += handleNewSessions(); updateTrafficMask(); // Now, if we have had some incoming or outgoing events, // deal with them if (selected > 0) { // LOG.debug("Processing ..."); // This log hurts one of the MDCFilter test... process(); } // Write the pending requests long currentTime = System.currentTimeMillis(); flush(currentTime); // And manage removed sessions nSessions -= removeSessions(); // Last, not least, send Idle events to the idle sessions notifyIdleSessions(currentTime); // Get a chance to exit the infinite loop if there are no // more sessions on this Processor if (nSessions == 0) { processorRef.set(null); if (newSessions.isEmpty() && isSelectorEmpty()) { // newSessions.add() precedes startupProcessor assert (processorRef.get() != this); break; } assert (processorRef.get() != this); if (!processorRef.compareAndSet(null, this)) { // startupProcessor won race, so must exit processor assert (processorRef.get() != this); break; } assert (processorRef.get() == this); } // Disconnect all sessions immediately if disposal has been // requested so that we exit this loop eventually. if (isDisposing()) { for (Iterator<S> i = allSessions(); i.hasNext(); ) { scheduleRemove(i.next()); } wakeup(); } } catch (ClosedSelectorException cse) { // If the selector has been closed, we can exit the loop break; } catch (Throwable t) { ExceptionMonitor.getInstance().exceptionCaught(t); try { Thread.sleep(1000); } catch (InterruptedException e1) { ExceptionMonitor.getInstance().exceptionCaught(e1); } } } try { synchronized (disposalLock) { if (disposing) { doDispose(); } } } catch (Throwable t) { ExceptionMonitor.getInstance().exceptionCaught(t); } finally { disposalFuture.setValue(true); } }