Path: blob/master/src/java.base/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java
41159 views
/*1* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.ch;2627import java.nio.channels.*;28import java.util.concurrent.*;29import java.nio.ByteBuffer;30import java.security.AccessController;31import java.security.PrivilegedAction;32import java.io.FileDescriptor;33import java.io.IOException;3435/**36* "Portable" implementation of AsynchronousFileChannel for use on operating37* systems that don't support asynchronous file I/O.38*/3940public class SimpleAsynchronousFileChannelImpl41extends AsynchronousFileChannelImpl42{43// lazy initialization of default thread pool for file I/O44private static class DefaultExecutorHolder {45static final ExecutorService defaultExecutor =46ThreadPool.createDefault().executor();47}4849// Used to make native read and write calls50private static final FileDispatcher nd = new FileDispatcherImpl();5152// Thread-safe set of IDs of native threads, for signalling53private final NativeThreadSet threads = new NativeThreadSet(2);545556SimpleAsynchronousFileChannelImpl(FileDescriptor fdObj,57boolean reading,58boolean writing,59ExecutorService executor)60{61super(fdObj, reading, writing, executor);62}6364public static AsynchronousFileChannel open(FileDescriptor fdo,65boolean reading,66boolean writing,67ThreadPool pool)68{69// Executor is either default or based on pool parameters70ExecutorService executor = (pool == null) ?71DefaultExecutorHolder.defaultExecutor : pool.executor();72return new SimpleAsynchronousFileChannelImpl(fdo, reading, writing, executor);73}7475@Override76public void close() throws IOException {77// mark channel as closed78synchronized (fdObj) {79if (closed)80return; // already closed81closed = true;82// from this point on, if another thread invokes the begin() method83// then it will throw ClosedChannelException84}8586// Invalidate and release any locks that we still hold87invalidateAllLocks();8889// signal any threads blocked on this channel90threads.signalAndWait();9192// wait until all async I/O operations have completely gracefully93closeLock.writeLock().lock();94try {95// do nothing96} finally {97closeLock.writeLock().unlock();98}99100// close file101nd.close(fdObj);102}103104@Override105public long size() throws IOException {106int ti = threads.add();107try {108long n = 0L;109try {110begin();111do {112n = nd.size(fdObj);113} while ((n == IOStatus.INTERRUPTED) && isOpen());114return n;115} finally {116end(n >= 0L);117}118} finally {119threads.remove(ti);120}121}122123@Override124public AsynchronousFileChannel truncate(long size) throws IOException {125if (size < 0L)126throw new IllegalArgumentException("Negative size");127if (!writing)128throw new NonWritableChannelException();129int ti = threads.add();130try {131long n = 0L;132try {133begin();134do {135n = nd.size(fdObj);136} while ((n == IOStatus.INTERRUPTED) && isOpen());137138// truncate file if 'size' less than current size139if (size < n && isOpen()) {140do {141n = nd.truncate(fdObj, size);142} while ((n == IOStatus.INTERRUPTED) && isOpen());143}144return this;145} finally {146end(n > 0);147}148} finally {149threads.remove(ti);150}151}152153@Override154public void force(boolean metaData) throws IOException {155int ti = threads.add();156try {157int n = 0;158try {159begin();160do {161n = nd.force(fdObj, metaData);162} while ((n == IOStatus.INTERRUPTED) && isOpen());163} finally {164end(n >= 0);165}166} finally {167threads.remove(ti);168}169}170171@Override172<A> Future<FileLock> implLock(final long position,173final long size,174final boolean shared,175final A attachment,176final CompletionHandler<FileLock,? super A> handler)177{178if (shared && !reading)179throw new NonReadableChannelException();180if (!shared && !writing)181throw new NonWritableChannelException();182183// add to lock table184final FileLockImpl fli = addToFileLockTable(position, size, shared);185if (fli == null) {186Throwable exc = new ClosedChannelException();187if (handler == null)188return CompletedFuture.withFailure(exc);189Invoker.invokeIndirectly(handler, attachment, null, exc, executor);190return null;191}192193final PendingFuture<FileLock,A> result = (handler == null) ?194new PendingFuture<FileLock,A>(this) : null;195Runnable task = new Runnable() {196public void run() {197Throwable exc = null;198199int ti = threads.add();200try {201int n;202try {203begin();204do {205n = nd.lock(fdObj, true, position, size, shared);206} while ((n == FileDispatcher.INTERRUPTED) && isOpen());207if (n != FileDispatcher.LOCKED || !isOpen()) {208throw new AsynchronousCloseException();209}210} catch (IOException x) {211removeFromFileLockTable(fli);212if (!isOpen())213x = new AsynchronousCloseException();214exc = x;215} finally {216end();217}218} finally {219threads.remove(ti);220}221if (handler == null) {222result.setResult(fli, exc);223} else {224Invoker.invokeUnchecked(handler, attachment, fli, exc);225}226}227};228boolean executed = false;229try {230executor.execute(task);231executed = true;232} finally {233if (!executed) {234// rollback235removeFromFileLockTable(fli);236}237}238return result;239}240241@Override242public FileLock tryLock(long position, long size, boolean shared)243throws IOException244{245if (shared && !reading)246throw new NonReadableChannelException();247if (!shared && !writing)248throw new NonWritableChannelException();249250// add to lock table251FileLockImpl fli = addToFileLockTable(position, size, shared);252if (fli == null)253throw new ClosedChannelException();254255int ti = threads.add();256boolean gotLock = false;257try {258begin();259int n;260do {261n = nd.lock(fdObj, false, position, size, shared);262} while ((n == FileDispatcher.INTERRUPTED) && isOpen());263if (n == FileDispatcher.LOCKED && isOpen()) {264gotLock = true;265return fli; // lock acquired266}267if (n == FileDispatcher.NO_LOCK)268return null; // locked by someone else269if (n == FileDispatcher.INTERRUPTED)270throw new AsynchronousCloseException();271// should not get here272throw new AssertionError();273} finally {274if (!gotLock)275removeFromFileLockTable(fli);276end();277threads.remove(ti);278}279}280281@Override282protected void implRelease(FileLockImpl fli) throws IOException {283nd.release(fdObj, fli.position(), fli.size());284}285286@Override287<A> Future<Integer> implRead(final ByteBuffer dst,288final long position,289final A attachment,290final CompletionHandler<Integer,? super A> handler)291{292if (position < 0)293throw new IllegalArgumentException("Negative position");294if (!reading)295throw new NonReadableChannelException();296if (dst.isReadOnly())297throw new IllegalArgumentException("Read-only buffer");298299// complete immediately if channel closed or no space remaining300if (!isOpen() || (dst.remaining() == 0)) {301Throwable exc = (isOpen()) ? null : new ClosedChannelException();302if (handler == null)303return CompletedFuture.withResult(0, exc);304Invoker.invokeIndirectly(handler, attachment, 0, exc, executor);305return null;306}307308final PendingFuture<Integer,A> result = (handler == null) ?309new PendingFuture<Integer,A>(this) : null;310Runnable task = new Runnable() {311public void run() {312int n = 0;313Throwable exc = null;314315int ti = threads.add();316try {317begin();318do {319n = IOUtil.read(fdObj, dst, position, nd);320} while ((n == IOStatus.INTERRUPTED) && isOpen());321if (n < 0 && !isOpen())322throw new AsynchronousCloseException();323} catch (IOException x) {324if (!isOpen())325x = new AsynchronousCloseException();326exc = x;327} finally {328end();329threads.remove(ti);330}331if (handler == null) {332result.setResult(n, exc);333} else {334Invoker.invokeUnchecked(handler, attachment, n, exc);335}336}337};338executor.execute(task);339return result;340}341342@Override343<A> Future<Integer> implWrite(final ByteBuffer src,344final long position,345final A attachment,346final CompletionHandler<Integer,? super A> handler)347{348if (position < 0)349throw new IllegalArgumentException("Negative position");350if (!writing)351throw new NonWritableChannelException();352353// complete immediately if channel is closed or no bytes remaining354if (!isOpen() || (src.remaining() == 0)) {355Throwable exc = (isOpen()) ? null : new ClosedChannelException();356if (handler == null)357return CompletedFuture.withResult(0, exc);358Invoker.invokeIndirectly(handler, attachment, 0, exc, executor);359return null;360}361362final PendingFuture<Integer,A> result = (handler == null) ?363new PendingFuture<Integer,A>(this) : null;364Runnable task = new Runnable() {365public void run() {366int n = 0;367Throwable exc = null;368369int ti = threads.add();370try {371begin();372do {373n = IOUtil.write(fdObj, src, position, nd);374} while ((n == IOStatus.INTERRUPTED) && isOpen());375if (n < 0 && !isOpen())376throw new AsynchronousCloseException();377} catch (IOException x) {378if (!isOpen())379x = new AsynchronousCloseException();380exc = x;381} finally {382end();383threads.remove(ti);384}385if (handler == null) {386result.setResult(n, exc);387} else {388Invoker.invokeUnchecked(handler, attachment, n, exc);389}390}391};392executor.execute(task);393return result;394}395}396397398