|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.nio.ch; |
|
|
|
import java.nio.channels.*; |
|
import java.util.concurrent.*; |
|
import java.nio.ByteBuffer; |
|
import java.security.AccessController; |
|
import java.security.PrivilegedAction; |
|
import java.io.FileDescriptor; |
|
import java.io.IOException; |
|
|
|
/** |
|
* "Portable" implementation of AsynchronousFileChannel for use on operating |
|
* systems that don't support asynchronous file I/O. |
|
*/ |
|
|
|
public class SimpleAsynchronousFileChannelImpl |
|
extends AsynchronousFileChannelImpl |
|
{ |
|
|
|
private static class DefaultExecutorHolder { |
|
static final ExecutorService defaultExecutor = |
|
ThreadPool.createDefault().executor(); |
|
} |
|
|
|
|
|
private static final FileDispatcher nd = new FileDispatcherImpl(); |
|
|
|
|
|
private final NativeThreadSet threads = new NativeThreadSet(2); |
|
|
|
|
|
SimpleAsynchronousFileChannelImpl(FileDescriptor fdObj, |
|
boolean reading, |
|
boolean writing, |
|
ExecutorService executor) |
|
{ |
|
super(fdObj, reading, writing, executor); |
|
} |
|
|
|
public static AsynchronousFileChannel open(FileDescriptor fdo, |
|
boolean reading, |
|
boolean writing, |
|
ThreadPool pool) |
|
{ |
|
|
|
ExecutorService executor = (pool == null) ? |
|
DefaultExecutorHolder.defaultExecutor : pool.executor(); |
|
return new SimpleAsynchronousFileChannelImpl(fdo, reading, writing, executor); |
|
} |
|
|
|
@Override |
|
public void close() throws IOException { |
|
|
|
synchronized (fdObj) { |
|
if (closed) |
|
return; |
|
closed = true; |
|
// from this point on, if another thread invokes the begin() method |
|
// then it will throw ClosedChannelException |
|
} |
|
|
|
|
|
invalidateAllLocks(); |
|
|
|
|
|
threads.signalAndWait(); |
|
|
|
|
|
closeLock.writeLock().lock(); |
|
try { |
|
// do nothing |
|
} finally { |
|
closeLock.writeLock().unlock(); |
|
} |
|
|
|
|
|
nd.close(fdObj); |
|
} |
|
|
|
@Override |
|
public long size() throws IOException { |
|
int ti = threads.add(); |
|
try { |
|
long n = 0L; |
|
try { |
|
begin(); |
|
do { |
|
n = nd.size(fdObj); |
|
} while ((n == IOStatus.INTERRUPTED) && isOpen()); |
|
return n; |
|
} finally { |
|
end(n >= 0L); |
|
} |
|
} finally { |
|
threads.remove(ti); |
|
} |
|
} |
|
|
|
@Override |
|
public AsynchronousFileChannel truncate(long size) throws IOException { |
|
if (size < 0L) |
|
throw new IllegalArgumentException("Negative size"); |
|
if (!writing) |
|
throw new NonWritableChannelException(); |
|
int ti = threads.add(); |
|
try { |
|
long n = 0L; |
|
try { |
|
begin(); |
|
do { |
|
n = nd.size(fdObj); |
|
} while ((n == IOStatus.INTERRUPTED) && isOpen()); |
|
|
|
|
|
if (size < n && isOpen()) { |
|
do { |
|
n = nd.truncate(fdObj, size); |
|
} while ((n == IOStatus.INTERRUPTED) && isOpen()); |
|
} |
|
return this; |
|
} finally { |
|
end(n > 0); |
|
} |
|
} finally { |
|
threads.remove(ti); |
|
} |
|
} |
|
|
|
@Override |
|
public void force(boolean metaData) throws IOException { |
|
int ti = threads.add(); |
|
try { |
|
int n = 0; |
|
try { |
|
begin(); |
|
do { |
|
n = nd.force(fdObj, metaData); |
|
} while ((n == IOStatus.INTERRUPTED) && isOpen()); |
|
} finally { |
|
end(n >= 0); |
|
} |
|
} finally { |
|
threads.remove(ti); |
|
} |
|
} |
|
|
|
@Override |
|
<A> Future<FileLock> implLock(final long position, |
|
final long size, |
|
final boolean shared, |
|
final A attachment, |
|
final CompletionHandler<FileLock,? super A> handler) |
|
{ |
|
if (shared && !reading) |
|
throw new NonReadableChannelException(); |
|
if (!shared && !writing) |
|
throw new NonWritableChannelException(); |
|
|
|
|
|
final FileLockImpl fli = addToFileLockTable(position, size, shared); |
|
if (fli == null) { |
|
Throwable exc = new ClosedChannelException(); |
|
if (handler == null) |
|
return CompletedFuture.withFailure(exc); |
|
Invoker.invokeIndirectly(handler, attachment, null, exc, executor); |
|
return null; |
|
} |
|
|
|
final PendingFuture<FileLock,A> result = (handler == null) ? |
|
new PendingFuture<FileLock,A>(this) : null; |
|
Runnable task = new Runnable() { |
|
public void run() { |
|
Throwable exc = null; |
|
|
|
int ti = threads.add(); |
|
try { |
|
int n; |
|
try { |
|
begin(); |
|
do { |
|
n = nd.lock(fdObj, true, position, size, shared); |
|
} while ((n == FileDispatcher.INTERRUPTED) && isOpen()); |
|
if (n != FileDispatcher.LOCKED || !isOpen()) { |
|
throw new AsynchronousCloseException(); |
|
} |
|
} catch (IOException x) { |
|
removeFromFileLockTable(fli); |
|
if (!isOpen()) |
|
x = new AsynchronousCloseException(); |
|
exc = x; |
|
} finally { |
|
end(); |
|
} |
|
} finally { |
|
threads.remove(ti); |
|
} |
|
if (handler == null) { |
|
result.setResult(fli, exc); |
|
} else { |
|
Invoker.invokeUnchecked(handler, attachment, fli, exc); |
|
} |
|
} |
|
}; |
|
boolean executed = false; |
|
try { |
|
executor.execute(task); |
|
executed = true; |
|
} finally { |
|
if (!executed) { |
|
|
|
removeFromFileLockTable(fli); |
|
} |
|
} |
|
return result; |
|
} |
|
|
|
@Override |
|
public FileLock tryLock(long position, long size, boolean shared) |
|
throws IOException |
|
{ |
|
if (shared && !reading) |
|
throw new NonReadableChannelException(); |
|
if (!shared && !writing) |
|
throw new NonWritableChannelException(); |
|
|
|
|
|
FileLockImpl fli = addToFileLockTable(position, size, shared); |
|
if (fli == null) |
|
throw new ClosedChannelException(); |
|
|
|
int ti = threads.add(); |
|
boolean gotLock = false; |
|
try { |
|
begin(); |
|
int n; |
|
do { |
|
n = nd.lock(fdObj, false, position, size, shared); |
|
} while ((n == FileDispatcher.INTERRUPTED) && isOpen()); |
|
if (n == FileDispatcher.LOCKED && isOpen()) { |
|
gotLock = true; |
|
return fli; |
|
} |
|
if (n == FileDispatcher.NO_LOCK) |
|
return null; |
|
if (n == FileDispatcher.INTERRUPTED) |
|
throw new AsynchronousCloseException(); |
|
|
|
throw new AssertionError(); |
|
} finally { |
|
if (!gotLock) |
|
removeFromFileLockTable(fli); |
|
end(); |
|
threads.remove(ti); |
|
} |
|
} |
|
|
|
@Override |
|
protected void implRelease(FileLockImpl fli) throws IOException { |
|
nd.release(fdObj, fli.position(), fli.size()); |
|
} |
|
|
|
@Override |
|
<A> Future<Integer> implRead(final ByteBuffer dst, |
|
final long position, |
|
final A attachment, |
|
final CompletionHandler<Integer,? super A> handler) |
|
{ |
|
if (position < 0) |
|
throw new IllegalArgumentException("Negative position"); |
|
if (!reading) |
|
throw new NonReadableChannelException(); |
|
if (dst.isReadOnly()) |
|
throw new IllegalArgumentException("Read-only buffer"); |
|
|
|
|
|
if (!isOpen() || (dst.remaining() == 0)) { |
|
Throwable exc = (isOpen()) ? null : new ClosedChannelException(); |
|
if (handler == null) |
|
return CompletedFuture.withResult(0, exc); |
|
Invoker.invokeIndirectly(handler, attachment, 0, exc, executor); |
|
return null; |
|
} |
|
|
|
final PendingFuture<Integer,A> result = (handler == null) ? |
|
new PendingFuture<Integer,A>(this) : null; |
|
Runnable task = new Runnable() { |
|
public void run() { |
|
int n = 0; |
|
Throwable exc = null; |
|
|
|
int ti = threads.add(); |
|
try { |
|
begin(); |
|
do { |
|
n = IOUtil.read(fdObj, dst, position, nd); |
|
} while ((n == IOStatus.INTERRUPTED) && isOpen()); |
|
if (n < 0 && !isOpen()) |
|
throw new AsynchronousCloseException(); |
|
} catch (IOException x) { |
|
if (!isOpen()) |
|
x = new AsynchronousCloseException(); |
|
exc = x; |
|
} finally { |
|
end(); |
|
threads.remove(ti); |
|
} |
|
if (handler == null) { |
|
result.setResult(n, exc); |
|
} else { |
|
Invoker.invokeUnchecked(handler, attachment, n, exc); |
|
} |
|
} |
|
}; |
|
executor.execute(task); |
|
return result; |
|
} |
|
|
|
@Override |
|
<A> Future<Integer> implWrite(final ByteBuffer src, |
|
final long position, |
|
final A attachment, |
|
final CompletionHandler<Integer,? super A> handler) |
|
{ |
|
if (position < 0) |
|
throw new IllegalArgumentException("Negative position"); |
|
if (!writing) |
|
throw new NonWritableChannelException(); |
|
|
|
|
|
if (!isOpen() || (src.remaining() == 0)) { |
|
Throwable exc = (isOpen()) ? null : new ClosedChannelException(); |
|
if (handler == null) |
|
return CompletedFuture.withResult(0, exc); |
|
Invoker.invokeIndirectly(handler, attachment, 0, exc, executor); |
|
return null; |
|
} |
|
|
|
final PendingFuture<Integer,A> result = (handler == null) ? |
|
new PendingFuture<Integer,A>(this) : null; |
|
Runnable task = new Runnable() { |
|
public void run() { |
|
int n = 0; |
|
Throwable exc = null; |
|
|
|
int ti = threads.add(); |
|
try { |
|
begin(); |
|
do { |
|
n = IOUtil.write(fdObj, src, position, nd); |
|
} while ((n == IOStatus.INTERRUPTED) && isOpen()); |
|
if (n < 0 && !isOpen()) |
|
throw new AsynchronousCloseException(); |
|
} catch (IOException x) { |
|
if (!isOpen()) |
|
x = new AsynchronousCloseException(); |
|
exc = x; |
|
} finally { |
|
end(); |
|
threads.remove(ti); |
|
} |
|
if (handler == null) { |
|
result.setResult(n, exc); |
|
} else { |
|
Invoker.invokeUnchecked(handler, attachment, n, exc); |
|
} |
|
} |
|
}; |
|
executor.execute(task); |
|
return result; |
|
} |
|
} |