private void dispose(Selector localSelector, LinkedBlockingQueue localSelectorTasks) {
      Assert.eval(Thread.currentThread() == this);

      if (localSelector != null) {

        for (Object element : localSelector.keys()) {
          try {
            SelectionKey key = (SelectionKey) element;
            cleanupChannel(key.channel(), null);
          } catch (Exception e) {
            logger.warn("Exception trying to close channel", e);
          }
        }

        try {
          localSelector.close();
        } catch (Exception e) {
          if ((Os.isMac()) && (Os.isUnix()) && (e.getMessage().equals("Bad file descriptor"))) {
            // I can't find a specific bug about this, but I also can't seem to prevent the
            // exception on the Mac.
            // So just logging this as warning.
            logger.warn("Exception trying to close selector: " + e.getMessage());
          } else {
            logger.error("Exception trying to close selector", e);
          }
        }
      }
    }
Exemplo n.º 2
0
  @Override
  public void run() {
    selectorManager.notifyReady();
    while (selectorManager.isStarted() && selector.isOpen()) {
      try {
        beforeSelect();
        wakenUp.set(false);
        long before = -1;
        // Wether to look jvm bug
        if (isNeedLookingJVMBug()) {
          before = System.currentTimeMillis();
        }
        long wait = DEFAULT_WAIT;
        if (nextTimeout > 0) {
          wait = nextTimeout;
        }
        int selected = selector.select(wait);
        if (selected == 0) {
          if (before != -1) {
            lookJVMBug(before, selected, wait);
          }
          selectTries++;
          // check tmeout and idle
          nextTimeout = checkSessionTimeout();
          continue;
        } else {
          selectTries = 0;
        }

      } catch (ClosedSelectorException e) {
        break;
      } catch (IOException e) {
        log.error("Reactor select error", e);
        if (selector.isOpen()) {
          continue;
        } else {
          break;
        }
      }
      Set<SelectionKey> selectedKeys = selector.selectedKeys();
      gate.lock();
      try {
        postSelect(selectedKeys, selector.keys());
        dispatchEvent(selectedKeys);
      } finally {
        gate.unlock();
      }
    }
    if (selector != null) {
      if (selector.isOpen()) {
        try {
          controller.closeChannel(selector);
          selector.close();
        } catch (IOException e) {
          controller.notifyException(e);
          log.error("stop reactor error", e);
        }
      }
    }
  }
Exemplo n.º 3
0
 /** Return the set of SelectionKey registered on this Selector. */
 public Set<SelectionKey> keys() {
   if (selector != null) {
     return selector.keys();
   } else {
     throw new IllegalStateException("Selector is not created!");
   }
 }
  void unregisterChannels(SelectionKeyRegistrationReference registrationReference)
      throws Exception {

    registrationReference.cancelRegistration();

    SelectorIntraband defaultIntraband = (SelectorIntraband) registrationReference.getIntraband();

    Selector selector = defaultIntraband.selector;

    Set<SelectionKey> keys = selector.keys();

    while (!keys.isEmpty()) {
      selector.wakeup();
    }

    SelectionKey readSelectionKey = registrationReference.readSelectionKey;
    SelectionKey writeSelectionKey = registrationReference.writeSelectionKey;

    SelectableChannel readSelectableChannel = readSelectionKey.channel();
    SelectableChannel writeSelectableChannel = writeSelectionKey.channel();

    while (readSelectableChannel.keyFor(selector) != null) ;
    while (writeSelectableChannel.keyFor(selector) != null) ;

    writeSelectableChannel.close();
    readSelectableChannel.close();
  }
Exemplo n.º 5
0
  public boolean processNow() throws IOException {
    int numKeys = selector.selectNow();

    if (selector.keys().isEmpty()) return false;

    if (numKeys > 0) dispatchMessages();

    return true;
  }
  public void stop() {
    try {
      lock.lock();

      if (networkJob != null && !networkJob.isCancelled()) {
        networkJob.cancel(true);
        networkJob = null;
      }

      try {
        if (selector != null) {

          selector.wakeup();

          boolean isContinue = true;
          while (isContinue) {
            try {
              for (SelectionKey selectionKey : selector.keys()) {
                selectionKey.channel().close();
                selectionKey.cancel();
              }
              isContinue = false; // continue till all keys are cancelled
            } catch (ConcurrentModificationException e) {
              logger.warn(
                  "An exception occurred while closing a selector key : '{}'", e.getMessage());
            }
          }

          selector.close();
        }
      } catch (IOException e) {
        logger.warn("An exception occurred while closing the selector : '{}'", e.getMessage());
      }

      if (broadcastKey != null) {
        try {
          broadcastKey.channel().close();
        } catch (IOException e) {
          logger.warn(
              "An exception occurred while closing the broadcast channel : '{}'", e.getMessage());
        }
      }

      if (unicastKey != null) {
        try {
          unicastKey.channel().close();
        } catch (IOException e) {
          logger.warn(
              "An exception occurred while closing the unicast channel : '{}'", e.getMessage());
        }
      }

      ipAddress = null;
    } finally {
      lock.unlock();
    }
  }
Exemplo n.º 7
0
  public void shutdown(final long period, final TimeUnit timeUnit) {
    channelDispatcher.stop();
    for (SelectionKey selectionKey : socketChannelSelector.keys()) {
      final AbstractChannelReader reader = (AbstractChannelReader) selectionKey.attachment();
      selectionKey.cancel();
      if (reader != null) {
        while (!reader.isClosed()) {
          try {
            Thread.sleep(channelReaderFrequencyMSecs);
          } catch (InterruptedException e) {
          }
        }
        final ScheduledFuture<?> readerFuture = reader.getScheduledFuture();
        readerFuture.cancel(false);
      }
      IOUtils.closeQuietly(
          selectionKey
              .channel()); // should already be closed via reader, but if reader did not exist...
    }
    IOUtils.closeQuietly(socketChannelSelector);

    for (SelectionKey selectionKey : serverSocketSelector.keys()) {
      selectionKey.cancel();
      IOUtils.closeQuietly(selectionKey.channel());
    }
    IOUtils.closeQuietly(serverSocketSelector);
    executor.shutdown();
    try {
      executor.awaitTermination(period, timeUnit);
    } catch (final InterruptedException ex) {
      LOGGER.warn("Interrupted while trying to shutdown executor");
    }
    final int currentBufferPoolSize = bufferPool.size();
    final String warning =
        (currentBufferPoolSize != initialBufferPoolSize)
            ? "Initial buffer count="
                + initialBufferPoolSize
                + " Current buffer count="
                + currentBufferPoolSize
                + " Could indicate a buffer leak.  Ensure all consumers are executed until they complete."
            : "";
    LOGGER.info("Channel listener shutdown. " + warning);
  }
Exemplo n.º 8
0
 private void listen() throws IOException {
   // TODO Auto-generated method stub
   // 监听所有的事件
   while (true) {
     selector.select(); // 返回值为本次触发的事件数
     Set<SelectionKey> selectionKeys = selector.keys();
     for (SelectionKey key : selectionKeys) {
       handle(key);
     }
     selectionKeys.clear(); // 清除处理过的事件
   }
 }
Exemplo n.º 9
0
  /** MemcachedClient calls this method to handle IO over the connections. */
  @SuppressWarnings("unchecked")
  public void handleIO() throws IOException {
    if (shutDown) {
      throw new IOException("No IO while shut down");
    }

    // Deal with all of the stuff that's been added, but may not be marked
    // writable.
    handleInputQueue();
    getLogger().debug("Done dealing with queue.");

    long delay = 0;
    if (!reconnectQueue.isEmpty()) {
      long now = System.currentTimeMillis();
      long then = reconnectQueue.firstKey();
      delay = Math.max(then - now, 1);
    }
    getLogger().debug("Selecting with delay of %sms", delay);
    assert selectorsMakeSense() : "Selectors don't make sense.";
    int selected = selector.select(delay);
    Set<SelectionKey> selectedKeys = selector.selectedKeys();

    if (selectedKeys.isEmpty() && !shutDown) {
      getLogger().debug("No selectors ready, interrupted: " + Thread.interrupted());
      if (++emptySelects > DOUBLE_CHECK_EMPTY) {
        for (SelectionKey sk : selector.keys()) {
          getLogger().info("%s has %s, interested in %s", sk, sk.readyOps(), sk.interestOps());
          if (sk.readyOps() != 0) {
            getLogger().info("%s has a ready op, handling IO", sk);
            handleIO(sk);
          } else {
            queueReconnect((MemcachedNode) sk.attachment());
          }
        }
        assert emptySelects < EXCESSIVE_EMPTY : "Too many empty selects";
      }
    } else {
      getLogger().debug("Selected %d, selected %d keys", selected, selectedKeys.size());
      emptySelects = 0;
      for (SelectionKey sk : selectedKeys) {
        handleIO(sk);
      } // for each selector
      selectedKeys.clear();
    }

    if (!shutDown && !reconnectQueue.isEmpty()) {
      attemptReconnects();
    }
  }
Exemplo n.º 10
0
  public void close() {
    selectable = false;
    selector.wakeup();

    // forcibly close remaining sockets
    for (SelectionKey key : selector.keys()) {
      if (key != null) {
        safelyClose(key.channel());
      }
    }

    safelyClose(selector);
    safelyClose(agent);
    safelyClose(channel);
    if (authSocket != null) {
      FileUtils.deleteQuietly(new File(authSocket));
    }
  }
Exemplo n.º 11
0
  @Override
  public void update(Observable o, Object arg) {

    // ENVIAR POSICIONS
    // Si el que volem és actualitzar les posicions al joc
    if (arg instanceof int[]) {
      int[] lastPosition = (int[]) arg;
      enviar(lastPosition);
    }

    // ACABAR PARTIDA
    // Si el que volem és acabar la partida
    else if (arg instanceof Integer) {
      if ((int) arg == Const.ACABA_PARTIDA) {
        System.out.println(
            "~Partida Acabada | Desconectem " + arraySocketChannels.size() + " jugadors");
        controlador.acaba();
        enviar(Const.FINISH_CODE);

        System.out.print("Cancelació de les Claus...");

        // CONCURRENCIA claus
        // Les claus son recursos compartits. Un dels problemes que ens podem trobar,
        // es que abans de que els clients rebin el FINISH_CODE, enviïn un paquet,
        // i quan es procesi la clau sigui cancelada.

        // CANCELEM LES CLAUS
        // Hem de cancelar només les claus que pertanyen a conexions amb
        // clients, que son les que retornen un SocketChannel quan invoquem
        // key.channel()
        synchronized (this) {
          for (SelectionKey key : selector.keys()) {
            if (key.channel() instanceof SocketChannel
                && arraySocketChannels.contains((SocketChannel) key.channel())) {
              key.cancel();
              System.out.print(" | Clau cancelada");
            }
          }
        }
        arraySocketChannels.clear();
        System.out.println("\nArray de SocketChannels 'cleared'");
      }
    }
  }
Exemplo n.º 12
0
  /**
   * Cleans up the contents of the selector, closing any server socket channels that might be
   * associated with it. Any connections that might have been established through those channels
   * should not be impacted.
   */
  private void cleanUpSelector() {
    try {
      for (SelectionKey key : selector.keys()) {
        try {
          key.cancel();
        } catch (Exception e) {
          logger.traceException(e);
        }

        try {
          key.channel().close();
        } catch (Exception e) {
          logger.traceException(e);
        }
      }
    } catch (Exception e) {
      logger.traceException(e);
    }
  }
Exemplo n.º 13
0
  public boolean process(long timeout) throws IOException {
    while (timeout > 0) {
      long start = System.nanoTime();
      int numKeys = selector.select(timeout);
      long end = System.nanoTime();

      if (selector.keys().isEmpty()) return false;

      if (numKeys > 0) {
        dispatchMessages();
        break;
      }

      timeout -= TimeUnit.NANOSECONDS.toMillis(end - start);
      if (timeout <= 0) {
        break;
      }
    }
    return true;
  }
Exemplo n.º 14
0
  /**
   * Check session timeout or idle
   *
   * @return
   */
  private final long checkSessionTimeout() {
    long nextTimeout = 0;
    if (configuration.getCheckSessionTimeoutInterval() > 0) {
      gate.lock();
      try {
        if (selectTries * 1000 >= configuration.getCheckSessionTimeoutInterval()) {
          nextTimeout = configuration.getCheckSessionTimeoutInterval();
          for (SelectionKey key : selector.keys()) {

            if (key.attachment() != null) {
              long n = checkExpiredIdle(key, getSessionFromAttchment(key));
              nextTimeout = n < nextTimeout ? n : nextTimeout;
            }
          }
          selectTries = 0;
        }
      } finally {
        gate.unlock();
      }
    }
    return nextTimeout;
  }
Exemplo n.º 15
0
 protected void timeout(int keyCount, boolean hasEvents) {
   long now = System.currentTimeMillis();
   // This method is called on every loop of the Poller. Don't process
   // timeouts on every loop of the Poller since that would create too
   // much load and timeouts can afford to wait a few seconds.
   // However, do process timeouts if any of the following are true:
   // - the selector simply timed out (suggests there isn't much load)
   // - the nextExpiration time has passed
   // - the server socket is being closed
   if (nextExpiration > 0 && (keyCount > 0 || hasEvents) && (now < nextExpiration) && !close) {
     return;
   }
   // timeout
   int keycount = 0;
   try {
     for (SelectionKey key : selector.keys()) {
       keycount++;
       try {
         NioSocketWrapper ka = (NioSocketWrapper) key.attachment();
         if (ka == null) {
           cancelledKey(key); // we don't support any keys without attachments
         } else if (close) {
           key.interestOps(0);
           ka.interestOps(0); // avoid duplicate stop calls
           processKey(key, ka);
         } else if ((ka.interestOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ
             || (ka.interestOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {
           boolean isTimedOut = false;
           // Check for read timeout
           if ((ka.interestOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
             long delta = now - ka.getLastRead();
             long timeout = ka.getReadTimeout();
             isTimedOut = timeout > 0 && delta > timeout;
           }
           // Check for write timeout
           if (!isTimedOut
               && (ka.interestOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {
             long delta = now - ka.getLastWrite();
             long timeout = ka.getWriteTimeout();
             isTimedOut = timeout > 0 && delta > timeout;
           }
           if (isTimedOut) {
             key.interestOps(0);
             ka.interestOps(0); // avoid duplicate timeout calls
             ka.setError(new SocketTimeoutException());
             if (!processSocket(ka, SocketEvent.ERROR, true)) {
               cancelledKey(key);
             }
           }
         }
       } catch (CancelledKeyException ckx) {
         cancelledKey(key);
       }
     } // for
   } catch (ConcurrentModificationException cme) {
     // See https://bz.apache.org/bugzilla/show_bug.cgi?id=57943
     log.warn(sm.getString("endpoint.nio.timeoutCme"), cme);
   }
   long prevExp = nextExpiration; // for logging purposes only
   nextExpiration = System.currentTimeMillis() + socketProperties.getTimeoutInterval();
   if (log.isTraceEnabled()) {
     log.trace(
         "timeout completed: keys processed="
             + keycount
             + "; now="
             + now
             + "; nextExpiration="
             + prevExp
             + "; keyCount="
             + keyCount
             + "; hasEvents="
             + hasEvents
             + "; eval="
             + ((now < prevExp) && (keyCount > 0 || hasEvents) && (!close)));
   }
 }
Exemplo n.º 16
0
 @SelectorThreadOnly
 private void abortAll(Throwable e) {
   Set<NioTransport> pairs = new HashSet<NioTransport>();
   for (SelectionKey k : selector.keys()) pairs.add((NioTransport) k.attachment());
   for (NioTransport p : pairs) p.abort(e);
 }
Exemplo n.º 17
0
  /**
   * Attend to channels in the hub.
   *
   * <p>This method returns when {@link #close()} is called and the selector is shut down.
   */
  public void run() {
    synchronized (startedLock) {
      started = true;
      selectorThread = Thread.currentThread();
      startedLock.notifyAll();
    }
    final String oldName = selectorThread.getName();

    try {
      while (true) {
        try {
          while (true) {
            Callable<Void, IOException> t = selectorTasks.poll();
            if (t == null) break;
            try {
              t.call();
            } catch (IOException e) {
              LOGGER.log(WARNING, "Failed to process selectorTasks", e);
              // but keep on at the next task
            }
          }

          selectorThread.setName(
              "NioChannelHub keys=" + selector.keys().size() + " gen=" + (gen++) + ": " + oldName);
          selector.select();
        } catch (IOException e) {
          whatKilledSelectorThread = e;
          LOGGER.log(WARNING, "Failed to select", e);
          abortAll(e);
          return;
        }

        Iterator<SelectionKey> itr = selector.selectedKeys().iterator();
        while (itr.hasNext()) {
          SelectionKey key = itr.next();
          itr.remove();
          Object a = key.attachment();

          if (a instanceof NioTransport) {
            final NioTransport t = (NioTransport) a;

            try {
              if (key.isReadable()) {
                if (t.rb.receive(t.rr()) == -1) {
                  t.closeR();
                }

                final byte[] buf = new byte[2]; // space for reading the chunk header
                int pos = 0;
                int packetSize = 0;
                while (true) {
                  if (t.rb.peek(pos, buf) < buf.length)
                    break; // we don't have enough to parse header
                  int header = ChunkHeader.parse(buf);
                  int chunk = ChunkHeader.length(header);
                  pos += buf.length + chunk;
                  packetSize += chunk;
                  boolean last = ChunkHeader.isLast(header);
                  if (last
                      && pos <= t.rb.readable()) { // do we have the whole packet in our buffer?
                    // read in the whole packet
                    final byte[] packet = new byte[packetSize];
                    int r_ptr = 0;
                    do {
                      int r = t.rb.readNonBlocking(buf);
                      assert r == buf.length;
                      header = ChunkHeader.parse(buf);
                      chunk = ChunkHeader.length(header);
                      last = ChunkHeader.isLast(header);
                      t.rb.readNonBlocking(packet, r_ptr, chunk);
                      packetSize -= chunk;
                      r_ptr += chunk;
                    } while (!last);
                    assert packetSize == 0;
                    if (packet.length > 0) {
                      t.swimLane.submit(
                          new Runnable() {
                            public void run() {
                              t.receiver.handle(packet);
                            }
                          });
                    }
                    pos = 0;
                  }
                }

                if (t.rb.writable() == 0 && t.rb.readable() > 0) {
                  String msg =
                      "Command buffer overflow. Read "
                          + t.rb.readable()
                          + " bytes but still too small for a single command";
                  LOGGER.log(WARNING, msg);
                  // to avoid infinite hang, abort this connection
                  t.abort(new IOException(msg));
                }
                if (t.rb.isClosed()) {
                  // EOF. process this synchronously with respect to packets
                  t.swimLane.submit(
                      new Runnable() {
                        public void run() {
                          // if this EOF is unexpected, report an error.
                          if (!t.getChannel().isInClosed())
                            t.getChannel().terminate(new EOFException());
                        }
                      });
                }
              }
              if (key.isValid() && key.isWritable()) {
                t.wb.send(t.ww());
                if (t.wb.readable() < 0) {
                  // done with sending all the data
                  t.closeW();
                }
              }
              t.reregister();
            } catch (IOException e) {
              LOGGER.log(WARNING, "Communication problem", e);
              t.abort(e);
            } catch (CancelledKeyException e) {
              // see JENKINS-24050. I don't understand how this can happen, given that the selector
              // thread is the only thread that cancels keys. So to better understand what's going
              // on,
              // report the problem.
              LOGGER.log(SEVERE, "Unexpected key cancellation for " + t, e);
              // to be on the safe side, abort the communication. if we don't do this, it's possible
              // that the key never gets re-registered to the selector, and the traffic will hang
              // on this channel.
              t.abort(e);
            }
          } else {
            onSelected(key);
          }
        }
      }
    } catch (ClosedSelectorException e) {
      // end normally
      // TODO: what happens to all the registered ChannelPairs? don't we need to shut them down?
      whatKilledSelectorThread = e;
    } catch (RuntimeException e) {
      whatKilledSelectorThread = e;
      LOGGER.log(WARNING, "Unexpected shutdown of the selector thread", e);
      abortAll(e);
      throw e;
    } catch (Error e) {
      whatKilledSelectorThread = e;
      LOGGER.log(WARNING, "Unexpected shutdown of the selector thread", e);
      abortAll(e);
      throw e;
    } finally {
      selectorThread.setName(oldName);
      selectorThread = null;
      if (whatKilledSelectorThread == null)
        whatKilledSelectorThread = new AssertionError("NioChannelHub shouldn't exit normally");
    }
  }
Exemplo n.º 18
0
    @Override
    public void run() {
      boolean shutdown = false;
      Selector selector = this.selector;
      long lastConnectTimeoutCheckTimeNanos = System.nanoTime();
      for (; ; ) {
        wakenUp.set(false);

        try {
          int selectedKeyCount = selector.select(10);

          // 'wakenUp.compareAndSet(false, true)' is always evaluated
          // before calling 'selector.wakeup()' to reduce the wake-up
          // overhead. (Selector.wakeup() is an expensive operation.)
          //
          // However, there is a race condition in this approach.
          // The race condition is triggered when 'wakenUp' is set to
          // true too early.
          //
          // 'wakenUp' is set to true too early if:
          // 1) Selector is waken up between 'wakenUp.set(false)' and
          //    'selector.select(...)'. (BAD)
          // 2) Selector is waken up between 'selector.select(...)' and
          //    'if (wakenUp.get()) { ... }'. (OK)
          //
          // In the first case, 'wakenUp' is set to true and the
          // following 'selector.select(...)' will wake up immediately.
          // Until 'wakenUp' is set to false again in the next round,
          // 'wakenUp.compareAndSet(false, true)' will fail, and therefore
          // any attempt to wake up the Selector will fail, too, causing
          // the following 'selector.select(...)' call to block
          // unnecessarily.
          //
          // To fix this problem, we wake up the selector again if wakenUp
          // is true immediately after selector.select(...).
          // It is inefficient in that it wakes up the selector for both
          // the first case (BAD - wake-up required) and the second case
          // (OK - no wake-up required).

          if (wakenUp.get()) {
            selector.wakeup();
          }

          processRegisterTaskQueue();

          if (selectedKeyCount > 0) {
            processSelectedKeys(selector.selectedKeys());
          }

          // Handle connection timeout every 10 milliseconds approximately.
          long currentTimeNanos = System.nanoTime();
          if (currentTimeNanos - lastConnectTimeoutCheckTimeNanos >= 10 * 1000000L) {
            lastConnectTimeoutCheckTimeNanos = currentTimeNanos;
            processConnectTimeout(selector.keys(), currentTimeNanos);
          }

          // Exit the loop when there's nothing to handle.
          // The shutdown flag is used to delay the shutdown of this
          // loop to avoid excessive Selector creation when
          // connection attempts are made in a one-by-one manner
          // instead of concurrent manner.
          if (selector.keys().isEmpty()) {
            if (shutdown
                || bossExecutor instanceof ExecutorService
                    && ((ExecutorService) bossExecutor).isShutdown()) {

              synchronized (startStopLock) {
                if (registerTaskQueue.isEmpty() && selector.keys().isEmpty()) {
                  started = false;
                  try {
                    selector.close();
                  } catch (IOException e) {
                    if (logger.isWarnEnabled()) {
                      logger.warn("Failed to close a selector.", e);
                    }

                  } finally {
                    this.selector = null;
                  }
                  break;
                } else {
                  shutdown = false;
                }
              }
            } else {
              // Give one more second.
              shutdown = true;
            }
          } else {
            shutdown = false;
          }
        } catch (Throwable t) {
          if (logger.isWarnEnabled()) {
            logger.warn("Unexpected exception in the selector loop.", t);
          }

          // Prevent possible consecutive immediate failures.
          try {
            Thread.sleep(1000);
          } catch (InterruptedException e) {
            // Ignore.
          }
        }
      }
    }
Exemplo n.º 19
0
 static void releaseTemporarySelector(Selector sel) throws IOException {
   // Selector should be empty
   sel.selectNow(); // Flush cancelled keys
   assert sel.keys().isEmpty() : "Temporary selector not empty";
   localSelectorWrapper.set(null);
 }
Exemplo n.º 20
0
    @Override
    public void run() {
      LOG.debug(getName() + ": starting");
      SERVER.set(Server.this);
      long lastPurgeTime = 0; // last check for old calls.

      while (running) {
        try {
          waitPending(); // If a channel is being registered, wait.
          writeSelector.select(PURGE_INTERVAL);
          Iterator<SelectionKey> iter = writeSelector.selectedKeys().iterator();
          while (iter.hasNext()) {
            SelectionKey key = iter.next();
            iter.remove();
            try {
              if (key.isValid() && key.isWritable()) {
                doAsyncWrite(key);
              }
            } catch (IOException e) {
              LOG.info(getName() + ": doAsyncWrite threw exception " + e);
            }
          }
          long now = System.currentTimeMillis();
          if (now < lastPurgeTime + PURGE_INTERVAL) {
            continue;
          }
          lastPurgeTime = now;
          //
          // If there were some calls that have not been sent out for a
          // long time, discard them.
          //
          ArrayList<Call> calls;

          // get the list of channels from list of keys.
          synchronized (writeSelector.keys()) {
            calls = new ArrayList<Call>(writeSelector.keys().size());
            iter = writeSelector.keys().iterator();
            while (iter.hasNext()) {
              SelectionKey key = iter.next();
              Call call = (Call) key.attachment();
              if (call != null && key.channel() == call.connection.channel) {
                calls.add(call);
              }
            }
          }

          for (Call call : calls) {
            try {
              doPurge(call, now);
            } catch (IOException e) {
              LOG.warn("Error in purging old calls " + e);
            }
          }
        } catch (OutOfMemoryError e) {
          //
          // we can run out of memory if we have too many threads
          // log the event and sleep for a minute and give
          // some thread(s) a chance to finish
          //
          LOG.warn("Out of Memory in server select", e);
          try {
            Thread.sleep(60000);
          } catch (Exception ie) {
          }
        } catch (Exception e) {
          LOG.warn("Exception in Responder " + e.toString());
        }
      }
      LOG.debug("Stopping " + this.getName());

      this.shutDown = true;
    }
Exemplo n.º 21
0
  public void run() {

    while (!stopping) {

      //  Execute any due timers.
      long timeout = execute_timers();

      if (retired) {

        for (SelectableChannel ch : fd_table.keySet()) {
          SelectionKey key = ch.keyFor(selector);
          if (key == null) {
            try {
              key = ch.register(selector, pollset.get(ch));
              key.attach(fd_table.get(ch));
            } catch (ClosedChannelException e) {
              continue;
            }
          } else if (key.isValid()) {
            key.attach(fd_table.get(ch));
            key.interestOps(pollset.get(ch));
          }
        }
        for (SelectionKey key : selector.keys()) {

          if (!fd_table.containsKey(key.channel())) {
            // removed
            key.cancel();
          }
        }
        retired = false;
      }

      //  Wait for events.
      int rc;
      try {
        rc = selector.select(timeout);
      } catch (IOException e) {
        throw new ZError.IOException(e);
      }

      if (rc == 0) continue;

      Iterator<SelectionKey> it = selector.selectedKeys().iterator();
      while (it.hasNext()) {

        SelectionKey key = it.next();
        IPollEvents evt = (IPollEvents) key.attachment();
        it.remove();

        try {
          if (key.isWritable()) {
            evt.out_event();
          }

          if (key.isReadable()) {
            evt.in_event();
          } else if (key.isAcceptable()) {
            evt.accept_event();
          } else if (key.isConnectable()) {
            evt.connect_event();
          }
        } catch (CancelledKeyException e) {
          // channel might have been closed
        }
      }
    }

    stopped = true;
  }
Exemplo n.º 22
0
  @Override
  public void run() {
    thread = Thread.currentThread();

    boolean shutdown = false;
    Selector selector = this.selector;
    for (; ; ) {
      wakenUp.set(false);

      if (CONSTRAINT_LEVEL != 0) {
        selectorGuard.writeLock().lock();
        // This empty synchronization block prevents the selector
        // from acquiring its lock.
        selectorGuard.writeLock().unlock();
      }

      try {
        SelectorUtil.select(selector);

        // 'wakenUp.compareAndSet(false, true)' is always evaluated
        // before calling 'selector.wakeup()' to reduce the wake-up
        // overhead. (Selector.wakeup() is an expensive operation.)
        //
        // However, there is a race condition in this approach.
        // The race condition is triggered when 'wakenUp' is set to
        // true too early.
        //
        // 'wakenUp' is set to true too early if:
        // 1) Selector is waken up between 'wakenUp.set(false)' and
        //    'selector.select(...)'. (BAD)
        // 2) Selector is waken up between 'selector.select(...)' and
        //    'if (wakenUp.get()) { ... }'. (OK)
        //
        // In the first case, 'wakenUp' is set to true and the
        // following 'selector.select(...)' will wake up immediately.
        // Until 'wakenUp' is set to false again in the next round,
        // 'wakenUp.compareAndSet(false, true)' will fail, and therefore
        // any attempt to wake up the Selector will fail, too, causing
        // the following 'selector.select(...)' call to block
        // unnecessarily.
        //
        // To fix this problem, we wake up the selector again if wakenUp
        // is true immediately after selector.select(...).
        // It is inefficient in that it wakes up the selector for both
        // the first case (BAD - wake-up required) and the second case
        // (OK - no wake-up required).

        if (wakenUp.get()) {
          selector.wakeup();
        }

        cancelledKeys = 0;
        processRegisterTaskQueue();
        processEventQueue();
        processWriteTaskQueue();
        processSelectedKeys(selector.selectedKeys());

        // Exit the loop when there's nothing to handle.
        // The shutdown flag is used to delay the shutdown of this
        // loop to avoid excessive Selector creation when
        // connections are registered in a one-by-one manner instead of
        // concurrent manner.
        if (selector.keys().isEmpty()) {
          if (shutdown
              || executor instanceof ExecutorService && ((ExecutorService) executor).isShutdown()) {

            synchronized (startStopLock) {
              if (registerTaskQueue.isEmpty() && selector.keys().isEmpty()) {
                started = false;
                try {
                  selector.close();
                } catch (IOException e) {
                  if (logger.isWarnEnabled()) {
                    logger.warn("Failed to close a selector.", e);
                  }
                } finally {
                  this.selector = null;
                }
                break;
              } else {
                shutdown = false;
              }
            }
          } else {
            // Give one more second.
            shutdown = true;
          }
        } else {
          shutdown = false;
        }
      } catch (Throwable t) {
        if (logger.isWarnEnabled()) {
          logger.warn("Unexpected exception in the selector loop.", t);
        }
        // Prevent possible consecutive immediate failures that lead to
        // excessive CPU consumption.
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          // Ignore.
        }
      }
    }
  }
Exemplo n.º 23
0
  /** Shuntdown this instance by closing its Selector and associated channels. */
  public void shutdown() {
    // If shutdown was called for this SelectorHandler
    if (isShutDown.getAndSet(true)) return;

    stateHolder.setState(State.STOPPED);

    if (selector != null) {
      try {
        boolean isContinue = true;
        while (isContinue) {
          try {
            for (SelectionKey selectionKey : selector.keys()) {
              selectionKeyHandler.close(selectionKey);
            }

            isContinue = false;
          } catch (ConcurrentModificationException e) {
            // ignore
          }
        }
      } catch (ClosedSelectorException e) {
        // If Selector is already closed - OK
      }
    }

    try {
      if (serverSocket != null) {
        serverSocket.close();
        serverSocket = null;
      }
    } catch (Throwable ex) {
      Controller.logger().log(Level.SEVERE, "serverSocket.close", ex);
    }

    try {
      if (serverSocketChannel != null) {
        serverSocketChannel.close();
        serverSocketChannel = null;
      }
    } catch (Throwable ex) {
      Controller.logger().log(Level.SEVERE, "serverSocketChannel.close", ex);
    }

    try {
      if (selector != null) selector.close();
    } catch (Throwable ex) {
      Controller.logger().log(Level.SEVERE, "selector.close", ex);
    }

    if (asyncQueueReader != null) {
      asyncQueueReader.close();
      asyncQueueReader = null;
    }

    if (asyncQueueWriter != null) {
      asyncQueueWriter.close();
      asyncQueueWriter = null;
    }

    selectorHandlerTasks.clear();

    attributes = null;
  }
Exemplo n.º 24
0
  /**
   * Look jvm bug
   *
   * @param before
   * @param selected
   * @param wait
   * @return
   * @throws IOException
   */
  private boolean lookJVMBug(long before, int selected, long wait) throws IOException {
    boolean seeing = false;
    long now = System.currentTimeMillis();

    if (JVMBUG_THRESHHOLD > 0
        && selected == 0
        && wait > JVMBUG_THRESHHOLD
        && now - before < wait / 4
        && !wakenUp.get() /* waken up */
        && !Thread.currentThread().isInterrupted() /* Interrupted */) {
      jvmBug.incrementAndGet();
      if (jvmBug.get() >= JVMBUG_THRESHHOLD2) {
        gate.lock();
        try {
          lastJVMBug = now;
          log.warn(
              "JVM bug occured at "
                  + new Date(lastJVMBug)
                  + ",http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6403933,reactIndex="
                  + reactorIndex);
          if (jvmBug1) {
            log.debug("seeing JVM BUG(s) - recreating selector,reactIndex=" + reactorIndex);
          } else {
            jvmBug1 = true;
            log.info("seeing JVM BUG(s) - recreating selector,reactIndex=" + reactorIndex);
          }
          seeing = true;
          final Selector new_selector = SystemUtils.openSelector();

          for (SelectionKey k : selector.keys()) {
            if (!k.isValid() || k.interestOps() == 0) {
              continue;
            }

            final SelectableChannel channel = k.channel();
            final Object attachment = k.attachment();

            channel.register(new_selector, k.interestOps(), attachment);
          }

          selector.close();
          selector = new_selector;

        } finally {
          gate.unlock();
        }
        jvmBug.set(0);

      } else if (jvmBug.get() == JVMBUG_THRESHHOLD || jvmBug.get() == JVMBUG_THRESHHOLD1) {
        if (jvmBug0) {
          log.debug("seeing JVM BUG(s) - cancelling interestOps==0,reactIndex=" + reactorIndex);
        } else {
          jvmBug0 = true;
          log.info("seeing JVM BUG(s) - cancelling interestOps==0,reactIndex=" + reactorIndex);
        }
        gate.lock();
        seeing = true;
        try {
          for (SelectionKey k : selector.keys()) {
            if (k.isValid() && k.interestOps() == 0) {
              k.cancel();
            }
          }
        } finally {
          gate.unlock();
        }
      }
    } else {
      jvmBug.set(0);
    }
    return seeing;
  }