From 9e2590b7bf321030927385d637a333d45e1e633e Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 15 Apr 2009 14:53:34 +0100 Subject: [PATCH 1/2] 6795561: (bf) CharBuffer.subSequence() uses wrong capacity value for new buffer Reviewed-by: sherman, iris --- .../share/classes/java/nio/ByteBufferAs-X-Buffer.java | 10 ++++++---- jdk/src/share/classes/java/nio/Direct-X-Buffer.java | 10 ++++++---- jdk/src/share/classes/java/nio/Heap-X-Buffer.java | 9 ++++++--- jdk/src/share/classes/java/nio/StringCharBuffer.java | 6 ++++-- jdk/test/java/nio/Buffer/Basic-X.java | 9 +++++++-- jdk/test/java/nio/Buffer/Basic.java | 2 +- jdk/test/java/nio/Buffer/BasicByte.java | 5 +++++ jdk/test/java/nio/Buffer/BasicChar.java | 9 +++++++-- jdk/test/java/nio/Buffer/BasicDouble.java | 5 +++++ jdk/test/java/nio/Buffer/BasicFloat.java | 5 +++++ jdk/test/java/nio/Buffer/BasicInt.java | 5 +++++ jdk/test/java/nio/Buffer/BasicLong.java | 5 +++++ jdk/test/java/nio/Buffer/BasicShort.java | 5 +++++ 13 files changed, 67 insertions(+), 18 deletions(-) diff --git a/jdk/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java b/jdk/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java index 15626425a0e..60be7479c49 100644 --- a/jdk/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java +++ b/jdk/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java @@ -196,10 +196,12 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private if ((start < 0) || (end > len) || (start > end)) throw new IndexOutOfBoundsException(); - int sublen = end - start; - int off = offset + ((pos + start) << $LG_BYTES_PER_VALUE$); - assert (off >= 0); - return new ByteBufferAsCharBuffer$RW$$BO$(bb, -1, 0, sublen, sublen, off); + return new ByteBufferAsCharBuffer$RW$$BO$(bb, + -1, + pos + start, + pos + end, + capacity(), + offset); } #end[char] diff --git a/jdk/src/share/classes/java/nio/Direct-X-Buffer.java b/jdk/src/share/classes/java/nio/Direct-X-Buffer.java index 5f738b7811e..a977626351e 100644 --- a/jdk/src/share/classes/java/nio/Direct-X-Buffer.java +++ b/jdk/src/share/classes/java/nio/Direct-X-Buffer.java @@ -412,10 +412,12 @@ class Direct$Type$Buffer$RW$$BO$ if ((start < 0) || (end > len) || (start > end)) throw new IndexOutOfBoundsException(); - int sublen = end - start; - int off = (pos + start) << $LG_BYTES_PER_VALUE$; - assert (off >= 0); - return new DirectCharBuffer$RW$$BO$(this, -1, 0, sublen, sublen, off); + return new DirectCharBuffer$RW$$BO$(this, + -1, + pos + start, + pos + end, + capacity(), + offset); } #end[char] diff --git a/jdk/src/share/classes/java/nio/Heap-X-Buffer.java b/jdk/src/share/classes/java/nio/Heap-X-Buffer.java index b615ba3c633..864161fa02e 100644 --- a/jdk/src/share/classes/java/nio/Heap-X-Buffer.java +++ b/jdk/src/share/classes/java/nio/Heap-X-Buffer.java @@ -572,10 +572,13 @@ class Heap$Type$Buffer$RW$ || (end > length()) || (start > end)) throw new IndexOutOfBoundsException(); - int len = end - start; + int pos = position(); return new HeapCharBuffer$RW$(hb, - -1, 0, len, len, - offset + position() + start); + -1, + pos + start, + pos + end, + capacity(), + offset); } #end[char] diff --git a/jdk/src/share/classes/java/nio/StringCharBuffer.java b/jdk/src/share/classes/java/nio/StringCharBuffer.java index 648b1986fca..8871b943f41 100644 --- a/jdk/src/share/classes/java/nio/StringCharBuffer.java +++ b/jdk/src/share/classes/java/nio/StringCharBuffer.java @@ -102,10 +102,12 @@ class StringCharBuffer // package-private public final CharBuffer subSequence(int start, int end) { try { int pos = position(); - return new StringCharBuffer(str, -1, + return new StringCharBuffer(str, + -1, pos + checkIndex(start, pos), pos + checkIndex(end, pos), - remaining(), offset); + capacity(), + offset); } catch (IllegalArgumentException x) { throw new IndexOutOfBoundsException(); } diff --git a/jdk/test/java/nio/Buffer/Basic-X.java b/jdk/test/java/nio/Buffer/Basic-X.java index d4e1a2762f1..6612771def4 100644 --- a/jdk/test/java/nio/Buffer/Basic-X.java +++ b/jdk/test/java/nio/Buffer/Basic-X.java @@ -365,8 +365,11 @@ public class Basic$Type$ b.position(2); ck(b, b.charAt(1), 'd'); - CharBuffer c = (CharBuffer)b.subSequence(1, 4); - ck(b, b.subSequence(1, 4).toString().equals("def")); + CharBuffer c = b.subSequence(1, 4); + ck(c, c.capacity(), b.capacity()); + ck(c, c.position(), b.position()+1); + ck(c, c.limit(), b.position()+4); + ck(c, b.subSequence(1, 4).toString().equals("def")); // 4938424 b.position(4); @@ -722,6 +725,8 @@ public class Basic$Type$ ck(b, start, b.position()); ck(b, end, b.limit()); ck(b, s.length(), b.capacity()); + b.position(6); + ck(b, b.subSequence(0,3).toString().equals("ghi")); // The index, relative to the position, must be non-negative and // smaller than remaining(). diff --git a/jdk/test/java/nio/Buffer/Basic.java b/jdk/test/java/nio/Buffer/Basic.java index c0c420f8495..b8ed89bb30d 100644 --- a/jdk/test/java/nio/Buffer/Basic.java +++ b/jdk/test/java/nio/Buffer/Basic.java @@ -25,7 +25,7 @@ * @summary Unit test for buffers * @bug 4413135 4414911 4416536 4416562 4418782 4471053 4472779 4490253 4523725 * 4526177 4463011 4660660 4661219 4663521 4782970 4804304 4938424 6231529 - * 6221101 6234263 6535542 6591971 6593946 + * 6221101 6234263 6535542 6591971 6593946 6795561 * @author Mark Reinhold */ diff --git a/jdk/test/java/nio/Buffer/BasicByte.java b/jdk/test/java/nio/Buffer/BasicByte.java index 0f5ac6f6e0a..7e259a1416d 100644 --- a/jdk/test/java/nio/Buffer/BasicByte.java +++ b/jdk/test/java/nio/Buffer/BasicByte.java @@ -371,6 +371,9 @@ public class BasicByte + + + @@ -783,6 +786,8 @@ public class BasicByte + + diff --git a/jdk/test/java/nio/Buffer/BasicChar.java b/jdk/test/java/nio/Buffer/BasicChar.java index 28eb49fb560..a0df9fcf3a9 100644 --- a/jdk/test/java/nio/Buffer/BasicChar.java +++ b/jdk/test/java/nio/Buffer/BasicChar.java @@ -365,8 +365,11 @@ public class BasicChar b.position(2); ck(b, b.charAt(1), 'd'); - CharBuffer c = (CharBuffer)b.subSequence(1, 4); - ck(b, b.subSequence(1, 4).toString().equals("def")); + CharBuffer c = b.subSequence(1, 4); + ck(c, c.capacity(), b.capacity()); + ck(c, c.position(), b.position()+1); + ck(c, c.limit(), b.position()+4); + ck(c, b.subSequence(1, 4).toString().equals("def")); // 4938424 b.position(4); @@ -722,6 +725,8 @@ public class BasicChar ck(b, start, b.position()); ck(b, end, b.limit()); ck(b, s.length(), b.capacity()); + b.position(6); + ck(b, b.subSequence(0,3).toString().equals("ghi")); // The index, relative to the position, must be non-negative and // smaller than remaining(). diff --git a/jdk/test/java/nio/Buffer/BasicDouble.java b/jdk/test/java/nio/Buffer/BasicDouble.java index b2a1be65ad7..a627d0e9194 100644 --- a/jdk/test/java/nio/Buffer/BasicDouble.java +++ b/jdk/test/java/nio/Buffer/BasicDouble.java @@ -371,6 +371,9 @@ public class BasicDouble + + + @@ -783,6 +786,8 @@ public class BasicDouble + + diff --git a/jdk/test/java/nio/Buffer/BasicFloat.java b/jdk/test/java/nio/Buffer/BasicFloat.java index b6b5ea0dbdf..730dcbeac95 100644 --- a/jdk/test/java/nio/Buffer/BasicFloat.java +++ b/jdk/test/java/nio/Buffer/BasicFloat.java @@ -371,6 +371,9 @@ public class BasicFloat + + + @@ -783,6 +786,8 @@ public class BasicFloat + + diff --git a/jdk/test/java/nio/Buffer/BasicInt.java b/jdk/test/java/nio/Buffer/BasicInt.java index 938ada29571..b20e4bb1056 100644 --- a/jdk/test/java/nio/Buffer/BasicInt.java +++ b/jdk/test/java/nio/Buffer/BasicInt.java @@ -371,6 +371,9 @@ public class BasicInt + + + @@ -783,6 +786,8 @@ public class BasicInt + + diff --git a/jdk/test/java/nio/Buffer/BasicLong.java b/jdk/test/java/nio/Buffer/BasicLong.java index 17537a71ffc..0d4c568e1e3 100644 --- a/jdk/test/java/nio/Buffer/BasicLong.java +++ b/jdk/test/java/nio/Buffer/BasicLong.java @@ -371,6 +371,9 @@ public class BasicLong + + + @@ -783,6 +786,8 @@ public class BasicLong + + diff --git a/jdk/test/java/nio/Buffer/BasicShort.java b/jdk/test/java/nio/Buffer/BasicShort.java index dc9c7db3803..58e5a3e6d68 100644 --- a/jdk/test/java/nio/Buffer/BasicShort.java +++ b/jdk/test/java/nio/Buffer/BasicShort.java @@ -371,6 +371,9 @@ public class BasicShort + + + @@ -783,6 +786,8 @@ public class BasicShort + + From 26dc2b8949b950c8624b4c963bd219942736a119 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 15 Apr 2009 16:16:35 +0100 Subject: [PATCH 2/2] 6543863: (fc) FileLock.release can deadlock with FileChannel.close 6429910: (fc) FileChannel.lock() IOException: Bad file number, not AsynchronousCloseException 6814948: (fc) test/java/nio/channels/AsynchronousFileChannel/Lock.java failed intermittently 6822643: (fc) AsynchronousFileChannel.close does not invalidate FileLocks Reviewed-by: sherman --- .../nio/ch/AsynchronousFileChannelImpl.java | 34 +++++-- .../classes/sun/nio/ch/FileChannelImpl.java | 63 ++++++------ .../classes/sun/nio/ch/FileLockImpl.java | 10 +- .../classes/sun/nio/ch/FileLockTable.java | 29 ++---- .../ch/SimpleAsynchronousFileChannelImpl.java | 38 +++---- .../WindowsAsynchronousFileChannelImpl.java | 11 +-- .../native/sun/nio/ch/FileDispatcherImpl.c | 2 +- .../AsynchronousFileChannel/Basic.java | 81 ++++++++------- .../AsynchronousFileChannel/Lock.java | 2 +- .../FileChannel/ReleaseOnCloseDeadlock.java | 98 +++++++++++++++++++ 10 files changed, 229 insertions(+), 139 deletions(-) create mode 100644 jdk/test/java/nio/channels/FileChannel/ReleaseOnCloseDeadlock.java diff --git a/jdk/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java index 2735a5a29cd..180238d8413 100644 --- a/jdk/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java @@ -113,16 +113,16 @@ abstract class AsynchronousFileChannelImpl } } - final void invalidateAllLocks() { + final void invalidateAllLocks() throws IOException { if (fileLockTable != null) { - try { - fileLockTable.removeAll( new FileLockTable.Releaser() { - public void release(FileLock fl) { - ((FileLockImpl)fl).invalidate(); + for (FileLock fl: fileLockTable.removeAll()) { + synchronized (fl) { + if (fl.isValid()) { + FileLockImpl fli = (FileLockImpl)fl; + implRelease(fli); + fli.invalidate(); } - }); - } catch (IOException e) { - throw new AssertionError(e); + } } } } @@ -158,7 +158,21 @@ abstract class AsynchronousFileChannelImpl } /** - * Invoked by FileLockImpl to release lock acquired by this channel. + * Releases the given file lock. */ - abstract void release(FileLockImpl fli) throws IOException; + protected abstract void implRelease(FileLockImpl fli) throws IOException; + + /** + * Invoked by FileLockImpl to release the given file lock and remove it + * from the lock table. + */ + final void release(FileLockImpl fli) throws IOException { + try { + begin(); + implRelease(fli); + removeFromFileLockTable(fli); + } finally { + end(); + } + } } diff --git a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java index 1d60e9615ff..d0461b30b9a 100644 --- a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java @@ -33,8 +33,6 @@ import java.nio.BufferPoolMXBean; import java.nio.channels.*; import java.util.ArrayList; import java.util.List; -import java.util.Iterator; -import java.lang.reflect.Field; import java.security.AccessController; import javax.management.ObjectName; import javax.management.MalformedObjectNameException; @@ -95,14 +93,16 @@ public class FileChannelImpl // -- Standard channel operations -- protected void implCloseChannel() throws IOException { - // Invalidate and release any locks that we still hold + // Release and invalidate any locks that we still hold if (fileLockTable != null) { - fileLockTable.removeAll( new FileLockTable.Releaser() { - public void release(FileLock fl) throws IOException { - ((FileLockImpl)fl).invalidate(); - nd.release(fd, fl.position(), fl.size()); + for (FileLock fl: fileLockTable.removeAll()) { + synchronized (fl) { + if (fl.isValid()) { + nd.release(fd, fl.position(), fl.size()); + ((FileLockImpl)fl).invalidate(); + } } - }); + } } nd.preClose(fd); @@ -912,32 +912,33 @@ public class FileChannelImpl FileLockImpl fli = new FileLockImpl(this, position, size, shared); FileLockTable flt = fileLockTable(); flt.add(fli); - boolean i = true; + boolean completed = false; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return null; - int result = nd.lock(fd, true, position, size, shared); - if (result == FileDispatcher.RET_EX_LOCK) { - assert shared; - FileLockImpl fli2 = new FileLockImpl(this, position, size, - false); - flt.replace(fli, fli2); - return fli2; + int n; + do { + n = nd.lock(fd, true, position, size, shared); + } while ((n == FileDispatcher.INTERRUPTED) && isOpen()); + if (isOpen()) { + if (n == FileDispatcher.RET_EX_LOCK) { + assert shared; + FileLockImpl fli2 = new FileLockImpl(this, position, size, + false); + flt.replace(fli, fli2); + fli = fli2; + } + completed = true; } - if (result == FileDispatcher.INTERRUPTED || result == FileDispatcher.NO_LOCK) { - flt.remove(fli); - i = false; - } - } catch (IOException e) { - flt.remove(fli); - throw e; } finally { + if (!completed) + flt.remove(fli); threads.remove(ti); try { - end(i); + end(completed); } catch (ClosedByInterruptException e) { throw new FileLockInterruptionException(); } @@ -985,7 +986,6 @@ public class FileChannelImpl } void release(FileLockImpl fli) throws IOException { - ensureOpen(); int ti = threads.add(); try { ensureOpen(); @@ -1005,7 +1005,7 @@ public class FileChannelImpl */ private static class SimpleFileLockTable extends FileLockTable { // synchronize on list for access - private List lockList = new ArrayList(2); + private final List lockList = new ArrayList(2); public SimpleFileLockTable() { } @@ -1034,14 +1034,11 @@ public class FileChannelImpl } } - public void removeAll(Releaser releaser) throws IOException { + public List removeAll() { synchronized(lockList) { - Iterator i = lockList.iterator(); - while (i.hasNext()) { - FileLock fl = i.next(); - releaser.release(fl); - i.remove(); - } + List result = new ArrayList(lockList); + lockList.clear(); + return result; } } diff --git a/jdk/src/share/classes/sun/nio/ch/FileLockImpl.java b/jdk/src/share/classes/sun/nio/ch/FileLockImpl.java index 9efd1532b50..8f12bcf0fdb 100644 --- a/jdk/src/share/classes/sun/nio/ch/FileLockImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/FileLockImpl.java @@ -31,25 +31,24 @@ import java.nio.channels.*; public class FileLockImpl extends FileLock { - boolean valid; + private volatile boolean valid = true; FileLockImpl(FileChannel channel, long position, long size, boolean shared) { super(channel, position, size, shared); - this.valid = true; } FileLockImpl(AsynchronousFileChannel channel, long position, long size, boolean shared) { super(channel, position, size, shared); - this.valid = true; } - public synchronized boolean isValid() { + public boolean isValid() { return valid; } - synchronized void invalidate() { + void invalidate() { + assert Thread.holdsLock(this); valid = false; } @@ -66,5 +65,4 @@ public class FileLockImpl valid = false; } } - } diff --git a/jdk/src/share/classes/sun/nio/ch/FileLockTable.java b/jdk/src/share/classes/sun/nio/ch/FileLockTable.java index 137ab88872b..39cee5abfe8 100644 --- a/jdk/src/share/classes/sun/nio/ch/FileLockTable.java +++ b/jdk/src/share/classes/sun/nio/ch/FileLockTable.java @@ -60,23 +60,12 @@ abstract class FileLockTable { */ public abstract void remove(FileLock fl); - /** - * An implementation of this interface releases a given file lock. - * Used with removeAll. - */ - public abstract interface Releaser { - void release(FileLock fl) throws IOException; - } - /** * Removes all file locks from the table. - *

- * The Releaser#release method is invoked for each file lock before - * it is removed. * - * @throws IOException if the release method throws IOException + * @return The list of file locks removed */ - public abstract void removeAll(Releaser r) throws IOException; + public abstract List removeAll(); /** * Replaces an existing file lock in the table. @@ -195,7 +184,7 @@ class SharedFileLockTable extends FileLockTable { FileLockReference ref = list.get(index); FileLock lock = ref.get(); if (lock == fl) { - assert (lock != null) && (lock.channel() == channel); + assert (lock != null) && (lock.acquiredBy() == channel); ref.clear(); list.remove(index); break; @@ -206,7 +195,8 @@ class SharedFileLockTable extends FileLockTable { } @Override - public void removeAll(Releaser releaser) throws IOException { + public List removeAll() { + List result = new ArrayList(); List list = lockMap.get(fileKey); if (list != null) { synchronized (list) { @@ -216,13 +206,13 @@ class SharedFileLockTable extends FileLockTable { FileLock lock = ref.get(); // remove locks obtained by this channel - if (lock != null && lock.channel() == channel) { - // invoke the releaser to invalidate/release the lock - releaser.release(lock); - + if (lock != null && lock.acquiredBy() == channel) { // remove the lock from the list ref.clear(); list.remove(index); + + // add to result + result.add(lock); } else { index++; } @@ -232,6 +222,7 @@ class SharedFileLockTable extends FileLockTable { removeKeyIfEmpty(fileKey, list); } } + return result; } @Override diff --git a/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java index 52fe5a2802f..fb82f330be4 100644 --- a/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java @@ -97,6 +97,9 @@ public class SimpleAsynchronousFileChannelImpl // then it will throw ClosedChannelException } + // Invalidate and release any locks that we still hold + invalidateAllLocks(); + // signal any threads blocked on this channel nd.preClose(fdObj); threads.signalAndWait(); @@ -109,9 +112,6 @@ public class SimpleAsynchronousFileChannelImpl closeLock.writeLock().unlock(); } - // Invalidate and release any locks that we still hold - invalidateAllLocks(); - // close file nd.close(fdObj); @@ -226,11 +226,9 @@ public class SimpleAsynchronousFileChannelImpl do { n = nd.lock(fdObj, true, position, size, shared); } while ((n == FileDispatcher.INTERRUPTED) && isOpen()); - if (n == FileDispatcher.LOCKED) { + if (n == FileDispatcher.LOCKED && isOpen()) { result.setResult(fli); } else { - if (n != FileDispatcher.INTERRUPTED) - throw new AssertionError(); throw new AsynchronousCloseException(); } } catch (IOException x) { @@ -279,16 +277,16 @@ public class SimpleAsynchronousFileChannelImpl do { n = nd.lock(fdObj, false, position, size, shared); } while ((n == FileDispatcher.INTERRUPTED) && isOpen()); - if (n != FileDispatcher.LOCKED) { - if (n == FileDispatcher.NO_LOCK) - return null; // locked by someone else - if (n == FileDispatcher.INTERRUPTED) - throw new AsynchronousCloseException(); - // should not get here - throw new AssertionError(); + if (n == FileDispatcher.LOCKED && isOpen()) { + gotLock = true; + return fli; // lock acquired } - gotLock = true; - return fli; + if (n == FileDispatcher.NO_LOCK) + return null; // locked by someone else + if (n == FileDispatcher.INTERRUPTED) + throw new AsynchronousCloseException(); + // should not get here + throw new AssertionError(); } finally { if (!gotLock) removeFromFileLockTable(fli); @@ -298,14 +296,8 @@ public class SimpleAsynchronousFileChannelImpl } @Override - void release(FileLockImpl fli) throws IOException { - try { - begin(); - nd.release(fdObj, fli.position(), fli.size()); - removeFromFileLockTable(fli); - } finally { - end(); - } + protected void implRelease(FileLockImpl fli) throws IOException { + nd.release(fdObj, fli.position(), fli.size()); } @Override diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java index ef668648d67..e08f460d919 100644 --- a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java @@ -354,16 +354,9 @@ public class WindowsAsynchronousFileChannelImpl } } - // invoke by FileFileImpl to release lock @Override - void release(FileLockImpl fli) throws IOException { - try { - begin(); - nd.release(fdObj, fli.position(), fli.size()); - removeFromFileLockTable(fli); - } finally { - end(); - } + protected void implRelease(FileLockImpl fli) throws IOException { + nd.release(fdObj, fli.position(), fli.size()); } /** diff --git a/jdk/src/windows/native/sun/nio/ch/FileDispatcherImpl.c b/jdk/src/windows/native/sun/nio/ch/FileDispatcherImpl.c index a65ad90e24d..7b41d86fad1 100644 --- a/jdk/src/windows/native/sun/nio/ch/FileDispatcherImpl.c +++ b/jdk/src/windows/native/sun/nio/ch/FileDispatcherImpl.c @@ -414,7 +414,7 @@ Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this, o.Offset = lowPos; o.OffsetHigh = highPos; result = UnlockFileEx(h, 0, lowNumBytes, highNumBytes, &o); - if (result == 0) { + if (result == 0 && GetLastError() != ERROR_NOT_LOCKED) { JNU_ThrowIOExceptionWithLastError(env, "Release failed"); } } diff --git a/jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java b/jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java index 5ffb42c0b8b..ea9a5415923 100644 --- a/jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6822643 * @summary Unit test for AsynchronousFileChannel */ @@ -51,7 +51,6 @@ public class Basic { // run tests testUsingCompletionHandlers(ch); testUsingWaitOnResult(ch); - testLocking(ch); testInterruptHandlerThread(ch); // close channel and invoke test that expects channel to be closed @@ -59,6 +58,7 @@ public class Basic { testClosedChannel(ch); // these tests open the file themselves + testLocking(blah.toPath()); testCustomThreadPool(blah.toPath()); testAsynchronousClose(blah.toPath()); testCancel(blah.toPath()); @@ -160,47 +160,54 @@ public class Basic { } // exercise lock methods - static void testLocking(AsynchronousFileChannel ch) - throws IOException - { + static void testLocking(Path file) throws IOException { System.out.println("testLocking"); - // test 1 - acquire lock and check that tryLock throws - // OverlappingFileLockException + AsynchronousFileChannel ch = AsynchronousFileChannel + .open(file, READ, WRITE); FileLock fl; try { - fl = ch.lock().get(); - } catch (ExecutionException x) { - throw new RuntimeException(x); - } catch (InterruptedException x) { - throw new RuntimeException("Should not be interrupted"); - } - if (!fl.acquiredBy().equals(ch)) - throw new RuntimeException("FileLock#acquiredBy returned incorrect channel"); - try { - ch.tryLock(); - throw new RuntimeException("OverlappingFileLockException expected"); - } catch (OverlappingFileLockException x) { - } - fl.release(); + // test 1 - acquire lock and check that tryLock throws + // OverlappingFileLockException + try { + fl = ch.lock().get(); + } catch (ExecutionException x) { + throw new RuntimeException(x); + } catch (InterruptedException x) { + throw new RuntimeException("Should not be interrupted"); + } + if (!fl.acquiredBy().equals(ch)) + throw new RuntimeException("FileLock#acquiredBy returned incorrect channel"); + try { + ch.tryLock(); + throw new RuntimeException("OverlappingFileLockException expected"); + } catch (OverlappingFileLockException x) { + } + fl.release(); - // test 2 - acquire try and check that lock throws OverlappingFileLockException - fl = ch.tryLock(); - if (fl == null) - throw new RuntimeException("Unable to acquire lock"); - try { - ch.lock(null, new CompletionHandler () { - public void completed(FileLock result, Void att) { - } - public void failed(Throwable exc, Void att) { - } - public void cancelled(Void att) { - } - }); - throw new RuntimeException("OverlappingFileLockException expected"); - } catch (OverlappingFileLockException x) { + // test 2 - acquire try and check that lock throws OverlappingFileLockException + fl = ch.tryLock(); + if (fl == null) + throw new RuntimeException("Unable to acquire lock"); + try { + ch.lock(null, new CompletionHandler () { + public void completed(FileLock result, Void att) { + } + public void failed(Throwable exc, Void att) { + } + public void cancelled(Void att) { + } + }); + throw new RuntimeException("OverlappingFileLockException expected"); + } catch (OverlappingFileLockException x) { + } + } finally { + ch.close(); } - fl.release(); + + // test 3 - channel is closed so FileLock should no longer be valid + if (fl.isValid()) + throw new RuntimeException("FileLock expected to be invalid"); } // interrupt should not close channel diff --git a/jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java b/jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java index 38c0f7d0c6e..f8b55cc44f8 100644 --- a/jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java @@ -23,7 +23,7 @@ /* @test - * @bug 4607272 + * @bug 4607272 6814948 * @summary Unit test for AsynchronousFileChannel#lock method */ diff --git a/jdk/test/java/nio/channels/FileChannel/ReleaseOnCloseDeadlock.java b/jdk/test/java/nio/channels/FileChannel/ReleaseOnCloseDeadlock.java new file mode 100644 index 00000000000..c7ed16a9204 --- /dev/null +++ b/jdk/test/java/nio/channels/FileChannel/ReleaseOnCloseDeadlock.java @@ -0,0 +1,98 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 6543863 + * @summary Try to cause a deadlock between (Asynchronous)FileChannel.close + * and FileLock.release + */ + +import java.io.*; +import java.nio.file.Path; +import static java.nio.file.StandardOpenOption.*; +import java.nio.channels.*; +import java.util.concurrent.*; + +public class ReleaseOnCloseDeadlock { + private static final int LOCK_COUNT = 1024; + + public static void main(String[] args) throws IOException { + File blah = File.createTempFile("blah", null); + blah.deleteOnExit(); + for (int i=0; i<100; i++) { + test(blah.toPath()); + } + } + + static void test(Path file) throws IOException { + FileLock[] locks = new FileLock[LOCK_COUNT]; + + FileChannel fc = FileChannel.open(file, READ, WRITE); + for (int i=0; i