jdk/src/windows/classes/sun/nio/ch/PendingIoCache.java
changeset 2057 3acf8e5e2ca0
child 5506 202f599c92aa
equal deleted inserted replaced
2056:115e09b7a004 2057:3acf8e5e2ca0
       
     1 /*
       
     2  * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.nio.ch;
       
    27 
       
    28 import java.nio.channels.*;
       
    29 import java.util.*;
       
    30 import sun.misc.Unsafe;
       
    31 
       
    32 /**
       
    33  * Maintains a mapping of pending I/O requests (identified by the address of
       
    34  * an OVERLAPPED structure) to Futures.
       
    35  */
       
    36 
       
    37 class PendingIoCache {
       
    38     private static final Unsafe unsafe = Unsafe.getUnsafe();
       
    39     private static final int addressSize = unsafe.addressSize();
       
    40 
       
    41     private static int dependsArch(int value32, int value64) {
       
    42         return (addressSize == 4) ? value32 : value64;
       
    43     }
       
    44 
       
    45     /*
       
    46      * typedef struct _OVERLAPPED {
       
    47      *     DWORD  Internal;
       
    48      *     DWORD  InternalHigh;
       
    49      *     DWORD  Offset;
       
    50      *     DWORD  OffsetHigh;
       
    51      *     HANDLE hEvent;
       
    52      * } OVERLAPPED;
       
    53      */
       
    54     private static final int SIZEOF_OVERLAPPED = dependsArch(20, 32);
       
    55 
       
    56     // set to true when closed
       
    57     private boolean closed;
       
    58 
       
    59     // set to true when thread is waiting for all I/O operations to complete
       
    60     private boolean closePending;
       
    61 
       
    62     // maps OVERLAPPED to PendingFuture
       
    63     private final Map<Long,PendingFuture> pendingIoMap =
       
    64         new HashMap<Long,PendingFuture>();
       
    65 
       
    66     // per-channel cache of OVERLAPPED structures
       
    67     private long[] overlappedCache = new long[4];
       
    68     private int overlappedCacheCount = 0;
       
    69 
       
    70     PendingIoCache() {
       
    71     }
       
    72 
       
    73     long add(PendingFuture<?,?> result) {
       
    74         synchronized (this) {
       
    75             if (closed)
       
    76                 throw new AssertionError("Should not get here");
       
    77             long ov;
       
    78             if (overlappedCacheCount > 0) {
       
    79                 ov = overlappedCache[--overlappedCacheCount];
       
    80             } else {
       
    81                 ov = unsafe.allocateMemory(SIZEOF_OVERLAPPED);
       
    82             }
       
    83             pendingIoMap.put(ov, result);
       
    84             return ov;
       
    85         }
       
    86     }
       
    87 
       
    88     @SuppressWarnings("unchecked")
       
    89     <V,A> PendingFuture<V,A> remove(long overlapped) {
       
    90         synchronized (this) {
       
    91             PendingFuture<V,A> res = pendingIoMap.remove(overlapped);
       
    92             if (res != null) {
       
    93                 if (overlappedCacheCount < overlappedCache.length) {
       
    94                     overlappedCache[overlappedCacheCount++] = overlapped;
       
    95                 } else {
       
    96                     // cache full or channel closing
       
    97                     unsafe.freeMemory(overlapped);
       
    98                 }
       
    99                 // notify closing thread.
       
   100                 if (closePending) {
       
   101                     this.notifyAll();
       
   102                 }
       
   103             }
       
   104             return res;
       
   105         }
       
   106     }
       
   107 
       
   108     void close() {
       
   109         synchronized (this) {
       
   110             if (closed)
       
   111                 return;
       
   112 
       
   113             // handle the case that where there are I/O operations that have
       
   114             // not completed.
       
   115             if (!pendingIoMap.isEmpty())
       
   116                 clearPendingIoMap();
       
   117 
       
   118             // release memory for any cached OVERLAPPED structures
       
   119             while (overlappedCacheCount > 0) {
       
   120                 unsafe.freeMemory( overlappedCache[--overlappedCacheCount] );
       
   121             }
       
   122 
       
   123             // done
       
   124             closed = true;
       
   125         }
       
   126     }
       
   127 
       
   128     private void clearPendingIoMap() {
       
   129         assert Thread.holdsLock(this);
       
   130 
       
   131         // wait up to 50ms for the I/O operations to complete
       
   132         closePending = true;
       
   133         try {
       
   134             this.wait(50);
       
   135         } catch (InterruptedException x) { }
       
   136         closePending = false;
       
   137         if (pendingIoMap.isEmpty())
       
   138             return;
       
   139 
       
   140         // cause all pending I/O operations to fail
       
   141         // simulate the failure of all pending I/O operations.
       
   142         for (Long ov: pendingIoMap.keySet()) {
       
   143             PendingFuture<?,?> result = pendingIoMap.get(ov);
       
   144             assert !result.isDone();
       
   145 
       
   146             // make I/O port aware of the stale OVERLAPPED structure
       
   147             Iocp iocp = (Iocp)((Groupable)result.channel()).group();
       
   148             iocp.makeStale(ov);
       
   149 
       
   150             // execute a task that invokes the result handler's failed method
       
   151             final Iocp.ResultHandler rh = (Iocp.ResultHandler)result.getContext();
       
   152             Runnable task = new Runnable() {
       
   153                 public void run() {
       
   154                     rh.failed(-1, new AsynchronousCloseException());
       
   155                 }
       
   156             };
       
   157             iocp.executeOnPooledThread(task);
       
   158         }
       
   159         pendingIoMap.clear();
       
   160     }
       
   161 }