United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6596323 (fc) ClosedByInterruptException not thrown by the interrupt method (lnx)
JDK-6596323 : (fc) ClosedByInterruptException not thrown by the interrupt method (lnx)

Details
Type:
Bug
Submit Date:
2007-08-23
Status:
Closed
Updated Date:
2011-05-18
Project Name:
JDK
Resolved Date:
2011-05-18
Component:
core-libs
OS:
linux
Sub-Component:
java.nio
CPU:
x86
Priority:
P2
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Backport:
Backport:
Relates:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.6.0_02"
Java(TM) SE Runtime Environment (build 1.6.0_02-b05)
Java HotSpot(TM) Client VM (build 1.6.0_02-b05, mixed mode, sharing)


ADDITIONAL OS VERSION INFORMATION :
Linux hostname 2.6.17-11-386 #2 Fri May 18 23:37:00 UTC 2007 i686 GNU/Linux

Ubuntu 6.10

A DESCRIPTION OF THE PROBLEM :
I have implemented a timeout for the thread blocking on the I/O operation using InterruptableChannel interface. It works just fine with jdk 1.5.0_10. The ClosedByInterruptException is thrown and caught (please see the sample code below)
However, on Java 6 it seems like the the blocked thread never receives the ClosedByInterruptException.

If the read is attempeted after the interrupt then the ClosedChannelException is thrown and the thread is stopped. However if no read happens the thread blocks for ever.



STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the code provided below.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Start
user input
Read line:'user input'
INTERRUPTING
LEAVING java.nio.channels.ClosedByInterruptException

ACTUAL -
Start
user input 1
Read line:'user input 1'
INTERRUPTING


However if I try yet another "user input" AFTER the interrupt, I get:

Start
user input
Read line:'user input'
INTERRUPTING
user input 2
Read line:'user input 2'
LEAVING java.nio.channels.ClosedChannelException


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.io.BufferedReader;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.nio.channels.Channels;

public class InterruptInput {
    
    public static void main(String args[]) {
        try {
        	
        	BufferedReader in = new BufferedReader(
                    new InputStreamReader(
                    Channels.newInputStream(
                    (new FileInputStream(FileDescriptor.in)).getChannel())));
            
            System.out.println("Start");
            // interrupt input in 10 sec
            (new TimeOut()).start();
            String line = null;
            while ((line = in.readLine()) != null) {
                System.out.println("Read line:'"+line+"'");
            }
        } catch (Exception ex) {
            System.out.println("LEAVING " + ex.toString());
        }
    }
    
    public static class TimeOut extends Thread {
        
        Thread threadToInterrupt = null;
        public TimeOut() {
            // interrupt thread that creates this TimeOut.
            threadToInterrupt = Thread.currentThread();
            setDaemon(true);
        }
        
        public void run() {
            try {
                sleep(10000);
            } catch(InterruptedException ex) {/*ignore*/}
            System.out.println("INTERRUPTING");
            threadToInterrupt.interrupt();
        }
    }
}
---------- END SOURCE ----------

Release Regression From : 5.0
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.

                                    

Comments
EVALUATION

There is indeed a regression here. The close mechanism records the thread ID of threads doing I/O so they can be interrupted. It appears the changes for 6285901 changed this so that negative thread IDs are not recorded. This bug has gone unnoticed because a read from a FileChannel does not normally block indefinitely.
                                     
2007-08-23
EVALUATION

The regression is also why there is a difference between the "spec" and implementation as observed by Martin here:
  http://mail.openjdk.java.net/pipermail/core-libs-dev/2008-April/000317.html
That is, the original intent was the thread id was to be used to signal a blocked thread on Linux. The changes in 6285901 change the semantics so that a non-zero value means there is a reader or writer thread.
                                     
2008-04-06
EVALUATION

The plan is to fix this in jdk7 and let it bake for a while before considering it for a jdk6 update.
                                     
2008-05-23
SUGGESTED FIX

$ diff -r cbd182c404d8 src/share/classes/sun/nio/ch/NativeThreadSet.java
--- a/src/share/classes/sun/nio/ch/NativeThreadSet.java Fri May 23 11:13:45 2008 -0700
+++ b/src/share/classes/sun/nio/ch/NativeThreadSet.java Thu May 29 16:13:26 2008 +0100
@@ -43,7 +43,7 @@ class NativeThreadSet {
     //
     int add() {
         long th = NativeThread.current();
-        if (th <= 0)
+        if (th == -1)
             return -1;
         synchronized (this) {
             int start = 0;
diff -r cbd182c404d8 src/solaris/classes/sun/nio/ch/NativeThread.java
--- a/src/solaris/classes/sun/nio/ch/NativeThread.java  Fri May 23 11:13:45 2008 -0700
+++ b/src/solaris/classes/sun/nio/ch/NativeThread.java  Thu May 29 16:13:26 2008 +0100
@@ -41,7 +41,7 @@ class NativeThread {

     // Returns an opaque token representing the native thread underlying the
     // invoking Java thread.  On systems that do not require signalling, this
-    // method always returns zero.
+    // method always return -1.
     //
     static native long current();

diff -r cbd182c404d8 src/windows/classes/sun/nio/ch/NativeThread.java
--- a/src/windows/classes/sun/nio/ch/NativeThread.java  Fri May 23 11:13:45 2008 -0700
+++ b/src/windows/classes/sun/nio/ch/NativeThread.java  Thu May 29 16:13:26 2008 +0100
@@ -31,7 +31,7 @@ package sun.nio.ch;

 class NativeThread {

-    static long current() { return 0; }
+    static long current() { return -1; }

     static void signal(long nt) { }

diff -r cbd182c404d8 test/java/nio/channels/AsyncCloseAndInterrupt.java
--- a/test/java/nio/channels/AsyncCloseAndInterrupt.java        Fri May 23 11:13:45 2008 -0700
+++ b/test/java/nio/channels/AsyncCloseAndInterrupt.java        Thu May 29 16:13:26 2008 +0100
@@ -22,7 +22,7 @@
  */

 /* @test
- * @bug 4460583 4470470 4840199 6419424
+ * @bug 4460583 4470470 4840199 6419424 6596323
  * @summary Comprehensive test of asynchronous closing and interruption
  * @author Mark Reinhold
  */
                                     
2008-05-29



Hardware and Software, Engineered to Work Together