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

(so) Async close of socket stream fails when timeout specified

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • 6
    • 1.4.1
    • core-libs
    • b33
    • x86, sparc
    • linux, solaris, windows_nt



      Name: nt126004 Date: 07/31/2002


      FULL PRODUCT VERSION :
      java version "1.4.1-beta"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-beta-b14)
      Java HotSpot(TM) Client VM (build 1.4.1-beta-b14, mixed mode)

      FULL OPERATING SYSTEM VERSION :
      Windows NT Version 4.0

      A DESCRIPTION OF THE PROBLEM :
      Let S be a socket created from an NIO channel, with a
      SO_TIMEOUT value of T. Say that a thread T1 is blocked in a
      call to S.getInputStream().read(). If another thread T2
      calls S.close(), T1's call to read() should terminate
      immediately and throw an IOException.

      However, this does not happen with Java 1.4.1-beta or 1.4.0.
       Instead, T1's call to read() does not return for a full T
      milliseconds, and then it throws CancelledKeyException. So
      there are really two problems: read() terminates too slowly
      and then throws an unexpected exception.

      The bug happens on Windows NT and Linux. Have not tried
      other platforms. It does not happen if the Socket is not
      created from a channel. Nor does it happen if SO_TIMEOUT is
      not set.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the attached program. You will need an internet
      connection to contact the named web server.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      The attached program should generate the following output,
      modulo a few timing changes:

        Thread1: opening connection
        Thread1: starting read w/timeout
                              Thread2: closing socket
                              Thread2: socket closed
        Thread1: connection closed
        Thread1: terminating after 74 msecs

      Instead it prints the following:

        Thread1: opening connection
        Thread1: starting read w/timeout
                              Thread2: closing socket
                              Thread2: socket closed
        Thread1: terminating after 3074 msecs
        ******UNEXPECTED EXCEPTION!******
      java.nio.channels.CancelledKeyException
              at
      sun.nio.ch.SelectionKeyImpl.ensureValid(SelectionKeyImpl.java:55)
              at
      sun.nio.ch.SelectionKeyImpl.readyOps(SelectionKeyImpl.java:77)
              at
      java.nio.channels.SelectionKey.isReadable(SelectionKey.java:271)
              at
      sun.nio.ch.SocketAdaptor$SocketInputStream.read(SocketAdaptor.java:186)
              at
      sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:86)
              at java.io.InputStream.read(InputStream.java:88)
              at
      sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:64)
              at
      CloseInterruptsReadTest.startConnection(CloseInterruptsReadTest.java:39)
              at
      CloseInterruptsReadTest.main(CloseInterruptsReadTest.java:16)

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
        To repeat the above exception (hopefully without line wrapping):

      java.nio.channels.CancelledKeyException
              at sun.nio.ch.SelectionKeyImpl.ensureValid(SelectionKeyImpl.java:55)
              at sun.nio.ch.SelectionKeyImpl.readyOps(SelectionKeyImpl.java:77)
              at java.nio.channels.SelectionKey.isReadable(SelectionKey.java:271)
              at sun.nio.ch.SocketAdaptor$SocketInputStream.read(SocketAdaptor.java:186)
              at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:86)
              at java.io.InputStream.read(InputStream.java:88)
              at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:64)
              at CloseInterruptsReadTest.startConnection(CloseInterruptsReadTest.java:39)
              at CloseInterruptsReadTest.main(CloseInterruptsReadTest.java:16)

      Also, it's worth noting that I once got a NullPointerException in the call to
      read. This may be a distinct bug; I am still struggling to repeat it.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.nio.*;
      import java.net.*;
      public class CloseInterruptsReadTest {
          private static Socket _socket=null;

          public static void main(String args[]) {
              try {
                  startKillerThread();
                  startConnection();
              } catch (Exception e) {
                  System.err.println("******UNEXPECTED EXCEPTION!******");
                  e.printStackTrace();
              }
          }
          
          /** Synchronously connects to server and starts a read. Blocking. */
          private static void startConnection() throws IOException {
              //Create connection to arbitrary server using channels. Here we use an
              //HTTP server, because it won't send data until it gets a proper GET
              //request. Make connection blocking, with timeouts.
              System.out.println("Thread1: opening connection");
              SocketAddress addr=new InetSocketAddress("www.limewire.com", 80);
              SocketChannel channel=SocketChannel.open(addr);
              _socket=channel.socket();
              _socket.setSoTimeout(3000);
              InputStream in=_socket.getInputStream();

              //Now start a read.
              System.out.println("Thread1: starting read w/timeout");
              long start=System.currentTimeMillis();
              try {
                  int b=in.read();
              } catch (IOException e) {
                  System.out.println("Thread1: connection closed");
                  return;
              } finally {
                  long elapsed=System.currentTimeMillis()-start;
                  System.out.println("Thread1: terminating after "+elapsed+" msecs");
              }
          }

          /** Starts a thread to close connection created by startConnection.
           * Does not block. */
          private static void startKillerThread() {
              KillerThread thread=new KillerThread();
              thread.start();
          }

          private static class KillerThread extends Thread {
              public void run() {
                  //Busy wait for read() to start.
                  while (_socket==null) { }
                  try { Thread.sleep(100); } catch (InterruptedException e) { }
                  //Now close connection
                  System.out.println("\t\t\t\t\tThread2: closing socket");
                  try {
                      _socket.close();
                      System.out.println("\t\t\t\t\tThread2: socket closed");
                  } catch (IOException e) {
                      System.err.println("\t\t\t\t\tThread2: couldn't kill!");
                  }
              }
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER WORKAROUND :
      We can catch CancelledKeyException and treat it like
      IOException. That doesn't take care of the timing issue,
      but that's only a minor performance problem in our application.
      (Review ID: 160054)
      ======================================================================

            sherman Xueming Shen
            nthompsosunw Nathanael Thompson (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: