Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8011538

java.nio.channels.Selector select is spinning for OP_READ

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P3 P3
    • None
    • 7
    • core-libs
    • None

      FULL PRODUCT VERSION :
      java version " 1.7.0_09 "
      Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
      Java HotSpot(TM) Server VM (build 23.5-b02, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      SunOS sundev31 5.10 144488-05 sun4v sparc SUNW,T5240

      A DESCRIPTION OF THE PROBLEM :
      It seems there was a previous issue with epoll spinning, for which the suggested workaround was to thrash the sector and create a new one and fix was available for Java 7. Is the fix available for all platforms ?



      REGRESSION. Last worked in version 6u31

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Create a selector
      2. Register OP_CONNECT, if AsyncSocket.connect() returned false
      3. After connection gets created, unregister OP_CONNECT
      4. Register OP_READ
      5. The selector starts spining


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      // TimeClient.java [Connects and registers OP_READ]
      import java.io.IOException;
      import java.net.InetAddress;
      import java.net.InetSocketAddress;
      import java.net.SocketAddress;
      import java.nio.ByteBuffer;
      import java.nio.channels.ReadableByteChannel;
      import java.nio.channels.SelectionKey;
      import java.nio.channels.Selector;
      import java.nio.channels.SocketChannel;
      import java.util.Iterator;
      import java.util.Set;

      public class TimeClient implements Runnable {
          private static final int READ_BUFFER_SIZE = 0x100000;

          private ByteBuffer d_readBuf = ByteBuffer.allocateDirect(READ_BUFFER_SIZE); // 1Mb

          private final Thread d_thread = new Thread(this);
          private SocketAddress d_address;

          private Selector d_selector;
          private SocketChannel d_channel;

          public TimeClient() {
              try {
                  d_address = new InetSocketAddress(InetAddress.getLocalHost(), 38900);
              }
              catch(Exception e) {
                  e.printStackTrace();
              }

          }

          public void start() throws IOException {
              System.out.println( " starting event loop " );
              d_thread.start();
          }

          public void stop() throws IOException, InterruptedException {
              System.out.println( " stopping event loop " );
              d_thread.interrupt();
              d_selector.wakeup();
              d_thread.join();
          }

          public void run() {
              System.out.println( " event loop running " );
              try {
                  d_selector = Selector.open();
                  d_channel = SocketChannel.open();
                  d_channel.configureBlocking(false);
                  d_channel.socket().setTcpNoDelay(true); // disable nagle

                  if (d_channel.connect(d_address)) {
                      processConnect(true);
                  }
                  d_channel.register(d_selector, SelectionKey.OP_CONNECT);

                  while(!d_thread.isInterrupted() && d_channel.isOpen()) {
                      int numSelectedKeys = d_selector.select();
                      System.out.println( " Spinning ? " );

                      if (numSelectedKeys > 0) {
                          processSelectedKeys(d_selector.selectedKeys());
                      }
                  }
              } catch (Exception e) {
                      e.printStackTrace();
              } finally {
                  try {
                  d_channel.close();
                  d_selector.close();
                  }
                  catch (IOException e) {
                      System.out.println(e);
                  }
                  System.out.println( " connection closed " );
              }
              System.out.println( " event loop terminated " );
          }

          private void processSelectedKeys(Set<SelectionKey> keys) throws Exception {
              Iterator<SelectionKey> itr = keys.iterator();
              while (itr.hasNext()) {
                  SelectionKey key = itr.next();
                  if (key.isReadable()) {
                      processRead(key);
                  }
                  else if (key.isConnectable()) {
                      processConnect(false);
                  }
                  else {
                      System.out.println( " Un-interested key selected " );
                  }
                  itr.remove();
              }
          }

          private void processConnect(boolean connectComplete) throws Exception {
              SelectionKey key = d_channel.keyFor(d_selector);
              if (connectComplete) {
                  System.out.println( " ConnectComplete Immediately " + connectComplete);
                  d_channel.register(d_selector, SelectionKey.OP_READ);
              }
              else if (d_channel.finishConnect()) {
                  System.out.println( " connected to " + d_address);
                  key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT);
                  key.interestOps(key.interestOps() | SelectionKey.OP_READ);
              }
          }

          private void processRead(SelectionKey key) throws Exception {
              ReadableByteChannel ch = (ReadableByteChannel)key.channel();

              int bytesOp = 0, bytesTotal = 0;
              while (d_readBuf.hasRemaining() && (bytesOp = ch.read(d_readBuf)) > 0) {
      bytesTotal += bytesOp;
      }

              if (bytesTotal > 0) {
                  d_readBuf.flip();
                  // do something with data
                  d_readBuf.compact();
              }
              else if (bytesOp == -1) {
                  System.out.println( " peer closed read channel " );
                  ch.close();
              }
          }

          public static void main(String[] args) throws Exception {
              final TimeClient client = new TimeClient();
              try {
                  client.start();
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }


      // TimeServer.java Sample implementation [Just used for connecting]
      import java.io.*;
      import java.nio.*;
      import java.nio.channels.*;
      import java.nio.channels.spi.*;
      import java.net.*;
      import java.util.*;

      // Listen on a port for connections and write back the current time.
      public class TimeServer {
          private static final int DEFAULT_TIME_PORT = 38900;

          // Constructor with no arguments creates a time server on default port.
          public TimeServer() throws Exception {
      acceptConnections(this.DEFAULT_TIME_PORT);
          }

          // Constructor with port argument creates a time server on specified port.
          public TimeServer(int port) throws Exception {
      acceptConnections(port);
          }

          // Accept connections for current time. Lazy Exception thrown.
          private static void acceptConnections(int port) throws Exception {
              // Selector for incoming time requests
              Selector acceptSelector = SelectorProvider.provider().openSelector();
              System.out.println( " Coming here 1 " );

              // Create a new server socket and set to non blocking mode
              ServerSocketChannel ssc = ServerSocketChannel.open();
              ssc.configureBlocking(false);

              // Bind the server socket to the local host and port
      // Bind the server socket to the local host and port

              InetAddress lh = InetAddress.getLocalHost();
              InetSocketAddress isa = new InetSocketAddress(lh, port);
              ssc.socket().bind(isa);
              System.out.println( " Coming here 2 " + isa);

      // Register accepts on the server socket with the selector. This
      // step tells the selector that the socket wants to be put on the
      // ready list when accept operations occur, so allowing multiplexed
      // non-blocking I/O to take place.
      SelectionKey acceptKey = ssc.register(acceptSelector,
            SelectionKey.OP_ACCEPT);

      int keysAdded = 0;
              System.out.println( " Coming here 3 " );

      // Here's where everything happens. The select method will
      // return when any operations registered above have occurred, the
      // thread has been interrupted, etc.
      while ((keysAdded = acceptSelector.select()) > 0) {
          // Someone is ready for I/O, get the ready keys
          Set readyKeys = acceptSelector.selectedKeys();
          Iterator i = readyKeys.iterator();

                  System.out.println( " Coming here 4 " );
          // Walk through the ready keys collection and process date requests.
          while (i.hasNext()) {
      SelectionKey sk = (SelectionKey)i.next();
      i.remove();
      // The key indexes into the selector so you
      // can retrieve the socket that's ready for I/O
      ServerSocketChannel nextReady =
          (ServerSocketChannel)sk.channel();
      // Accept the date request and send back the date string
      Socket s = nextReady.accept().socket();
      // Write the current time to the socket
                      PrintWriter out = new PrintWriter(s.getOutputStream(), true);
                      Date now = new Date();
                      out.println(now);
                      out.close();
                  }
              }
          }

          // Entry point.
          public static void main(String[] args) {
              try {
                      TimeServer t = new TimeServer();
              } catch(Exception e) {
                      e.printStackTrace();
              }
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Destroying the current selector and creating a new one (and registering OP_CONNECT) fixes the problem

            alanb Alan Bateman
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: