Merge
This commit is contained in:
commit
d3af1f284c
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<FileLock> lockList = new ArrayList<FileLock>(2);
|
||||
private final List<FileLock> lockList = new ArrayList<FileLock>(2);
|
||||
|
||||
public SimpleFileLockTable() {
|
||||
}
|
||||
@ -1034,14 +1034,11 @@ public class FileChannelImpl
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAll(Releaser releaser) throws IOException {
|
||||
public List<FileLock> removeAll() {
|
||||
synchronized(lockList) {
|
||||
Iterator<FileLock> i = lockList.iterator();
|
||||
while (i.hasNext()) {
|
||||
FileLock fl = i.next();
|
||||
releaser.release(fl);
|
||||
i.remove();
|
||||
}
|
||||
List<FileLock> result = new ArrayList<FileLock>(lockList);
|
||||
lockList.clear();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
* <p>
|
||||
* 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<FileLock> 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<FileLock> removeAll() {
|
||||
List<FileLock> result = new ArrayList<FileLock>();
|
||||
List<FileLockReference> 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
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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().
|
||||
|
@ -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
|
||||
*/
|
||||
|
||||
|
@ -371,6 +371,9 @@ public class BasicByte
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -783,6 +786,8 @@ public class BasicByte
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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().
|
||||
|
@ -371,6 +371,9 @@ public class BasicDouble
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -783,6 +786,8 @@ public class BasicDouble
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -371,6 +371,9 @@ public class BasicFloat
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -783,6 +786,8 @@ public class BasicFloat
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -371,6 +371,9 @@ public class BasicInt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -783,6 +786,8 @@ public class BasicInt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -371,6 +371,9 @@ public class BasicLong
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -783,6 +786,8 @@ public class BasicLong
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -371,6 +371,9 @@ public class BasicShort
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -783,6 +786,8 @@ public class BasicShort
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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<FileLock,Void> () {
|
||||
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<FileLock,Void> () {
|
||||
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
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
|
||||
/* @test
|
||||
* @bug 4607272
|
||||
* @bug 4607272 6814948
|
||||
* @summary Unit test for AsynchronousFileChannel#lock method
|
||||
*/
|
||||
|
||||
|
@ -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<LOCK_COUNT; i++) {
|
||||
locks[i] = fc.lock(i, 1, true);
|
||||
}
|
||||
tryToDeadlock(fc, locks);
|
||||
|
||||
AsynchronousFileChannel ch = AsynchronousFileChannel.open(file, READ, WRITE);
|
||||
for (int i=0; i<LOCK_COUNT; i++) {
|
||||
try {
|
||||
locks[i] = ch.lock(i, 1, true, null, null).get();
|
||||
} catch (InterruptedException x) {
|
||||
throw new RuntimeException(x);
|
||||
} catch (ExecutionException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
}
|
||||
tryToDeadlock(ch, locks);
|
||||
}
|
||||
|
||||
static void tryToDeadlock(final Channel channel, FileLock[] locks)
|
||||
throws IOException
|
||||
{
|
||||
// start thread to close the file (and invalidate the locks)
|
||||
Thread closer = new Thread(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
channel.close();
|
||||
} catch (IOException ignore) {
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
}});
|
||||
closer.start();
|
||||
|
||||
// release the locks explicitly
|
||||
for (int i=0; i<locks.length; i++) {
|
||||
try {
|
||||
locks[i].release();
|
||||
} catch (ClosedChannelException ignore) { }
|
||||
}
|
||||
|
||||
// we are done when closer has terminated
|
||||
while (closer.isAlive()) {
|
||||
try {
|
||||
closer.join();
|
||||
} catch (InterruptedException ignore) { }
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user