Ejemplo n.º 1
0
  private boolean scheduleWriteIfNecessary(final SctpChannelImpl channel) {
    final Thread currentThread = Thread.currentThread();
    final Thread workerThread = thread;
    if (currentThread != workerThread) {
      if (channel.writeTaskInTaskQueue.compareAndSet(false, true)) {
        boolean offered = writeTaskQueue.offer(channel.writeTask);
        assert offered;
      }

      if (!(channel instanceof SctpAcceptedChannel)
          || ((SctpAcceptedChannel) channel).bossThread != currentThread) {
        final Selector workerSelector = selector;
        if (workerSelector != null) {
          if (wakenUp.compareAndSet(false, true)) {
            workerSelector.wakeup();
          }
        }
      } else {
        // A write request can be made from an acceptor thread (boss)
        // when a user attempted to write something in:
        //
        //   * channelOpen()
        //   * channelBound()
        //   * channelConnected().
        //
        // In this case, there's no need to wake up the selector because
        // the channel is not even registered yet at this moment.
      }

      return true;
    }

    return false;
  }
Ejemplo n.º 2
0
    @Override
    public void run() {
      final Thread currentThread = Thread.currentThread();

      channel.shutdownLock.lock();
      try {
        for (; ; ) {
          try {
            if (selector.select(500) > 0) {
              selector.selectedKeys().clear();
            }

            SctpChannel acceptedSocket = channel.serverChannel.accept();
            if (acceptedSocket != null) {
              registerAcceptedChannel(acceptedSocket, currentThread);
            }
          } catch (SocketTimeoutException e) {
            // Thrown every second to get ClosedChannelException
            // raised.
          } catch (CancelledKeyException e) {
            // Raised by accept() when the server socket was closed.
          } catch (ClosedSelectorException e) {
            // Raised by accept() when the server socket was closed.
          } catch (ClosedChannelException e) {
            // Closed as requested.
            break;
          } catch (Throwable e) {
            if (logger.isWarnEnabled()) {
              logger.warn("Failed to accept a connection.", e);
            }
            try {
              Thread.sleep(1000);
            } catch (InterruptedException e1) {
              // Ignore
            }
          }
        }
      } finally {
        channel.shutdownLock.unlock();
        closeSelector();
      }
    }
Ejemplo n.º 3
0
  void setInterestOps(SctpChannelImpl channel, ChannelFuture future, int interestOps) {
    boolean changed = false;
    try {
      // interestOps can change at any time and at any thread.
      // Acquire a lock to avoid possible race condition.
      synchronized (channel.interestOpsLock) {
        Selector selector = this.selector;
        SelectionKey key = channel.channel.keyFor(selector);

        if (key == null || selector == null) {
          // Not registered to the worker yet.
          // Set the rawInterestOps immediately; RegisterTask will pick it up.
          channel.setRawInterestOpsNow(interestOps);
          return;
        }

        // Override OP_WRITE flag - a user cannot change this flag.
        interestOps &= ~Channel.OP_WRITE;
        interestOps |= channel.getRawInterestOps() & Channel.OP_WRITE;

        switch (CONSTRAINT_LEVEL) {
          case 0:
            if (channel.getRawInterestOps() != interestOps) {
              key.interestOps(interestOps);
              if (Thread.currentThread() != thread && wakenUp.compareAndSet(false, true)) {
                selector.wakeup();
              }
              changed = true;
            }
            break;
          case 1:
          case 2:
            if (channel.getRawInterestOps() != interestOps) {
              if (Thread.currentThread() == thread) {
                key.interestOps(interestOps);
                changed = true;
              } else {
                selectorGuard.readLock().lock();
                try {
                  if (wakenUp.compareAndSet(false, true)) {
                    selector.wakeup();
                  }
                  key.interestOps(interestOps);
                  changed = true;
                } finally {
                  selectorGuard.readLock().unlock();
                }
              }
            }
            break;
          default:
            throw new Error();
        }

        if (changed) {
          channel.setRawInterestOpsNow(interestOps);
        }
      }

      future.setSuccess();
      if (changed) {
        fireChannelInterestChanged(channel);
      }
    } catch (CancelledKeyException e) {
      // setInterestOps() was called on a closed channel.
      ClosedChannelException cce = new ClosedChannelException();
      future.setFailure(cce);
      fireExceptionCaught(channel, cce);
    } catch (Throwable t) {
      future.setFailure(t);
      fireExceptionCaught(channel, t);
    }
  }
Ejemplo n.º 4
0
 static boolean isIoThread(SctpChannelImpl channel) {
   return Thread.currentThread() == channel.worker.thread;
 }
Ejemplo n.º 5
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.
        }
      }
    }
  }
    @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.
          }
        }
      }
    }