1 /* 2 * Copyright (c) 2008, 2011, 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.channels.*; 29 import java.util.*; 30 import jdk.internal.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 @SuppressWarnings("rawtypes") 64 private final Map<Long,PendingFuture> pendingIoMap = 65 new HashMap<Long,PendingFuture>(); 66 67 // per-channel cache of OVERLAPPED structures 68 private long[] overlappedCache = new long[4]; 69 private int overlappedCacheCount = 0; 70 71 PendingIoCache() { 72 } 73 74 long add(PendingFuture<?,?> result) { 75 synchronized (this) { 76 if (closed) 77 throw new AssertionError("Should not get here"); 78 long ov; 79 if (overlappedCacheCount > 0) { 80 ov = overlappedCache[--overlappedCacheCount]; 81 } else { 82 ov = unsafe.allocateMemory(SIZEOF_OVERLAPPED); 83 } 84 pendingIoMap.put(ov, result); 85 return ov; 86 } 87 } 88 89 @SuppressWarnings("unchecked") 90 <V,A> PendingFuture<V,A> remove(long overlapped) { 91 synchronized (this) { 92 PendingFuture<V,A> res = pendingIoMap.remove(overlapped); 93 if (res != null) { 94 if (overlappedCacheCount < overlappedCache.length) { 95 overlappedCache[overlappedCacheCount++] = overlapped; 96 } else { 97 // cache full or channel closing 98 unsafe.freeMemory(overlapped); 99 } 100 // notify closing thread. 101 if (closePending) { 102 this.notifyAll(); 103 } 104 } 105 return res; 106 } 107 } 108 109 void close() { 110 synchronized (this) { 111 if (closed) 112 return; 113 114 // handle case where I/O operations that have 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 Thread.currentThread().interrupt(); 137 } 138 closePending = false; 139 if (pendingIoMap.isEmpty()) 140 return; 141 142 // cause all pending I/O operations to fail 143 // simulate the failure of all pending I/O operations. 144 for (Long ov: pendingIoMap.keySet()) { 145 PendingFuture<?,?> result = pendingIoMap.get(ov); 146 assert !result.isDone(); 147 148 // make I/O port aware of the stale OVERLAPPED structure 149 Iocp iocp = (Iocp)((Groupable)result.channel()).group(); 150 iocp.makeStale(ov); 151 152 // execute a task that invokes the result handler's failed method 153 final Iocp.ResultHandler rh = (Iocp.ResultHandler)result.getContext(); 154 Runnable task = new Runnable() { 155 public void run() { 156 rh.failed(-1, new AsynchronousCloseException()); 157 } 158 }; 159 iocp.executeOnPooledThread(task); 160 } 161 pendingIoMap.clear(); 162 } 163 }