changeset 2057 | 3acf8e5e2ca0 |
parent 1821 | fe2556ead537 |
child 2441 | 228c040622a2 |
2056:115e09b7a004 | 2057:3acf8e5e2ca0 |
---|---|
1 /* |
1 /* |
2 * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. |
2 * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Sun designates this |
7 * published by the Free Software Foundation. Sun designates this |
24 */ |
24 */ |
25 |
25 |
26 package sun.nio.ch; |
26 package sun.nio.ch; |
27 |
27 |
28 import java.io.FileDescriptor; |
28 import java.io.FileDescriptor; |
29 import java.io.FileInputStream; |
|
30 import java.io.FileOutputStream; |
|
31 import java.io.RandomAccessFile; |
|
32 import java.io.IOException; |
29 import java.io.IOException; |
33 import java.nio.ByteBuffer; |
30 import java.nio.ByteBuffer; |
34 import java.nio.MappedByteBuffer; |
31 import java.nio.MappedByteBuffer; |
35 import java.nio.BufferPoolMXBean; |
32 import java.nio.BufferPoolMXBean; |
36 import java.nio.channels.*; |
33 import java.nio.channels.*; |
37 import java.nio.channels.spi.*; |
|
38 import java.util.ArrayList; |
34 import java.util.ArrayList; |
39 import java.util.List; |
35 import java.util.List; |
40 import java.util.Iterator; |
36 import java.util.Iterator; |
41 import java.util.concurrent.ConcurrentHashMap; |
|
42 import java.lang.ref.WeakReference; |
|
43 import java.lang.ref.ReferenceQueue; |
|
44 import java.lang.reflect.Field; |
37 import java.lang.reflect.Field; |
45 import java.security.AccessController; |
38 import java.security.AccessController; |
46 import java.security.PrivilegedAction; |
|
47 import javax.management.ObjectName; |
39 import javax.management.ObjectName; |
48 import javax.management.MalformedObjectNameException; |
40 import javax.management.MalformedObjectNameException; |
49 |
|
50 import sun.misc.Cleaner; |
41 import sun.misc.Cleaner; |
51 import sun.security.action.GetPropertyAction; |
42 import sun.security.action.GetPropertyAction; |
52 |
43 |
53 public class FileChannelImpl |
44 public class FileChannelImpl |
54 extends FileChannel |
45 extends FileChannel |
55 { |
46 { |
56 |
47 |
57 // Used to make native read and write calls |
48 // Used to make native read and write calls |
58 private static final NativeDispatcher nd; |
49 private static final FileDispatcher nd; |
59 |
50 |
60 // Memory allocation size for mapping buffers |
51 // Memory allocation size for mapping buffers |
61 private static final long allocationGranularity; |
52 private static final long allocationGranularity; |
62 |
53 |
63 // File descriptor |
54 // File descriptor |
102 |
93 |
103 |
94 |
104 // -- Standard channel operations -- |
95 // -- Standard channel operations -- |
105 |
96 |
106 protected void implCloseChannel() throws IOException { |
97 protected void implCloseChannel() throws IOException { |
107 |
|
108 nd.preClose(fd); |
|
109 threads.signal(); |
|
110 |
|
111 // Invalidate and release any locks that we still hold |
98 // Invalidate and release any locks that we still hold |
112 if (fileLockTable != null) { |
99 if (fileLockTable != null) { |
113 fileLockTable.removeAll( new FileLockTable.Releaser() { |
100 fileLockTable.removeAll( new FileLockTable.Releaser() { |
114 public void release(FileLock fl) throws IOException { |
101 public void release(FileLock fl) throws IOException { |
115 ((FileLockImpl)fl).invalidate(); |
102 ((FileLockImpl)fl).invalidate(); |
116 release0(fd, fl.position(), fl.size()); |
103 nd.release(fd, fl.position(), fl.size()); |
117 } |
104 } |
118 }); |
105 }); |
119 } |
106 } |
107 |
|
108 nd.preClose(fd); |
|
109 threads.signalAndWait(); |
|
120 |
110 |
121 if (parent != null) { |
111 if (parent != null) { |
122 |
112 |
123 // Close the fd via the parent stream's close method. The parent |
113 // Close the fd via the parent stream's close method. The parent |
124 // will reinvoke our close method, which is defined in the |
114 // will reinvoke our close method, which is defined in the |
136 ensureOpen(); |
126 ensureOpen(); |
137 if (!readable) |
127 if (!readable) |
138 throw new NonReadableChannelException(); |
128 throw new NonReadableChannelException(); |
139 synchronized (positionLock) { |
129 synchronized (positionLock) { |
140 int n = 0; |
130 int n = 0; |
141 int ti = -1; |
131 int ti = threads.add(); |
142 try { |
132 try { |
143 begin(); |
133 begin(); |
144 if (!isOpen()) |
134 if (!isOpen()) |
145 return 0; |
135 return 0; |
146 ti = threads.add(); |
|
147 do { |
136 do { |
148 n = IOUtil.read(fd, dst, -1, nd, positionLock); |
137 n = IOUtil.read(fd, dst, -1, nd, positionLock); |
149 } while ((n == IOStatus.INTERRUPTED) && isOpen()); |
138 } while ((n == IOStatus.INTERRUPTED) && isOpen()); |
150 return IOStatus.normalize(n); |
139 return IOStatus.normalize(n); |
151 } finally { |
140 } finally { |
160 ensureOpen(); |
149 ensureOpen(); |
161 if (!readable) |
150 if (!readable) |
162 throw new NonReadableChannelException(); |
151 throw new NonReadableChannelException(); |
163 synchronized (positionLock) { |
152 synchronized (positionLock) { |
164 long n = 0; |
153 long n = 0; |
165 int ti = -1; |
154 int ti = threads.add(); |
166 try { |
155 try { |
167 begin(); |
156 begin(); |
168 if (!isOpen()) |
157 if (!isOpen()) |
169 return 0; |
158 return 0; |
170 ti = threads.add(); |
|
171 do { |
159 do { |
172 n = IOUtil.read(fd, dsts, nd); |
160 n = IOUtil.read(fd, dsts, nd); |
173 } while ((n == IOStatus.INTERRUPTED) && isOpen()); |
161 } while ((n == IOStatus.INTERRUPTED) && isOpen()); |
174 return IOStatus.normalize(n); |
162 return IOStatus.normalize(n); |
175 } finally { |
163 } finally { |
193 ensureOpen(); |
181 ensureOpen(); |
194 if (!writable) |
182 if (!writable) |
195 throw new NonWritableChannelException(); |
183 throw new NonWritableChannelException(); |
196 synchronized (positionLock) { |
184 synchronized (positionLock) { |
197 int n = 0; |
185 int n = 0; |
198 int ti = -1; |
186 int ti = threads.add(); |
199 try { |
187 try { |
200 begin(); |
188 begin(); |
201 if (!isOpen()) |
189 if (!isOpen()) |
202 return 0; |
190 return 0; |
203 ti = threads.add(); |
|
204 do { |
191 do { |
205 n = IOUtil.write(fd, src, -1, nd, positionLock); |
192 n = IOUtil.write(fd, src, -1, nd, positionLock); |
206 } while ((n == IOStatus.INTERRUPTED) && isOpen()); |
193 } while ((n == IOStatus.INTERRUPTED) && isOpen()); |
207 return IOStatus.normalize(n); |
194 return IOStatus.normalize(n); |
208 } finally { |
195 } finally { |
217 ensureOpen(); |
204 ensureOpen(); |
218 if (!writable) |
205 if (!writable) |
219 throw new NonWritableChannelException(); |
206 throw new NonWritableChannelException(); |
220 synchronized (positionLock) { |
207 synchronized (positionLock) { |
221 long n = 0; |
208 long n = 0; |
222 int ti = -1; |
209 int ti = threads.add(); |
223 try { |
210 try { |
224 begin(); |
211 begin(); |
225 if (!isOpen()) |
212 if (!isOpen()) |
226 return 0; |
213 return 0; |
227 ti = threads.add(); |
|
228 do { |
214 do { |
229 n = IOUtil.write(fd, srcs, nd); |
215 n = IOUtil.write(fd, srcs, nd); |
230 } while ((n == IOStatus.INTERRUPTED) && isOpen()); |
216 } while ((n == IOStatus.INTERRUPTED) && isOpen()); |
231 return IOStatus.normalize(n); |
217 return IOStatus.normalize(n); |
232 } finally { |
218 } finally { |
251 |
237 |
252 public long position() throws IOException { |
238 public long position() throws IOException { |
253 ensureOpen(); |
239 ensureOpen(); |
254 synchronized (positionLock) { |
240 synchronized (positionLock) { |
255 long p = -1; |
241 long p = -1; |
256 int ti = -1; |
242 int ti = threads.add(); |
257 try { |
243 try { |
258 begin(); |
244 begin(); |
259 if (!isOpen()) |
245 if (!isOpen()) |
260 return 0; |
246 return 0; |
261 ti = threads.add(); |
|
262 do { |
247 do { |
263 p = position0(fd, -1); |
248 p = position0(fd, -1); |
264 } while ((p == IOStatus.INTERRUPTED) && isOpen()); |
249 } while ((p == IOStatus.INTERRUPTED) && isOpen()); |
265 return IOStatus.normalize(p); |
250 return IOStatus.normalize(p); |
266 } finally { |
251 } finally { |
275 ensureOpen(); |
260 ensureOpen(); |
276 if (newPosition < 0) |
261 if (newPosition < 0) |
277 throw new IllegalArgumentException(); |
262 throw new IllegalArgumentException(); |
278 synchronized (positionLock) { |
263 synchronized (positionLock) { |
279 long p = -1; |
264 long p = -1; |
280 int ti = -1; |
265 int ti = threads.add(); |
281 try { |
266 try { |
282 begin(); |
267 begin(); |
283 if (!isOpen()) |
268 if (!isOpen()) |
284 return null; |
269 return null; |
285 ti = threads.add(); |
|
286 do { |
270 do { |
287 p = position0(fd, newPosition); |
271 p = position0(fd, newPosition); |
288 } while ((p == IOStatus.INTERRUPTED) && isOpen()); |
272 } while ((p == IOStatus.INTERRUPTED) && isOpen()); |
289 return this; |
273 return this; |
290 } finally { |
274 } finally { |
297 |
281 |
298 public long size() throws IOException { |
282 public long size() throws IOException { |
299 ensureOpen(); |
283 ensureOpen(); |
300 synchronized (positionLock) { |
284 synchronized (positionLock) { |
301 long s = -1; |
285 long s = -1; |
302 int ti = -1; |
286 int ti = threads.add(); |
303 try { |
287 try { |
304 begin(); |
288 begin(); |
305 if (!isOpen()) |
289 if (!isOpen()) |
306 return -1; |
290 return -1; |
307 ti = threads.add(); |
|
308 do { |
291 do { |
309 s = size0(fd); |
292 s = nd.size(fd); |
310 } while ((s == IOStatus.INTERRUPTED) && isOpen()); |
293 } while ((s == IOStatus.INTERRUPTED) && isOpen()); |
311 return IOStatus.normalize(s); |
294 return IOStatus.normalize(s); |
312 } finally { |
295 } finally { |
313 threads.remove(ti); |
296 threads.remove(ti); |
314 end(s > -1); |
297 end(s > -1); |
326 if (!writable) |
309 if (!writable) |
327 throw new NonWritableChannelException(); |
310 throw new NonWritableChannelException(); |
328 synchronized (positionLock) { |
311 synchronized (positionLock) { |
329 int rv = -1; |
312 int rv = -1; |
330 long p = -1; |
313 long p = -1; |
331 int ti = -1; |
314 int ti = threads.add(); |
332 try { |
315 try { |
333 begin(); |
316 begin(); |
334 if (!isOpen()) |
317 if (!isOpen()) |
335 return null; |
318 return null; |
336 ti = threads.add(); |
|
337 |
319 |
338 // get current position |
320 // get current position |
339 do { |
321 do { |
340 p = position0(fd, -1); |
322 p = position0(fd, -1); |
341 } while ((p == IOStatus.INTERRUPTED) && isOpen()); |
323 } while ((p == IOStatus.INTERRUPTED) && isOpen()); |
343 return null; |
325 return null; |
344 assert p >= 0; |
326 assert p >= 0; |
345 |
327 |
346 // truncate file |
328 // truncate file |
347 do { |
329 do { |
348 rv = truncate0(fd, size); |
330 rv = nd.truncate(fd, size); |
349 } while ((rv == IOStatus.INTERRUPTED) && isOpen()); |
331 } while ((rv == IOStatus.INTERRUPTED) && isOpen()); |
350 if (!isOpen()) |
332 if (!isOpen()) |
351 return null; |
333 return null; |
352 |
334 |
353 // set position to size if greater than size |
335 // set position to size if greater than size |
366 } |
348 } |
367 |
349 |
368 public void force(boolean metaData) throws IOException { |
350 public void force(boolean metaData) throws IOException { |
369 ensureOpen(); |
351 ensureOpen(); |
370 int rv = -1; |
352 int rv = -1; |
371 int ti = -1; |
353 int ti = threads.add(); |
372 try { |
354 try { |
373 begin(); |
355 begin(); |
374 if (!isOpen()) |
356 if (!isOpen()) |
375 return; |
357 return; |
376 ti = threads.add(); |
|
377 do { |
358 do { |
378 rv = force0(fd, metaData); |
359 rv = nd.force(fd, metaData); |
379 } while ((rv == IOStatus.INTERRUPTED) && isOpen()); |
360 } while ((rv == IOStatus.INTERRUPTED) && isOpen()); |
380 } finally { |
361 } finally { |
381 threads.remove(ti); |
362 threads.remove(ti); |
382 end(rv > -1); |
363 end(rv > -1); |
383 assert IOStatus.check(rv); |
364 assert IOStatus.check(rv); |
423 int targetFDVal = IOUtil.fdVal(targetFD); |
404 int targetFDVal = IOUtil.fdVal(targetFD); |
424 if (thisFDVal == targetFDVal) // Not supported on some configurations |
405 if (thisFDVal == targetFDVal) // Not supported on some configurations |
425 return IOStatus.UNSUPPORTED; |
406 return IOStatus.UNSUPPORTED; |
426 |
407 |
427 long n = -1; |
408 long n = -1; |
428 int ti = -1; |
409 int ti = threads.add(); |
429 try { |
410 try { |
430 begin(); |
411 begin(); |
431 if (!isOpen()) |
412 if (!isOpen()) |
432 return -1; |
413 return -1; |
433 ti = threads.add(); |
|
434 do { |
414 do { |
435 n = transferTo0(thisFDVal, position, icount, targetFDVal); |
415 n = transferTo0(thisFDVal, position, icount, targetFDVal); |
436 } while ((n == IOStatus.INTERRUPTED) && isOpen()); |
416 } while ((n == IOStatus.INTERRUPTED) && isOpen()); |
437 if (n == IOStatus.UNSUPPORTED_CASE) { |
417 if (n == IOStatus.UNSUPPORTED_CASE) { |
438 if (target instanceof SinkChannelImpl) |
418 if (target instanceof SinkChannelImpl) |
630 throw new IllegalArgumentException("Negative position"); |
610 throw new IllegalArgumentException("Negative position"); |
631 if (!readable) |
611 if (!readable) |
632 throw new NonReadableChannelException(); |
612 throw new NonReadableChannelException(); |
633 ensureOpen(); |
613 ensureOpen(); |
634 int n = 0; |
614 int n = 0; |
635 int ti = -1; |
615 int ti = threads.add(); |
636 try { |
616 try { |
637 begin(); |
617 begin(); |
638 if (!isOpen()) |
618 if (!isOpen()) |
639 return -1; |
619 return -1; |
640 ti = threads.add(); |
|
641 do { |
620 do { |
642 n = IOUtil.read(fd, dst, position, nd, positionLock); |
621 n = IOUtil.read(fd, dst, position, nd, positionLock); |
643 } while ((n == IOStatus.INTERRUPTED) && isOpen()); |
622 } while ((n == IOStatus.INTERRUPTED) && isOpen()); |
644 return IOStatus.normalize(n); |
623 return IOStatus.normalize(n); |
645 } finally { |
624 } finally { |
656 throw new IllegalArgumentException("Negative position"); |
635 throw new IllegalArgumentException("Negative position"); |
657 if (!writable) |
636 if (!writable) |
658 throw new NonWritableChannelException(); |
637 throw new NonWritableChannelException(); |
659 ensureOpen(); |
638 ensureOpen(); |
660 int n = 0; |
639 int n = 0; |
661 int ti = -1; |
640 int ti = threads.add(); |
662 try { |
641 try { |
663 begin(); |
642 begin(); |
664 if (!isOpen()) |
643 if (!isOpen()) |
665 return -1; |
644 return -1; |
666 ti = threads.add(); |
|
667 do { |
645 do { |
668 n = IOUtil.write(fd, src, position, nd, positionLock); |
646 n = IOUtil.write(fd, src, position, nd, positionLock); |
669 } while ((n == IOStatus.INTERRUPTED) && isOpen()); |
647 } while ((n == IOStatus.INTERRUPTED) && isOpen()); |
670 return IOStatus.normalize(n); |
648 return IOStatus.normalize(n); |
671 } finally { |
649 } finally { |
751 throw new NonWritableChannelException(); |
729 throw new NonWritableChannelException(); |
752 if (!readable) |
730 if (!readable) |
753 throw new NonReadableChannelException(); |
731 throw new NonReadableChannelException(); |
754 |
732 |
755 long addr = -1; |
733 long addr = -1; |
756 int ti = -1; |
734 int ti = threads.add(); |
757 try { |
735 try { |
758 begin(); |
736 begin(); |
759 if (!isOpen()) |
737 if (!isOpen()) |
760 return null; |
738 return null; |
761 ti = threads.add(); |
|
762 if (size() < position + size) { // Extend file size |
739 if (size() < position + size) { // Extend file size |
763 if (!writable) { |
740 if (!writable) { |
764 throw new IOException("Channel not open for writing " + |
741 throw new IOException("Channel not open for writing " + |
765 "- cannot extend file to required size"); |
742 "- cannot extend file to required size"); |
766 } |
743 } |
767 int rv; |
744 int rv; |
768 do { |
745 do { |
769 rv = truncate0(fd, position + size); |
746 rv = nd.truncate(fd, position + size); |
770 } while ((rv == IOStatus.INTERRUPTED) && isOpen()); |
747 } while ((rv == IOStatus.INTERRUPTED) && isOpen()); |
771 } |
748 } |
772 if (size == 0) { |
749 if (size == 0) { |
773 addr = 0; |
750 addr = 0; |
774 if ((!writable) || (imode == MAP_RO)) |
751 if ((!writable) || (imode == MAP_RO)) |
858 } |
835 } |
859 } |
836 } |
860 |
837 |
861 // -- Locks -- |
838 // -- Locks -- |
862 |
839 |
863 public static final int NO_LOCK = -1; // Failed to lock |
840 |
864 public static final int LOCKED = 0; // Obtained requested lock |
|
865 public static final int RET_EX_LOCK = 1; // Obtained exclusive lock |
|
866 public static final int INTERRUPTED = 2; // Request interrupted |
|
867 |
841 |
868 // keeps track of locks on this file |
842 // keeps track of locks on this file |
869 private volatile FileLockTable fileLockTable; |
843 private volatile FileLockTable fileLockTable; |
870 |
844 |
871 // indicates if file locks are maintained system-wide (as per spec) |
845 // indicates if file locks are maintained system-wide (as per spec) |
891 } |
865 } |
892 } |
866 } |
893 return isSharedFileLockTable; |
867 return isSharedFileLockTable; |
894 } |
868 } |
895 |
869 |
896 private FileLockTable fileLockTable() { |
870 private FileLockTable fileLockTable() throws IOException { |
897 if (fileLockTable == null) { |
871 if (fileLockTable == null) { |
898 synchronized (this) { |
872 synchronized (this) { |
899 if (fileLockTable == null) { |
873 if (fileLockTable == null) { |
900 fileLockTable = isSharedFileLockTable() ? |
874 if (isSharedFileLockTable()) { |
901 new SharedFileLockTable(this) : new SimpleFileLockTable(); |
875 int ti = threads.add(); |
876 try { |
|
877 ensureOpen(); |
|
878 fileLockTable = FileLockTable.newSharedFileLockTable(this, fd); |
|
879 } finally { |
|
880 threads.remove(ti); |
|
881 } |
|
882 } else { |
|
883 fileLockTable = new SimpleFileLockTable(); |
|
884 } |
|
902 } |
885 } |
903 } |
886 } |
904 } |
887 } |
905 return fileLockTable; |
888 return fileLockTable; |
906 } |
889 } |
915 throw new NonWritableChannelException(); |
898 throw new NonWritableChannelException(); |
916 FileLockImpl fli = new FileLockImpl(this, position, size, shared); |
899 FileLockImpl fli = new FileLockImpl(this, position, size, shared); |
917 FileLockTable flt = fileLockTable(); |
900 FileLockTable flt = fileLockTable(); |
918 flt.add(fli); |
901 flt.add(fli); |
919 boolean i = true; |
902 boolean i = true; |
920 int ti = -1; |
903 int ti = threads.add(); |
921 try { |
904 try { |
922 begin(); |
905 begin(); |
923 if (!isOpen()) |
906 if (!isOpen()) |
924 return null; |
907 return null; |
925 ti = threads.add(); |
908 int result = nd.lock(fd, true, position, size, shared); |
926 int result = lock0(fd, true, position, size, shared); |
909 if (result == FileDispatcher.RET_EX_LOCK) { |
927 if (result == RET_EX_LOCK) { |
|
928 assert shared; |
910 assert shared; |
929 FileLockImpl fli2 = new FileLockImpl(this, position, size, |
911 FileLockImpl fli2 = new FileLockImpl(this, position, size, |
930 false); |
912 false); |
931 flt.replace(fli, fli2); |
913 flt.replace(fli, fli2); |
932 return fli2; |
914 return fli2; |
933 } |
915 } |
934 if (result == INTERRUPTED || result == NO_LOCK) { |
916 if (result == FileDispatcher.INTERRUPTED || result == FileDispatcher.NO_LOCK) { |
935 flt.remove(fli); |
917 flt.remove(fli); |
936 i = false; |
918 i = false; |
937 } |
919 } |
938 } catch (IOException e) { |
920 } catch (IOException e) { |
939 flt.remove(fli); |
921 flt.remove(fli); |
958 if (!shared && !writable) |
940 if (!shared && !writable) |
959 throw new NonWritableChannelException(); |
941 throw new NonWritableChannelException(); |
960 FileLockImpl fli = new FileLockImpl(this, position, size, shared); |
942 FileLockImpl fli = new FileLockImpl(this, position, size, shared); |
961 FileLockTable flt = fileLockTable(); |
943 FileLockTable flt = fileLockTable(); |
962 flt.add(fli); |
944 flt.add(fli); |
963 int result = lock0(fd, false, position, size, shared); |
945 int result; |
964 if (result == NO_LOCK) { |
946 |
965 flt.remove(fli); |
947 int ti = threads.add(); |
966 return null; |
948 try { |
967 } |
949 try { |
968 if (result == RET_EX_LOCK) { |
950 ensureOpen(); |
969 assert shared; |
951 result = nd.lock(fd, false, position, size, shared); |
970 FileLockImpl fli2 = new FileLockImpl(this, position, size, |
952 } catch (IOException e) { |
971 false); |
953 flt.remove(fli); |
972 flt.replace(fli, fli2); |
954 throw e; |
973 return fli2; |
955 } |
974 } |
956 if (result == FileDispatcher.NO_LOCK) { |
975 return fli; |
957 flt.remove(fli); |
958 return null; |
|
959 } |
|
960 if (result == FileDispatcher.RET_EX_LOCK) { |
|
961 assert shared; |
|
962 FileLockImpl fli2 = new FileLockImpl(this, position, size, |
|
963 false); |
|
964 flt.replace(fli, fli2); |
|
965 return fli2; |
|
966 } |
|
967 return fli; |
|
968 } finally { |
|
969 threads.remove(ti); |
|
970 } |
|
976 } |
971 } |
977 |
972 |
978 void release(FileLockImpl fli) throws IOException { |
973 void release(FileLockImpl fli) throws IOException { |
979 ensureOpen(); |
974 ensureOpen(); |
980 release0(fd, fli.position(), fli.size()); |
975 int ti = threads.add(); |
976 try { |
|
977 ensureOpen(); |
|
978 nd.release(fd, fli.position(), fli.size()); |
|
979 } finally { |
|
980 threads.remove(ti); |
|
981 } |
|
981 assert fileLockTable != null; |
982 assert fileLockTable != null; |
982 fileLockTable.remove(fli); |
983 fileLockTable.remove(fli); |
983 } |
984 } |
984 |
985 |
985 |
986 // -- File lock support -- |
986 // -- File lock support -- |
|
987 |
|
988 /** |
|
989 * A table of FileLocks. |
|
990 */ |
|
991 private interface FileLockTable { |
|
992 /** |
|
993 * Adds a file lock to the table. |
|
994 * |
|
995 * @throws OverlappingFileLockException if the file lock overlaps |
|
996 * with an existing file lock in the table |
|
997 */ |
|
998 void add(FileLock fl) throws OverlappingFileLockException; |
|
999 |
|
1000 /** |
|
1001 * Remove an existing file lock from the table. |
|
1002 */ |
|
1003 void remove(FileLock fl); |
|
1004 |
|
1005 /** |
|
1006 * An implementation of this interface releases a given file lock. |
|
1007 * Used with removeAll. |
|
1008 */ |
|
1009 interface Releaser { |
|
1010 void release(FileLock fl) throws IOException; |
|
1011 } |
|
1012 |
|
1013 /** |
|
1014 * Removes all file locks from the table. |
|
1015 * <p> |
|
1016 * The Releaser#release method is invoked for each file lock before |
|
1017 * it is removed. |
|
1018 * |
|
1019 * @throws IOException if the release method throws IOException |
|
1020 */ |
|
1021 void removeAll(Releaser r) throws IOException; |
|
1022 |
|
1023 /** |
|
1024 * Replaces an existing file lock in the table. |
|
1025 */ |
|
1026 void replace(FileLock fl1, FileLock fl2); |
|
1027 } |
|
1028 |
987 |
1029 /** |
988 /** |
1030 * A simple file lock table that maintains a list of FileLocks obtained by a |
989 * A simple file lock table that maintains a list of FileLocks obtained by a |
1031 * FileChannel. Use to get 1.4/5.0 behaviour. |
990 * FileChannel. Use to get 1.4/5.0 behaviour. |
1032 */ |
991 */ |
1033 private static class SimpleFileLockTable implements FileLockTable { |
992 private static class SimpleFileLockTable extends FileLockTable { |
1034 // synchronize on list for access |
993 // synchronize on list for access |
1035 private List<FileLock> lockList = new ArrayList<FileLock>(2); |
994 private List<FileLock> lockList = new ArrayList<FileLock>(2); |
1036 |
995 |
1037 public SimpleFileLockTable() { |
996 public SimpleFileLockTable() { |
1038 } |
997 } |
1078 lockList.add(fl2); |
1037 lockList.add(fl2); |
1079 } |
1038 } |
1080 } |
1039 } |
1081 } |
1040 } |
1082 |
1041 |
1083 /** |
|
1084 * A weak reference to a FileLock. |
|
1085 * <p> |
|
1086 * SharedFileLockTable uses a list of file lock references to avoid keeping the |
|
1087 * FileLock (and FileChannel) alive. |
|
1088 */ |
|
1089 private static class FileLockReference extends WeakReference<FileLock> { |
|
1090 private FileKey fileKey; |
|
1091 |
|
1092 FileLockReference(FileLock referent, |
|
1093 ReferenceQueue<FileLock> queue, |
|
1094 FileKey key) { |
|
1095 super(referent, queue); |
|
1096 this.fileKey = key; |
|
1097 } |
|
1098 |
|
1099 private FileKey fileKey() { |
|
1100 return fileKey; |
|
1101 } |
|
1102 } |
|
1103 |
|
1104 /** |
|
1105 * A file lock table that is over a system-wide map of all file locks. |
|
1106 */ |
|
1107 private static class SharedFileLockTable implements FileLockTable { |
|
1108 // The system-wide map is a ConcurrentHashMap that is keyed on the FileKey. |
|
1109 // The map value is a list of file locks represented by FileLockReferences. |
|
1110 // All access to the list must be synchronized on the list. |
|
1111 private static ConcurrentHashMap<FileKey, ArrayList<FileLockReference>> lockMap = |
|
1112 new ConcurrentHashMap<FileKey, ArrayList<FileLockReference>>(); |
|
1113 |
|
1114 // reference queue for cleared refs |
|
1115 private static ReferenceQueue<FileLock> queue = new ReferenceQueue<FileLock>(); |
|
1116 |
|
1117 // the enclosing file channel |
|
1118 private FileChannelImpl fci; |
|
1119 |
|
1120 // File key for the file that this channel is connected to |
|
1121 private FileKey fileKey; |
|
1122 |
|
1123 public SharedFileLockTable(FileChannelImpl fci) { |
|
1124 this.fci = fci; |
|
1125 this.fileKey = FileKey.create(fci.fd); |
|
1126 } |
|
1127 |
|
1128 public void add(FileLock fl) throws OverlappingFileLockException { |
|
1129 ArrayList<FileLockReference> list = lockMap.get(fileKey); |
|
1130 |
|
1131 for (;;) { |
|
1132 |
|
1133 // The key isn't in the map so we try to create it atomically |
|
1134 if (list == null) { |
|
1135 list = new ArrayList<FileLockReference>(2); |
|
1136 ArrayList<FileLockReference> prev; |
|
1137 synchronized (list) { |
|
1138 prev = lockMap.putIfAbsent(fileKey, list); |
|
1139 if (prev == null) { |
|
1140 // we successfully created the key so we add the file lock |
|
1141 list.add(new FileLockReference(fl, queue, fileKey)); |
|
1142 break; |
|
1143 } |
|
1144 } |
|
1145 // someone else got there first |
|
1146 list = prev; |
|
1147 } |
|
1148 |
|
1149 // There is already a key. It is possible that some other thread |
|
1150 // is removing it so we re-fetch the value from the map. If it |
|
1151 // hasn't changed then we check the list for overlapping locks |
|
1152 // and add the new lock to the list. |
|
1153 synchronized (list) { |
|
1154 ArrayList<FileLockReference> current = lockMap.get(fileKey); |
|
1155 if (list == current) { |
|
1156 checkList(list, fl.position(), fl.size()); |
|
1157 list.add(new FileLockReference(fl, queue, fileKey)); |
|
1158 break; |
|
1159 } |
|
1160 list = current; |
|
1161 } |
|
1162 |
|
1163 } |
|
1164 |
|
1165 // process any stale entries pending in the reference queue |
|
1166 removeStaleEntries(); |
|
1167 } |
|
1168 |
|
1169 private void removeKeyIfEmpty(FileKey fk, ArrayList<FileLockReference> list) { |
|
1170 assert Thread.holdsLock(list); |
|
1171 assert lockMap.get(fk) == list; |
|
1172 if (list.isEmpty()) { |
|
1173 lockMap.remove(fk); |
|
1174 } |
|
1175 } |
|
1176 |
|
1177 public void remove(FileLock fl) { |
|
1178 assert fl != null; |
|
1179 |
|
1180 // the lock must exist so the list of locks must be present |
|
1181 ArrayList<FileLockReference> list = lockMap.get(fileKey); |
|
1182 assert list != null; |
|
1183 |
|
1184 synchronized (list) { |
|
1185 int index = 0; |
|
1186 while (index < list.size()) { |
|
1187 FileLockReference ref = list.get(index); |
|
1188 FileLock lock = ref.get(); |
|
1189 if (lock == fl) { |
|
1190 assert (lock != null) && (lock.channel() == fci); |
|
1191 ref.clear(); |
|
1192 list.remove(index); |
|
1193 break; |
|
1194 } |
|
1195 index++; |
|
1196 } |
|
1197 } |
|
1198 } |
|
1199 |
|
1200 public void removeAll(Releaser releaser) throws IOException { |
|
1201 ArrayList<FileLockReference> list = lockMap.get(fileKey); |
|
1202 if (list != null) { |
|
1203 synchronized (list) { |
|
1204 int index = 0; |
|
1205 while (index < list.size()) { |
|
1206 FileLockReference ref = list.get(index); |
|
1207 FileLock lock = ref.get(); |
|
1208 |
|
1209 // remove locks obtained by this channel |
|
1210 if (lock != null && lock.channel() == fci) { |
|
1211 // invoke the releaser to invalidate/release the lock |
|
1212 releaser.release(lock); |
|
1213 |
|
1214 // remove the lock from the list |
|
1215 ref.clear(); |
|
1216 list.remove(index); |
|
1217 } else { |
|
1218 index++; |
|
1219 } |
|
1220 } |
|
1221 |
|
1222 // once the lock list is empty we remove it from the map |
|
1223 removeKeyIfEmpty(fileKey, list); |
|
1224 } |
|
1225 } |
|
1226 } |
|
1227 |
|
1228 public void replace(FileLock fromLock, FileLock toLock) { |
|
1229 // the lock must exist so there must be a list |
|
1230 ArrayList<FileLockReference> list = lockMap.get(fileKey); |
|
1231 assert list != null; |
|
1232 |
|
1233 synchronized (list) { |
|
1234 for (int index=0; index<list.size(); index++) { |
|
1235 FileLockReference ref = list.get(index); |
|
1236 FileLock lock = ref.get(); |
|
1237 if (lock == fromLock) { |
|
1238 ref.clear(); |
|
1239 list.set(index, new FileLockReference(toLock, queue, fileKey)); |
|
1240 break; |
|
1241 } |
|
1242 } |
|
1243 } |
|
1244 } |
|
1245 |
|
1246 // Check for overlapping file locks |
|
1247 private void checkList(List<FileLockReference> list, long position, long size) |
|
1248 throws OverlappingFileLockException |
|
1249 { |
|
1250 assert Thread.holdsLock(list); |
|
1251 for (FileLockReference ref: list) { |
|
1252 FileLock fl = ref.get(); |
|
1253 if (fl != null && fl.overlaps(position, size)) |
|
1254 throw new OverlappingFileLockException(); |
|
1255 } |
|
1256 } |
|
1257 |
|
1258 // Process the reference queue |
|
1259 private void removeStaleEntries() { |
|
1260 FileLockReference ref; |
|
1261 while ((ref = (FileLockReference)queue.poll()) != null) { |
|
1262 FileKey fk = ref.fileKey(); |
|
1263 ArrayList<FileLockReference> list = lockMap.get(fk); |
|
1264 if (list != null) { |
|
1265 synchronized (list) { |
|
1266 list.remove(ref); |
|
1267 removeKeyIfEmpty(fk, list); |
|
1268 } |
|
1269 } |
|
1270 } |
|
1271 } |
|
1272 } |
|
1273 |
|
1274 // -- Native methods -- |
1042 // -- Native methods -- |
1275 |
|
1276 // Grabs a file lock |
|
1277 native int lock0(FileDescriptor fd, boolean blocking, long pos, long size, |
|
1278 boolean shared) throws IOException; |
|
1279 |
|
1280 // Releases a file lock |
|
1281 native void release0(FileDescriptor fd, long pos, long size) |
|
1282 throws IOException; |
|
1283 |
1043 |
1284 // Creates a new mapping |
1044 // Creates a new mapping |
1285 private native long map0(int prot, long position, long length) |
1045 private native long map0(int prot, long position, long length) |
1286 throws IOException; |
1046 throws IOException; |
1287 |
1047 |
1288 // Removes an existing mapping |
1048 // Removes an existing mapping |
1289 private static native int unmap0(long address, long length); |
1049 private static native int unmap0(long address, long length); |
1290 |
|
1291 // Forces output to device |
|
1292 private native int force0(FileDescriptor fd, boolean metaData); |
|
1293 |
|
1294 // Truncates a file |
|
1295 private native int truncate0(FileDescriptor fd, long size); |
|
1296 |
1050 |
1297 // Transfers from src to dst, or returns -2 if kernel can't do that |
1051 // Transfers from src to dst, or returns -2 if kernel can't do that |
1298 private native long transferTo0(int src, long position, long count, int dst); |
1052 private native long transferTo0(int src, long position, long count, int dst); |
1299 |
1053 |
1300 // Sets or reports this file's position |
1054 // Sets or reports this file's position |
1301 // If offset is -1, the current position is returned |
1055 // If offset is -1, the current position is returned |
1302 // otherwise the position is set to offset |
1056 // otherwise the position is set to offset |
1303 private native long position0(FileDescriptor fd, long offset); |
1057 private native long position0(FileDescriptor fd, long offset); |
1304 |
1058 |
1305 // Reports this file's size |
|
1306 private native long size0(FileDescriptor fd); |
|
1307 |
|
1308 // Caches fieldIDs |
1059 // Caches fieldIDs |
1309 private static native long initIDs(); |
1060 private static native long initIDs(); |
1310 |
1061 |
1311 static { |
1062 static { |
1312 Util.load(); |
1063 Util.load(); |
1313 allocationGranularity = initIDs(); |
1064 allocationGranularity = initIDs(); |
1314 nd = new FileDispatcher(); |
1065 nd = new FileDispatcherImpl(); |
1315 } |
1066 } |
1316 |
1067 |
1317 } |
1068 } |