1/*
2 * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.nio.ch;
27
28import java.nio.ByteBuffer;
29import java.nio.channels.*;
30import java.util.concurrent.ExecutorService;
31import java.util.concurrent.Future;
32import java.util.concurrent.locks.*;
33import java.io.FileDescriptor;
34import java.io.IOException;
35
36/**
37 * Base implementation of AsynchronousFileChannel.
38 */
39
40abstract class AsynchronousFileChannelImpl
41    extends AsynchronousFileChannel
42{
43    // close support
44    protected final ReadWriteLock closeLock = new ReentrantReadWriteLock();
45    protected volatile boolean closed;
46
47    // file descriptor
48    protected final FileDescriptor fdObj;
49
50    // indicates if open for reading/writing
51    protected final boolean reading;
52    protected final boolean writing;
53
54    // associated Executor
55    protected final ExecutorService executor;
56
57    protected AsynchronousFileChannelImpl(FileDescriptor fdObj,
58                                          boolean reading,
59                                          boolean writing,
60                                          ExecutorService executor)
61    {
62        this.fdObj = fdObj;
63        this.reading = reading;
64        this.writing = writing;
65        this.executor = executor;
66    }
67
68    final ExecutorService executor() {
69        return executor;
70    }
71
72    @Override
73    public final boolean isOpen() {
74        return !closed;
75    }
76
77    /**
78     * Marks the beginning of an I/O operation.
79     *
80     * @throws  ClosedChannelException  If channel is closed
81     */
82    protected final void begin() throws IOException {
83        closeLock.readLock().lock();
84        if (closed)
85            throw new ClosedChannelException();
86    }
87
88    /**
89     * Marks the end of an I/O operation.
90     */
91    protected final void end() {
92        closeLock.readLock().unlock();
93    }
94
95    /**
96     * Marks end of I/O operation
97     */
98    protected final void end(boolean completed) throws IOException {
99        end();
100        if (!completed && !isOpen())
101            throw new AsynchronousCloseException();
102    }
103
104    // -- file locking --
105
106    abstract <A> Future<FileLock> implLock(long position,
107                                           long size,
108                                           boolean shared,
109                                           A attachment,
110                                           CompletionHandler<FileLock,? super A> handler);
111
112    @Override
113    public final Future<FileLock> lock(long position,
114                                       long size,
115                                       boolean shared)
116
117    {
118        return implLock(position, size, shared, null, null);
119    }
120
121    @Override
122    public final <A> void lock(long position,
123                               long size,
124                               boolean shared,
125                               A attachment,
126                               CompletionHandler<FileLock,? super A> handler)
127    {
128        if (handler == null)
129            throw new NullPointerException("'handler' is null");
130        implLock(position, size, shared, attachment, handler);
131    }
132
133    private volatile FileLockTable fileLockTable;
134
135    final void ensureFileLockTableInitialized() throws IOException {
136        if (fileLockTable == null) {
137            synchronized (this) {
138                if (fileLockTable == null) {
139                    fileLockTable = FileLockTable.newSharedFileLockTable(this, fdObj);
140                }
141            }
142        }
143    }
144
145    final void invalidateAllLocks() throws IOException {
146        if (fileLockTable != null) {
147            for (FileLock fl: fileLockTable.removeAll()) {
148                synchronized (fl) {
149                    if (fl.isValid()) {
150                        FileLockImpl fli = (FileLockImpl)fl;
151                        implRelease(fli);
152                        fli.invalidate();
153                    }
154                }
155            }
156        }
157    }
158
159    /**
160     * Adds region to lock table
161     */
162    protected final FileLockImpl addToFileLockTable(long position, long size, boolean shared) {
163        final FileLockImpl fli;
164        try {
165            // like begin() but returns null instead of exception
166            closeLock.readLock().lock();
167            if (closed)
168                return null;
169
170            try {
171                ensureFileLockTableInitialized();
172            } catch (IOException x) {
173                // should not happen
174                throw new AssertionError(x);
175            }
176            fli = new FileLockImpl(this, position, size, shared);
177            // may throw OverlappedFileLockException
178            fileLockTable.add(fli);
179        } finally {
180            end();
181        }
182        return fli;
183    }
184
185    protected final void removeFromFileLockTable(FileLockImpl fli) {
186        fileLockTable.remove(fli);
187    }
188
189    /**
190     * Releases the given file lock.
191     */
192    protected abstract void implRelease(FileLockImpl fli) throws IOException;
193
194    /**
195     * Invoked by FileLockImpl to release the given file lock and remove it
196     * from the lock table.
197     */
198    final void release(FileLockImpl fli) throws IOException {
199        try {
200            begin();
201            implRelease(fli);
202            removeFromFileLockTable(fli);
203        } finally {
204            end();
205        }
206    }
207
208
209    // -- reading and writing --
210
211    abstract <A> Future<Integer> implRead(ByteBuffer dst,
212                                         long position,
213                                         A attachment,
214                                         CompletionHandler<Integer,? super A> handler);
215
216    @Override
217    public final Future<Integer> read(ByteBuffer dst, long position) {
218        return implRead(dst, position, null, null);
219    }
220
221    @Override
222    public final <A> void read(ByteBuffer dst,
223                               long position,
224                               A attachment,
225                               CompletionHandler<Integer,? super A> handler)
226    {
227        if (handler == null)
228            throw new NullPointerException("'handler' is null");
229        implRead(dst, position, attachment, handler);
230    }
231
232    abstract <A> Future<Integer> implWrite(ByteBuffer src,
233                                           long position,
234                                           A attachment,
235                                           CompletionHandler<Integer,? super A> handler);
236
237
238    @Override
239    public final Future<Integer> write(ByteBuffer src, long position) {
240        return implWrite(src, position, null, null);
241    }
242
243    @Override
244    public final <A> void write(ByteBuffer src,
245                                long position,
246                                A attachment,
247                                CompletionHandler<Integer,? super A> handler)
248    {
249        if (handler == null)
250            throw new NullPointerException("'handler' is null");
251        implWrite(src, position, attachment, handler);
252    }
253}
254