254 lines
7.9 KiB
Java
254 lines
7.9 KiB
Java
![]() |
/*
|
||
|
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. 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. Oracle designates this
|
||
|
* particular file as subject to the "Classpath" exception as provided
|
||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||
|
*
|
||
|
* 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||
|
* or visit www.oracle.com if you need additional information or have any
|
||
|
* questions.
|
||
|
*/
|
||
|
|
||
|
package sun.nio.ch;
|
||
|
|
||
|
import java.nio.ByteBuffer;
|
||
|
import java.nio.channels.*;
|
||
|
import java.util.concurrent.ExecutorService;
|
||
|
import java.util.concurrent.Future;
|
||
|
import java.util.concurrent.locks.*;
|
||
|
import java.io.FileDescriptor;
|
||
|
import java.io.IOException;
|
||
|
|
||
|
/**
|
||
|
* Base implementation of AsynchronousFileChannel.
|
||
|
*/
|
||
|
|
||
|
abstract class AsynchronousFileChannelImpl
|
||
|
extends AsynchronousFileChannel
|
||
|
{
|
||
|
// close support
|
||
|
protected final ReadWriteLock closeLock = new ReentrantReadWriteLock();
|
||
|
protected volatile boolean closed;
|
||
|
|
||
|
// file descriptor
|
||
|
protected final FileDescriptor fdObj;
|
||
|
|
||
|
// indicates if open for reading/writing
|
||
|
protected final boolean reading;
|
||
|
protected final boolean writing;
|
||
|
|
||
|
// associated Executor
|
||
|
protected final ExecutorService executor;
|
||
|
|
||
|
protected AsynchronousFileChannelImpl(FileDescriptor fdObj,
|
||
|
boolean reading,
|
||
|
boolean writing,
|
||
|
ExecutorService executor)
|
||
|
{
|
||
|
this.fdObj = fdObj;
|
||
|
this.reading = reading;
|
||
|
this.writing = writing;
|
||
|
this.executor = executor;
|
||
|
}
|
||
|
|
||
|
final ExecutorService executor() {
|
||
|
return executor;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public final boolean isOpen() {
|
||
|
return !closed;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Marks the beginning of an I/O operation.
|
||
|
*
|
||
|
* @throws ClosedChannelException If channel is closed
|
||
|
*/
|
||
|
protected final void begin() throws IOException {
|
||
|
closeLock.readLock().lock();
|
||
|
if (closed)
|
||
|
throw new ClosedChannelException();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Marks the end of an I/O operation.
|
||
|
*/
|
||
|
protected final void end() {
|
||
|
closeLock.readLock().unlock();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Marks end of I/O operation
|
||
|
*/
|
||
|
protected final void end(boolean completed) throws IOException {
|
||
|
end();
|
||
|
if (!completed && !isOpen())
|
||
|
throw new AsynchronousCloseException();
|
||
|
}
|
||
|
|
||
|
// -- file locking --
|
||
|
|
||
|
abstract <A> Future<FileLock> implLock(long position,
|
||
|
long size,
|
||
|
boolean shared,
|
||
|
A attachment,
|
||
|
CompletionHandler<FileLock,? super A> handler);
|
||
|
|
||
|
@Override
|
||
|
public final Future<FileLock> lock(long position,
|
||
|
long size,
|
||
|
boolean shared)
|
||
|
|
||
|
{
|
||
|
return implLock(position, size, shared, null, null);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public final <A> void lock(long position,
|
||
|
long size,
|
||
|
boolean shared,
|
||
|
A attachment,
|
||
|
CompletionHandler<FileLock,? super A> handler)
|
||
|
{
|
||
|
if (handler == null)
|
||
|
throw new NullPointerException("'handler' is null");
|
||
|
implLock(position, size, shared, attachment, handler);
|
||
|
}
|
||
|
|
||
|
private volatile FileLockTable fileLockTable;
|
||
|
|
||
|
final void ensureFileLockTableInitialized() throws IOException {
|
||
|
if (fileLockTable == null) {
|
||
|
synchronized (this) {
|
||
|
if (fileLockTable == null) {
|
||
|
fileLockTable = FileLockTable.newSharedFileLockTable(this, fdObj);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
final void invalidateAllLocks() throws IOException {
|
||
|
if (fileLockTable != null) {
|
||
|
for (FileLock fl: fileLockTable.removeAll()) {
|
||
|
synchronized (fl) {
|
||
|
if (fl.isValid()) {
|
||
|
FileLockImpl fli = (FileLockImpl)fl;
|
||
|
implRelease(fli);
|
||
|
fli.invalidate();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds region to lock table
|
||
|
*/
|
||
|
protected final FileLockImpl addToFileLockTable(long position, long size, boolean shared) {
|
||
|
final FileLockImpl fli;
|
||
|
try {
|
||
|
// like begin() but returns null instead of exception
|
||
|
closeLock.readLock().lock();
|
||
|
if (closed)
|
||
|
return null;
|
||
|
|
||
|
try {
|
||
|
ensureFileLockTableInitialized();
|
||
|
} catch (IOException x) {
|
||
|
// should not happen
|
||
|
throw new AssertionError(x);
|
||
|
}
|
||
|
fli = new FileLockImpl(this, position, size, shared);
|
||
|
// may throw OverlappedFileLockException
|
||
|
fileLockTable.add(fli);
|
||
|
} finally {
|
||
|
end();
|
||
|
}
|
||
|
return fli;
|
||
|
}
|
||
|
|
||
|
protected final void removeFromFileLockTable(FileLockImpl fli) {
|
||
|
fileLockTable.remove(fli);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Releases the given file lock.
|
||
|
*/
|
||
|
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();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// -- reading and writing --
|
||
|
|
||
|
abstract <A> Future<Integer> implRead(ByteBuffer dst,
|
||
|
long position,
|
||
|
A attachment,
|
||
|
CompletionHandler<Integer,? super A> handler);
|
||
|
|
||
|
@Override
|
||
|
public final Future<Integer> read(ByteBuffer dst, long position) {
|
||
|
return implRead(dst, position, null, null);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public final <A> void read(ByteBuffer dst,
|
||
|
long position,
|
||
|
A attachment,
|
||
|
CompletionHandler<Integer,? super A> handler)
|
||
|
{
|
||
|
if (handler == null)
|
||
|
throw new NullPointerException("'handler' is null");
|
||
|
implRead(dst, position, attachment, handler);
|
||
|
}
|
||
|
|
||
|
abstract <A> Future<Integer> implWrite(ByteBuffer src,
|
||
|
long position,
|
||
|
A attachment,
|
||
|
CompletionHandler<Integer,? super A> handler);
|
||
|
|
||
|
|
||
|
@Override
|
||
|
public final Future<Integer> write(ByteBuffer src, long position) {
|
||
|
return implWrite(src, position, null, null);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public final <A> void write(ByteBuffer src,
|
||
|
long position,
|
||
|
A attachment,
|
||
|
CompletionHandler<Integer,? super A> handler)
|
||
|
{
|
||
|
if (handler == null)
|
||
|
throw new NullPointerException("'handler' is null");
|
||
|
implWrite(src, position, attachment, handler);
|
||
|
}
|
||
|
}
|