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;
  }
  /** {@inheritDoc} */
  @Override
  protected final void unbind0(List<? extends SocketAddress> localAddresses) throws Exception {
    AcceptorOperationFuture request = new AcceptorOperationFuture(localAddresses);

    cancelQueue.add(request);
    startupAcceptor();
    wakeup();

    request.awaitUninterruptibly();

    if (request.getException() != null) {
      throw request.getException();
    }
  }
  /** {@inheritDoc} */
  @Override
  protected final Set<SocketAddress> bindInternal(List<? extends SocketAddress> localAddresses)
      throws Exception {
    // Create a bind request as a Future operation. When the selector
    // have handled the registration, it will signal this future.
    AcceptorOperationFuture request = new AcceptorOperationFuture(localAddresses);

    // adds the Registration request to the queue for the Workers
    // to handle
    registerQueue.add(request);

    // creates the Acceptor instance and has the local
    // executor kick it off.
    startupAcceptor();

    // As we just started the acceptor, we have to unblock the select()
    // in order to process the bind request we just have added to the
    // registerQueue.
    try {
      lock.acquire();

      // Wait a bit to give a chance to the Acceptor thread to do the select()
      Thread.sleep(10);
      wakeup();
    } finally {
      lock.release();
    }

    // Now, we wait until this request is completed.
    request.awaitUninterruptibly();

    if (request.getException() != null) {
      throw request.getException();
    }

    // Update the local addresses.
    // setLocalAddresses() shouldn't be called from the worker thread
    // because of deadlock.
    Set<SocketAddress> newLocalAddresses = new HashSet<SocketAddress>();

    for (DatagramChannel handle : boundHandles.values()) {
      newLocalAddresses.add(localAddress(handle));
    }

    return newLocalAddresses;
  }
  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;
  }
 /** {@inheritDoc} */
 public void flush(NioSession session) {
   if (scheduleFlush(session)) {
     wakeup();
   }
 }
 /** {@inheritDoc} */
 @Override
 protected void dispose0() throws Exception {
   unbind();
   startupAcceptor();
   wakeup();
 }