jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java
changeset 2057 3acf8e5e2ca0
parent 1821 fe2556ead537
child 2441 228c040622a2
equal deleted inserted replaced
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 }