Bug in interrupt handling in FileChannelImpl.map( … )

Chris Dennis chris.w.dennis at gmail.com
Fri Sep 13 15:04:53 UTC 2013


Hi All,

I have discovered what I'm pretty certain is a bug in FileChannelImpl's
interrupt handling.  The root cause is that the map(…) method is calling
size() from within it's begin()/end(…) block.  Due to the way that
implCloseChannel() implementation interacts with the NativeThreadSet the
begin() end() pair are not re-entrant for FileChannelImpl.  If you
interrupt the map() operation at the wrong time then you can cause the
thread to deadlock as the interrupted thread will be waiting in
signalAndWait() for itself to leave.  I believe the patch at the bottom of
this email (against jdk8/jdk) resolves this issue, which uses the same
logic in map(…) to get the underlying file size as is used in the
truncate(…) method at the moment.  I also think it would be good to check
on each begin call to make sure we are not re-entrant, which will avoid
any future breakage of this type.  I have struggled to reproduce this bug
in a small test-case - the only way I have been able to do has been by
modifying FileChannelImpl to put a spin-loop before the begin() call in
size() to open up the window in which the interrupt needs to happen.  Let
me know if you need clarification or more explanation of anything.

Thanks,

Chris Dennis


diff -r b67c8099ba28 src/share/classes/sun/nio/ch/FileChannelImpl.java
--- a/src/share/classes/sun/nio/ch/FileChannelImpl.java	Thu Sep 12
11:09:11 2013 -0700
+++ b/src/share/classes/sun/nio/ch/FileChannelImpl.java	Fri Sep 13
10:42:07 2013 -0400
@@ -840,7 +840,15 @@
             ti = threads.add();
             if (!isOpen())
                 return null;
-            if (size() < position + size) { // Extend file size
+
+            long filesize;
+            do {
+                filesize = nd.size(fd);
+            } while ((filesize == IOStatus.INTERRUPTED) && isOpen());
+            if (!isOpen())
+                return null;
+
+            if (filesize < position + size) { // Extend file size
                 if (!writable) {
                     throw new IOException("Channel not open for writing "
+
                         "- cannot extend file to required size");





More information about the nio-dev mailing list