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 
26 package sun.nio.ch;
27 
28 import java.nio.ByteBuffer;
29 import java.nio.channels.*;
30 import java.util.concurrent.ExecutorService;
31 import java.util.concurrent.Future;
32 import java.util.concurrent.locks.*;
33 import java.io.FileDescriptor;
34 import java.io.IOException;
35 
36 /**
37  * Base implementation of AsynchronousFileChannel.
38  */
39 
40 abstract 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 
AsynchronousFileChannelImpl(FileDescriptor fdObj, boolean reading, boolean writing, ExecutorService executor)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 
executor()68     final ExecutorService executor() {
69         return executor;
70     }
71 
72     @Override
isOpen()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      */
begin()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      */
end()91     protected final void end() {
92         closeLock.readLock().unlock();
93     }
94 
95     /**
96      * Marks end of I/O operation
97      */
end(boolean completed)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 
implLock(long position, long size, boolean shared, A attachment, CompletionHandler<FileLock,? super A> handler)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
lock(long position, long size, boolean shared)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
lock(long position, long size, boolean shared, A attachment, CompletionHandler<FileLock,? super A> handler)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 
ensureFileLockTableInitialized()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 
invalidateAllLocks()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      */
addToFileLockTable(long position, long size, boolean shared)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 
removeFromFileLockTable(FileLockImpl fli)185     protected final void removeFromFileLockTable(FileLockImpl fli) {
186         fileLockTable.remove(fli);
187     }
188 
189     /**
190      * Releases the given file lock.
191      */
implRelease(FileLockImpl fli)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      */
release(FileLockImpl fli)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 
implRead(ByteBuffer dst, long position, A attachment, CompletionHandler<Integer,? super A> handler)211     abstract <A> Future<Integer> implRead(ByteBuffer dst,
212                                          long position,
213                                          A attachment,
214                                          CompletionHandler<Integer,? super A> handler);
215 
216     @Override
read(ByteBuffer dst, long position)217     public final Future<Integer> read(ByteBuffer dst, long position) {
218         return implRead(dst, position, null, null);
219     }
220 
221     @Override
read(ByteBuffer dst, long position, A attachment, CompletionHandler<Integer,? super A> handler)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 
implWrite(ByteBuffer src, long position, A attachment, CompletionHandler<Integer,? super A> handler)232     abstract <A> Future<Integer> implWrite(ByteBuffer src,
233                                            long position,
234                                            A attachment,
235                                            CompletionHandler<Integer,? super A> handler);
236 
237 
238     @Override
write(ByteBuffer src, long position)239     public final Future<Integer> write(ByteBuffer src, long position) {
240         return implWrite(src, position, null, null);
241     }
242 
243     @Override
write(ByteBuffer src, long position, A attachment, CompletionHandler<Integer,? super A> handler)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