--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/ch/PendingIoCache.java Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.util.*;
+import sun.misc.Unsafe;
+
+/**
+ * Maintains a mapping of pending I/O requests (identified by the address of
+ * an OVERLAPPED structure) to Futures.
+ */
+
+class PendingIoCache {
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+ private static final int addressSize = unsafe.addressSize();
+
+ private static int dependsArch(int value32, int value64) {
+ return (addressSize == 4) ? value32 : value64;
+ }
+
+ /*
+ * typedef struct _OVERLAPPED {
+ * DWORD Internal;
+ * DWORD InternalHigh;
+ * DWORD Offset;
+ * DWORD OffsetHigh;
+ * HANDLE hEvent;
+ * } OVERLAPPED;
+ */
+ private static final int SIZEOF_OVERLAPPED = dependsArch(20, 32);
+
+ // set to true when closed
+ private boolean closed;
+
+ // set to true when thread is waiting for all I/O operations to complete
+ private boolean closePending;
+
+ // maps OVERLAPPED to PendingFuture
+ private final Map<Long,PendingFuture> pendingIoMap =
+ new HashMap<Long,PendingFuture>();
+
+ // per-channel cache of OVERLAPPED structures
+ private long[] overlappedCache = new long[4];
+ private int overlappedCacheCount = 0;
+
+ PendingIoCache() {
+ }
+
+ long add(PendingFuture<?,?> result) {
+ synchronized (this) {
+ if (closed)
+ throw new AssertionError("Should not get here");
+ long ov;
+ if (overlappedCacheCount > 0) {
+ ov = overlappedCache[--overlappedCacheCount];
+ } else {
+ ov = unsafe.allocateMemory(SIZEOF_OVERLAPPED);
+ }
+ pendingIoMap.put(ov, result);
+ return ov;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ <V,A> PendingFuture<V,A> remove(long overlapped) {
+ synchronized (this) {
+ PendingFuture<V,A> res = pendingIoMap.remove(overlapped);
+ if (res != null) {
+ if (overlappedCacheCount < overlappedCache.length) {
+ overlappedCache[overlappedCacheCount++] = overlapped;
+ } else {
+ // cache full or channel closing
+ unsafe.freeMemory(overlapped);
+ }
+ // notify closing thread.
+ if (closePending) {
+ this.notifyAll();
+ }
+ }
+ return res;
+ }
+ }
+
+ void close() {
+ synchronized (this) {
+ if (closed)
+ return;
+
+ // handle the case that where there are I/O operations that have
+ // not completed.
+ if (!pendingIoMap.isEmpty())
+ clearPendingIoMap();
+
+ // release memory for any cached OVERLAPPED structures
+ while (overlappedCacheCount > 0) {
+ unsafe.freeMemory( overlappedCache[--overlappedCacheCount] );
+ }
+
+ // done
+ closed = true;
+ }
+ }
+
+ private void clearPendingIoMap() {
+ assert Thread.holdsLock(this);
+
+ // wait up to 50ms for the I/O operations to complete
+ closePending = true;
+ try {
+ this.wait(50);
+ } catch (InterruptedException x) { }
+ closePending = false;
+ if (pendingIoMap.isEmpty())
+ return;
+
+ // cause all pending I/O operations to fail
+ // simulate the failure of all pending I/O operations.
+ for (Long ov: pendingIoMap.keySet()) {
+ PendingFuture<?,?> result = pendingIoMap.get(ov);
+ assert !result.isDone();
+
+ // make I/O port aware of the stale OVERLAPPED structure
+ Iocp iocp = (Iocp)((Groupable)result.channel()).group();
+ iocp.makeStale(ov);
+
+ // execute a task that invokes the result handler's failed method
+ final Iocp.ResultHandler rh = (Iocp.ResultHandler)result.getContext();
+ Runnable task = new Runnable() {
+ public void run() {
+ rh.failed(-1, new AsynchronousCloseException());
+ }
+ };
+ iocp.executeOnPooledThread(task);
+ }
+ pendingIoMap.clear();
+ }
+}