JDK-4648468 : (ch) Asynchronous closing and interruption generally broken
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 1.4.0
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2002-03-06
  • Updated: 2002-03-23
  • Resolved: 2002-03-23
Related Reports
Duplicate :  
Description

Name: nt126004			Date: 03/06/2002


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

FULL OPERATING SYSTEM VERSION :

Microsoft Windows 2000 [Version 5.00.2195]

ADDITIONAL OPERATING SYSTEMS :

A DESCRIPTION OF THE PROBLEM :
NOTE: This seems to be a regression bug, since it worked
correctly in Merlin-beta3 (build 1.4.0-beta3-b84). Since
1.4RC and now in 1.4.0, it is not working.

When using a DatagramChannel is it not possible to
asynchronously interrupt or close it. Accourding to the
specifications, if interrupt() is called on the channel's
thread, a java.nio.channels.ClosedByInterruptException
should be thrown. And if the channel's close() method is
called a java.nio.channels.AsynchronousCloseException
should be called. Neither of these work.

The thread dump of the sample program exhibithing this
incorrect behaviour clearly shows that the DatagramChannel
is blocked on a receive, and the main thread is blocked
trying to kill it:

Full thread dump Java HotSpot(TM) Client VM (1.4.0-b92
mixed mode):

"Channel Thread" prio=5 tid=0x0AAFDA60 nid=0x2328 runnable
[ae8f000..ae8fdb4]
        at sun.nio.ch.DatagramChannelImpl.receive0(Native
Method)
        at
sun.nio.ch.DatagramChannelImpl.receiveIntoNativeBuffer
(DatagramChanne
lImpl.java:173)
        at sun.nio.ch.DatagramChannelImpl.receive
(DatagramChannelImpl.java:159)
        at sun.nio.ch.DatagramChannelImpl.receive
(DatagramChannelImpl.java:116)
        - locked <02A06D08> (a java.lang.Object)
        at Client$1.run(Client.java:37)

"Signal Dispatcher" daemon prio=10 tid=0x008E3620
nid=0x2354 waiting on monitor
[0..0]

"Finalizer" daemon prio=9 tid=0x0AA90D60 nid=0x2168 waiting
on monitor [ad4f000.
.ad4fdb4]
        at java.lang.Object.wait(Native Method)
        - waiting on <02A80138> (a
java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove
(ReferenceQueue.java:111)
        - locked <02A80138> (a
java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove
(ReferenceQueue.java:127)
        at java.lang.ref.Finalizer$FinalizerThread.run
(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=0x0AA90160
nid=0x2284 waiting on monitor
[ad0f000..ad0fdb4]
        at java.lang.Object.wait(Native Method)
        - waiting on <02A801A0> (a
java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:426)
        at java.lang.ref.Reference$ReferenceHandler.run
(Reference.java:113)
        - locked <02A801A0> (a java.lang.ref.Reference$Lock)

"main" prio=5 tid=0x00234A10 nid=0x22fc waiting for monitor
entry [6f000..6fc3c]

        at sun.nio.ch.DatagramChannelImpl.kill
(DatagramChannelImpl.java:492)
        - waiting to lock <02A06D08> (a java.lang.Object)
        at
sun.nio.ch.DatagramChannelImpl.implCloseSelectableChannel
(DatagramCha
nnelImpl.java:487)
        at
java.nio.channels.spi.AbstractSelectableChannel.implCloseCha
nnel(Abst
ractSelectableChannel.java:202)
        at
java.nio.channels.spi.AbstractInterruptibleChannel$1.interru
pt(Abstra
ctInterruptibleChannel.java:147)
        - locked <02A06CF0> (a java.lang.Object)
        at java.lang.Thread.interrupt(Thread.java:741)
        at Client.<init>(Client.java:60)
        at Client.main(Client.java:71)

"VM Thread" prio=5 tid=0x0094F460 nid=0x2344 runnable

"VM Periodic Task Thread" prio=10 tid=0x008E22D0 nid=0x2340
waiting on monitor
"Suspend Checker Thread" prio=10 tid=0x008E2C60 nid=0x2360
runnable

REGRESSION.  Last worked in version 1.4

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
USE JDK 1.4.0

1. Create a thread that opens a datagram channel and
receives from it
2. From another thread attempt to close the channel or
interrupt the thread
3. the threads lock: the datagram channel thread is blocked
on i/o, and the other thread is blocked on trying to kill
the channel

Using the provided code, execute Client.java

EXPECTED VERSUS ACTUAL BEHAVIOR :
Depending on the closing method the expected results are:

java.nio.channels.AsynchronousCloseException
        at java.nio.channels.spi.AbstractChannel.end
(AbstractChannel.java:184)
        at sun.nio.ch.DatagramChannelImpl.receive
(DatagramChannelImpl.java:140)
        at Client$1.run(Client.java:36)

-or-

java.nio.channels.ClosedByInterruptException
        at java.nio.channels.spi.AbstractChannel.end
(AbstractChannel.java:183)
        at sun.nio.ch.DatagramChannelImpl.receive
(DatagramChannelImpl.java:140)
        at Client$1.run(Client.java:37)

Actual Results:
-no exceptions-

This bug can be reproduced always.

---------- BEGIN SOURCE ----------
//---- Client.java  ---

import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.net.*;

public class Client
{
  DatagramChannel channel;
  Client()
  {
    try
    {
	channel = DatagramChannel.open();
	ByteBuffer buf = ByteBuffer.allocate(1000);
	buf.put("This is a datagram message".getBytes());
	buf.flip();
	final InetSocketAddress address = new InetSocketAddress
                                                  ("225.100.10.101",8099);
        // send the datagram message
	channel.send(buf, address);
	
        // create a new thread the wait for the responses
	Thread t = new Thread()
	{
	  private Charset charset = Charset.forName("US-ASCII");
  	  private CharsetDecoder decoder = charset.newDecoder();
	  ByteBuffer buf2 = ByteBuffer.allocate(1000);
					
	  public void run()
	  {
	  	boolean interruptedOrClosed = false;
                // keep trying till this flag is set
		while(!interruptedOrClosed)
		{
		  try
		  {
		     buf2.clear();
                      
                     // even if we set the socket timeout, it doesn't work
		     // channel.socket().setSoTimeout(2000);
                 
		     System.out.println("thread waiting to recieve...");
		     channel.receive(buf2);
                     // if a server responds
		     System.out.println("waiting thread received something");
								buf2.flip();
	     	     System.out.println(decoder.decode(buf2).toString());
		  }
		  catch(Exception e)
		  {
			System.out.println("Some Exception");
                        // should be AsynchronousClose or ClosedByInterrupt
                        // depending on call made below
			e.printStackTrace();
			interruptedOrClosed = true;
		  }
		}
	    }
	};

        // start the thread to wait for a response
	t.start();

        // we will sleep and on awakening try to stop the waiting thread
	System.out.println("main thread sleeping for 2s");
	Thread.sleep(2000);

        // either use the close() or interrupt() way, comment out one or the
        // other to see that both work.

	//System.out.println("attempting to close channel");
	//channel.close();

	System.out.println("attempting to interrupt inner thread");
	t.interrupt();
     }
     catch(Exception e)
     {
	e.printStackTrace();
     }
     System.out.println("Main thread complete");
  }
	
  public static void main (String[] args)
  {
	new Client();
  }
	
}

//--- End of Client.java ---

==============================================================================
// if you want to run the server, here is a quick server that
// should respond once

// -- Server.java --
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.net.*;

public class Server
{
	MulticastSocket socket;
	private Charset charset = Charset.forName("US-ASCII");
	private CharsetDecoder decoder = charset.newDecoder();

	Server()
	{
		try
		{
		InetAddress group = InetAddress.getByName("225.100.10.101");
		socket = new MulticastSocket(8099);
		socket.joinGroup(group);
		byte[] buf = new byte[1000];
		DatagramPacket recv = new DatagramPacket(buf, buf.length);
		socket.receive(recv);
		System.out.println("Received: " + new String(recv.getData
()).trim());
		InetAddress sender = recv.getAddress();
		String reply = "This is a reply";
		DatagramPacket send = new DatagramPacket(reply.getBytes(),
reply.length() ,recv.getAddress(), recv.getPort());
		socket.send(send);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		
	}
	
	public static void main (String[] args)
	{
		new Server();
	}

}
// -- End of Server.java --
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
Not use latest version of 1.4, but keep using Merlin-beta3

Release Regression From : merlin-beta3
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

(Review ID: 139763) 
======================================================================