This is the mail archive of the java@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Unblocking blocked I/O


David Vrabel wrote:

>Yeah.  I found that discussion.  So much for the claimed cross-platform
>compatibility...
>
>>Unblocking I/O by closing a socket (resource revocation), however,
>>should work, and its a bug if it doesn't. Do you have a test case?
>>
>Yes.  It's perhaps a bit long but find it attached. Hmm.  Attachments are
>okay aren't they?
>
Thanks. I tried this on both Sun's Linux 1.3.1 JDK and IBM's Linux JDK 
1.3.0.

Sun's JDK appears to implement neither behaviour - both 
thread.interrupt() and socket.close() have no effect. On the IBM JDK, 
socket.close() has no effect but thread.interrupt() does cause the 
reading thread to unblock with an InterruptedIOException.

Here's a note from the 1.4 beta API docs (from java.nio.channels.Channel):

> That channels are asynchronously closeable and interruptible arises 
> from the practical need to be able to break threads out of blocking 
> I/O operations.
>
> The java.io 
> <http://waitaki/docs/jdk1.4/docs/api/java/io/package-summary.html> 
> package specifies an | InterruptedIOException| 
> <http://waitaki/docs/jdk1.4/docs/api/java/io/InterruptedIOException.html> 
> for this purpose, the idea being that invoking a thread's | interrupt| 
> <http://waitaki/docs/jdk1.4/docs/api/java/lang/Thread.html#interrupt%28%29> 
> method will cause the thread to break out of a blocking I/O operation 
> and receive this exception. Unfortunately this approach has turned out 
> to be impossible to implement both efficiently and reliably on most 
> popular operating systems, and in fact it is well known not to work 
> uniformly across different implementations of the Java platform.
>
> A technique that does work, however, is to close the file descriptor 
> or handle that is the subject of the operation in which the target 
> thread is blocked. Despite the fact that this closes the corresponding 
> stream or channel, this behavior is often acceptable because the most 
> common reason for interrupting a thread is to ask it to shut down. It 
> is also difficult in practice to write systems that deal gracefully at 
> a high level with partly-completed I/O operations; it is often simply 
> easier to discard a stream or channel that's in an unknown state and 
> recover in some other way, /e.g./, by opening a new connection. Hence 
> this technique has come to be known as a portable workaround for the 
> lack of true interruptible I/O in the java.io 
> <http://waitaki/docs/jdk1.4/docs/api/java/io/package-summary.html> 
> package.
>
So the docs are advocating the method that does not work on the Linux JDK's.

Ideally, in libgcj we should probibly implement both, but persumably 
interrupt on close() is unimplemented (in the JDKs) because it is hard 
to do on Linux: a close() on a file descriptor does not cause another 
thread reading from that FD to unblock. We could implement this by 
recording the current thread ID upon entry to read() etc, and have 
close() set a flag and signal the reading thread. This would add some 
overhead to every IO call (cost of looking up the current thread). I 
don't know what sort of impact that would have on networking 
performance, but if its insignificant then why havn't the other Linux 
implementations done it?

It is easy to implement thread.interrupt() for IO however - this patch, 
which I will check in, should give us similar behaviour to the IBM Linux 
JDK. Hopefully the whole problem will go away when we implement java.nio 
anyway because that gives us non-blocking IO as well as clearly defined 
interrupt semantics.

regards

Bryce.

2001-09-20  Bryce McKinlay  <bryce@waitaki.otago.ac.nz>

	* posix-threads.cc (_Jv_ThreadInterrupt): Enable interrupt of 
	blocking IO via pthread_kill().
	* java/io/natFileDescriptorPosix.cc (write (jint)): Check for thread 
	interrupted status flag only if ::write returned an error.
	(write (jbyteArray, jint, jint): Likewise.
	(read (jint)): Likewise.
	(read (jbyteArray, jint, jint): Likewise.

Index: posix-threads.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/posix-threads.cc,v
retrieving revision 1.27
diff -u -r1.27 posix-threads.cc
--- posix-threads.cc	2001/05/24 05:40:36	1.27
+++ posix-threads.cc	2001/09/20 06:42:09
@@ -263,7 +263,7 @@
   data->thread_obj->interrupt_flag = true;
 
   // Interrupt blocking system calls using a signal.
-//  pthread_kill (data->thread, INTR);
+  pthread_kill (data->thread, INTR);
   
   pthread_cond_signal (&data->wait_cond);
   
Index: java/io/natFileDescriptorPosix.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/natFileDescriptorPosix.cc,v
retrieving revision 1.15
diff -u -r1.15 natFileDescriptorPosix.cc
--- natFileDescriptorPosix.cc	2001/08/02 23:46:39	1.15
+++ natFileDescriptorPosix.cc	2001/09/20 06:42:09
@@ -125,15 +125,17 @@
   while (r != 1)
     {
       r = ::write (fd, &d, 1);
-      if (java::lang::Thread::interrupted())
-	{
-	  InterruptedIOException *iioe
-	    = new InterruptedIOException (JvNewStringLatin1 ("write interrupted"));
-	  iioe->bytesTransferred = r == -1 ? 0 : r;
-	  throw iioe;
+      if (r == -1)
+        {
+	  if (java::lang::Thread::interrupted())
+	    {
+	      InterruptedIOException *iioe
+		= new InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
+	      iioe->bytesTransferred = r == -1 ? 0 : r;
+	      throw iioe;
+	    }	    
+	  throw new IOException (JvNewStringLatin1 (strerror (errno)));
 	}
-      else if (r == -1)
-	throw new IOException (JvNewStringLatin1 (strerror (errno)));
     }
 }
 
@@ -150,18 +152,19 @@
   while (len > 0)
     {
       int r = ::write (fd, bytes, len);
-      if (r != -1)
-	written += r;
-      if (java::lang::Thread::interrupted())
-	{
-	  InterruptedIOException *iioe
-	    = new InterruptedIOException (JvNewStringLatin1 ("write interrupted"));
-	  iioe->bytesTransferred = written;
-	  throw iioe;
+      if (r == -1)
+        {
+	  if (java::lang::Thread::interrupted())
+	    {
+	      InterruptedIOException *iioe
+		= new InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
+	      iioe->bytesTransferred = written;
+	      throw iioe;
+	    }
+	  throw new IOException (JvNewStringLatin1 (strerror (errno)));
 	}
-      else if (r == -1)
-	throw new IOException (JvNewStringLatin1 (strerror (errno)));
 
+      written += r;
       len -= r;
       bytes += r;
     }
@@ -222,15 +225,17 @@
   int r = ::read (fd, &b, 1);
   if (r == 0)
     return -1;
-  if (java::lang::Thread::interrupted())
+  if (r == -1)
     {
-      InterruptedIOException *iioe
-	= new InterruptedIOException (JvNewStringLatin1 ("read interrupted"));
-      iioe->bytesTransferred = r == -1 ? 0 : r;
-      throw iioe;
+      if (java::lang::Thread::interrupted())
+	{
+	  InterruptedIOException *iioe
+	    = new InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
+	  iioe->bytesTransferred = r == -1 ? 0 : r;
+	  throw iioe;
+	}
+      throw new IOException (JvNewStringLatin1 (strerror (errno)));
     }
-  else if (r == -1)
-    throw new IOException (JvNewStringLatin1 (strerror (errno)));
   return b & 0xFF;
 }
 
@@ -246,15 +251,17 @@
   int r = ::read (fd, bytes, count);
   if (r == 0)
     return -1;
-  if (java::lang::Thread::interrupted())
-    {
-      InterruptedIOException *iioe
-	= new InterruptedIOException (JvNewStringLatin1 ("read interrupted"));
-      iioe->bytesTransferred = r == -1 ? 0 : r;
-      throw iioe;
+  if (r == -1)
+    {    
+      if (java::lang::Thread::interrupted())
+	{
+	  InterruptedIOException *iioe
+	    = new InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
+	  iioe->bytesTransferred = r == -1 ? 0 : r;
+	  throw iioe;
+	}
+      throw new IOException (JvNewStringLatin1 (strerror (errno)));
     }
-  else if (r == -1)
-    throw new IOException (JvNewStringLatin1 (strerror (errno)));
   return r;
 }
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]