diff options
author | tbell <none@none> | 2009-05-04 22:16:02 -0700 |
---|---|---|
committer | tbell <none@none> | 2009-05-04 22:16:02 -0700 |
commit | 2a66fd71f64b3fb47381937151270500530e64ed (patch) | |
tree | be7dde0c338436533851fc69c681b645fcc456fc /src | |
parent | 290c39b41bf3485eeb745eb79e260ea72ef7ffe0 (diff) | |
parent | 1e085183b40b55ce035f45133b2163713a5dbc60 (diff) |
Merge
Diffstat (limited to 'src')
-rw-r--r-- | src/share/classes/java/io/Console.java | 33 | ||||
-rw-r--r-- | src/share/classes/java/io/DeleteOnExitHook.java | 28 | ||||
-rw-r--r-- | src/share/classes/java/lang/ApplicationShutdownHooks.java | 23 | ||||
-rw-r--r-- | src/share/classes/java/lang/Shutdown.java | 47 | ||||
-rw-r--r-- | src/share/classes/java/lang/System.java | 4 | ||||
-rw-r--r-- | src/share/classes/java/util/zip/ZipFile.java | 6 | ||||
-rw-r--r-- | src/share/classes/java/util/zip/ZipInputStream.java | 2 | ||||
-rw-r--r-- | src/share/classes/java/util/zip/ZipOutputStream.java | 2 | ||||
-rw-r--r-- | src/share/classes/sun/misc/JavaLangAccess.java | 20 | ||||
-rw-r--r-- | src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java | 112 | ||||
-rw-r--r-- | src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c | 17 |
11 files changed, 161 insertions, 133 deletions
diff --git a/src/share/classes/java/io/Console.java b/src/share/classes/java/io/Console.java index 201b66f71..abd0e0c04 100644 --- a/src/share/classes/java/io/Console.java +++ b/src/share/classes/java/io/Console.java @@ -503,20 +503,25 @@ public final class Console implements Flushable // Set up JavaIOAccess in SharedSecrets static { - - // Add a shutdown hook to restore console's echo state should - // it be necessary. - sun.misc.SharedSecrets.getJavaLangAccess() - .registerShutdownHook(0 /* shutdown hook invocation order */, - new Runnable() { - public void run() { - try { - if (echoOff) { - echo(true); - } - } catch (IOException x) { } - } - }); + try { + // Add a shutdown hook to restore console's echo state should + // it be necessary. + sun.misc.SharedSecrets.getJavaLangAccess() + .registerShutdownHook(0 /* shutdown hook invocation order */, + false /* only register if shutdown is not in progress */, + new Runnable() { + public void run() { + try { + if (echoOff) { + echo(true); + } + } catch (IOException x) { } + } + }); + } catch (IllegalStateException e) { + // shutdown is already in progress and console is first used + // by a shutdown hook + } sun.misc.SharedSecrets.setJavaIOAccess(new sun.misc.JavaIOAccess() { public Console console() { diff --git a/src/share/classes/java/io/DeleteOnExitHook.java b/src/share/classes/java/io/DeleteOnExitHook.java index 1dc5c9d85..44d604c4d 100644 --- a/src/share/classes/java/io/DeleteOnExitHook.java +++ b/src/share/classes/java/io/DeleteOnExitHook.java @@ -34,23 +34,31 @@ import java.io.File; */ class DeleteOnExitHook { + private static LinkedHashSet<String> files = new LinkedHashSet<String>(); static { - sun.misc.SharedSecrets.getJavaLangAccess() - .registerShutdownHook(2 /* Shutdown hook invocation order */, - new Runnable() { - public void run() { - runHooks(); - } - }); + // DeleteOnExitHook must be the last shutdown hook to be invoked. + // Application shutdown hooks may add the first file to the + // delete on exit list and cause the DeleteOnExitHook to be + // registered during shutdown in progress. So set the + // registerShutdownInProgress parameter to true. + sun.misc.SharedSecrets.getJavaLangAccess() + .registerShutdownHook(2 /* Shutdown hook invocation order */, + true /* register even if shutdown in progress */, + new Runnable() { + public void run() { + runHooks(); + } + } + ); } - private static LinkedHashSet<String> files = new LinkedHashSet<String>(); - private DeleteOnExitHook() {} static synchronized void add(String file) { - if(files == null) + if(files == null) { + // DeleteOnExitHook is running. Too late to add a file throw new IllegalStateException("Shutdown in progress"); + } files.add(file); } diff --git a/src/share/classes/java/lang/ApplicationShutdownHooks.java b/src/share/classes/java/lang/ApplicationShutdownHooks.java index b3341de15..1afe8fad2 100644 --- a/src/share/classes/java/lang/ApplicationShutdownHooks.java +++ b/src/share/classes/java/lang/ApplicationShutdownHooks.java @@ -35,17 +35,26 @@ import java.util.*; */ class ApplicationShutdownHooks { + /* The set of registered hooks */ + private static IdentityHashMap<Thread, Thread> hooks; static { - Shutdown.add(1 /* shutdown hook invocation order */, - new Runnable() { - public void run() { - runHooks(); + try { + Shutdown.add(1 /* shutdown hook invocation order */, + false /* not registered if shutdown in progress */, + new Runnable() { + public void run() { + runHooks(); + } } - }); + ); + hooks = new IdentityHashMap<Thread, Thread>(); + } catch (IllegalStateException e) { + // application shutdown hooks cannot be added if + // shutdown is in progress. + hooks = null; + } } - /* The set of registered hooks */ - private static IdentityHashMap<Thread, Thread> hooks = new IdentityHashMap<Thread, Thread>(); private ApplicationShutdownHooks() {} diff --git a/src/share/classes/java/lang/Shutdown.java b/src/share/classes/java/lang/Shutdown.java index b77b45056..2d0b0dd03 100644 --- a/src/share/classes/java/lang/Shutdown.java +++ b/src/share/classes/java/lang/Shutdown.java @@ -53,6 +53,9 @@ class Shutdown { private static final int MAX_SYSTEM_HOOKS = 10; private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS]; + // the index of the currently running shutdown hook to the hooks array + private static int currentRunningHook = 0; + /* The preceding static fields are protected by this lock */ private static class Lock { }; private static Object lock = new Lock(); @@ -68,17 +71,39 @@ class Shutdown { } - /* Add a new shutdown hook. Checks the shutdown state and the hook itself, + /** + * Add a new shutdown hook. Checks the shutdown state and the hook itself, * but does not do any security checks. + * + * The registerShutdownInProgress parameter should be false except + * registering the DeleteOnExitHook since the first file may + * be added to the delete on exit list by the application shutdown + * hooks. + * + * @params slot the slot in the shutdown hook array, whose element + * will be invoked in order during shutdown + * @params registerShutdownInProgress true to allow the hook + * to be registered even if the shutdown is in progress. + * @params hook the hook to be registered + * + * @throw IllegalStateException + * if registerShutdownInProgress is false and shutdown is in progress; or + * if registerShutdownInProgress is true and the shutdown process + * already passes the given slot */ - static void add(int slot, Runnable hook) { + static void add(int slot, boolean registerShutdownInProgress, Runnable hook) { synchronized (lock) { - if (state > RUNNING) - throw new IllegalStateException("Shutdown in progress"); - if (hooks[slot] != null) throw new InternalError("Shutdown hook at slot " + slot + " already registered"); + if (!registerShutdownInProgress) { + if (state > RUNNING) + throw new IllegalStateException("Shutdown in progress"); + } else { + if (state > HOOKS || (state == HOOKS && slot <= currentRunningHook)) + throw new IllegalStateException("Shutdown in progress"); + } + hooks[slot] = hook; } } @@ -86,11 +111,15 @@ class Shutdown { /* Run all registered shutdown hooks */ private static void runHooks() { - /* We needn't bother acquiring the lock just to read the hooks field, - * since the hooks can't be modified once shutdown is in progress - */ - for (Runnable hook : hooks) { + for (int i=0; i < MAX_SYSTEM_HOOKS; i++) { try { + Runnable hook; + synchronized (lock) { + // acquire the lock to make sure the hook registered during + // shutdown is visible here. + currentRunningHook = i; + hook = hooks[i]; + } if (hook != null) hook.run(); } catch(Throwable t) { if (t instanceof ThreadDeath) { diff --git a/src/share/classes/java/lang/System.java b/src/share/classes/java/lang/System.java index 6c539b28e..902591332 100644 --- a/src/share/classes/java/lang/System.java +++ b/src/share/classes/java/lang/System.java @@ -1171,8 +1171,8 @@ public final class System { public void blockedOn(Thread t, Interruptible b) { t.blockedOn(b); } - public void registerShutdownHook(int slot, Runnable r) { - Shutdown.add(slot, r); + public void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook) { + Shutdown.add(slot, registerShutdownInProgress, hook); } }); } diff --git a/src/share/classes/java/util/zip/ZipFile.java b/src/share/classes/java/util/zip/ZipFile.java index 8ee0bc2eb..f37121c52 100644 --- a/src/share/classes/java/util/zip/ZipFile.java +++ b/src/share/classes/java/util/zip/ZipFile.java @@ -154,7 +154,7 @@ class ZipFile implements ZipConstants { * @param file the ZIP file to be opened for reading * @param mode the mode in which the file is to be opened * @param charset - * the {@link java.nio.charset.Charset {@code charset}} to + * the {@linkplain java.nio.charset.Charset charset} to * be used to decode the ZIP entry name and comment that are not * encoded by using UTF-8 encoding (indicated by entry's general * purpose flag). @@ -206,7 +206,7 @@ class ZipFile implements ZipConstants { * * @param name the name of the zip file * @param charset - * the {@link java.nio.charset.Charset {@code charset}} to + * the {@linkplain java.nio.charset.Charset charset} to * be used to decode the ZIP entry name and comment that are not * encoded by using UTF-8 encoding (indicated by entry's general * purpose flag). @@ -230,7 +230,7 @@ class ZipFile implements ZipConstants { * Opens a ZIP file for reading given the specified File object. * @param file the ZIP file to be opened for reading * @param charset - * The {@link java.nio.charset.Charset {@code charset}} to be + * The {@linkplain java.nio.charset.Charset charset} to be * used to decode the ZIP entry name and comment (ignored if * the <a href="package-summary.html#lang_encoding"> language * encoding bit</a> of the ZIP entry's general purpose bit diff --git a/src/share/classes/java/util/zip/ZipInputStream.java b/src/share/classes/java/util/zip/ZipInputStream.java index 83f9ad4b7..ed6f331e8 100644 --- a/src/share/classes/java/util/zip/ZipInputStream.java +++ b/src/share/classes/java/util/zip/ZipInputStream.java @@ -84,7 +84,7 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { * @param in the actual input stream * * @param charset - * The {@link java.nio.charset.Charset {@code charset}} to be + * The {@linkplain java.nio.charset.Charset charset} to be * used to decode the ZIP entry name (ignored if the * <a href="package-summary.html#lang_encoding"> language * encoding bit</a> of the ZIP entry's general purpose bit diff --git a/src/share/classes/java/util/zip/ZipOutputStream.java b/src/share/classes/java/util/zip/ZipOutputStream.java index da35ed97f..d33a922eb 100644 --- a/src/share/classes/java/util/zip/ZipOutputStream.java +++ b/src/share/classes/java/util/zip/ZipOutputStream.java @@ -108,7 +108,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { * * @param out the actual output stream * - * @param charset the {@link java.nio.charset.Charset </code>charset<code>} + * @param charset the {@linkplain java.nio.charset.Charset charset} * to be used to encode the entry names and comments * * @since 1.7 diff --git a/src/share/classes/sun/misc/JavaLangAccess.java b/src/share/classes/sun/misc/JavaLangAccess.java index c288bc840..846a671b7 100644 --- a/src/share/classes/sun/misc/JavaLangAccess.java +++ b/src/share/classes/sun/misc/JavaLangAccess.java @@ -55,6 +55,22 @@ public interface JavaLangAccess { /** Set thread's blocker field. */ void blockedOn(Thread t, Interruptible b); - /** register shutdown hook */ - void registerShutdownHook(int slot, Runnable r); + /** + * Registers a shutdown hook. + * + * It is expected that this method with registerShutdownInProgress=true + * is only used to register DeleteOnExitHook since the first file + * may be added to the delete on exit list by the application shutdown + * hooks. + * + * @params slot the slot in the shutdown hook array, whose element + * will be invoked in order during shutdown + * @params registerShutdownInProgress true to allow the hook + * to be registered even if the shutdown is in progress. + * @params hook the hook to be registered + * + * @throw IllegalStateException if shutdown is in progress and + * the slot is not valid to register. + */ + void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook); } diff --git a/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java b/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java index d1f8c9307..5ec0af046 100644 --- a/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java +++ b/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java @@ -475,49 +475,40 @@ class WindowsAsynchronousSocketChannelImpl // get an OVERLAPPED structure (from the cache or allocate) overlapped = ioCache.add(result); - // synchronize on result to allow this thread handle the case - // where the read completes immediately. - synchronized (result) { - int n = read0(handle, numBufs, readBufferArray, overlapped); - if (n == IOStatus.UNAVAILABLE) { - // I/O is pending - pending = true; - return; - } - // read completed immediately: - // 1. update buffer position - // 2. reset read flag - // 3. release waiters - if (n == 0) { - n = -1; - } else { - updateBuffers(n); - } + // initiate read + int n = read0(handle, numBufs, readBufferArray, overlapped); + if (n == IOStatus.UNAVAILABLE) { + // I/O is pending + pending = true; + return; + } + if (n == IOStatus.EOF) { + // input shutdown enableReading(); - if (scatteringRead) { - result.setResult((V)Long.valueOf(n)); + result.setResult((V)Long.valueOf(-1L)); } else { - result.setResult((V)Integer.valueOf(n)); + result.setResult((V)Integer.valueOf(-1)); } + } else { + throw new InternalError("Read completed immediately"); } } catch (Throwable x) { - // failed to initiate read: - // 1. reset read flag - // 2. free resources - // 3. release waiters + // failed to initiate read + // reset read flag before releasing waiters enableReading(); - if (overlapped != 0L) - ioCache.remove(overlapped); if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); if (!(x instanceof IOException)) x = new IOException(x); result.setFailure(x); } finally { - if (prepared && !pending) { - // return direct buffer(s) to cache if substituted - releaseBuffers(); + // release resources if I/O not pending + if (!pending) { + if (overlapped != 0L) + ioCache.remove(overlapped); + if (prepared) + releaseBuffers(); } end(); } @@ -721,7 +712,6 @@ class WindowsAsynchronousSocketChannelImpl @Override @SuppressWarnings("unchecked") public void run() { - int n = -1; long overlapped = 0L; boolean prepared = false; boolean pending = false; @@ -736,56 +726,34 @@ class WindowsAsynchronousSocketChannelImpl // get an OVERLAPPED structure (from the cache or allocate) overlapped = ioCache.add(result); - - // synchronize on result to allow this thread handle the case - // where the read completes immediately. - synchronized (result) { - n = write0(handle, numBufs, writeBufferArray, overlapped); - if (n == IOStatus.UNAVAILABLE) { - // I/O is pending - pending = true; - return; - } - - enableWriting(); - - if (n == IOStatus.EOF) { - // special case for shutdown output - shutdown = true; - throw new ClosedChannelException(); - } - - // write completed immediately: - // 1. enable writing - // 2. update buffer position - // 3. release waiters - updateBuffers(n); - - // result is a Long or Integer - if (gatheringWrite) { - result.setResult((V)Long.valueOf(n)); - } else { - result.setResult((V)Integer.valueOf(n)); - } + int n = write0(handle, numBufs, writeBufferArray, overlapped); + if (n == IOStatus.UNAVAILABLE) { + // I/O is pending + pending = true; + return; } + if (n == IOStatus.EOF) { + // special case for shutdown output + shutdown = true; + throw new ClosedChannelException(); + } + // write completed immediately + throw new InternalError("Write completed immediately"); } catch (Throwable x) { + // write failed. Enable writing before releasing waiters. enableWriting(); - - // failed to initiate read: if (!shutdown && (x instanceof ClosedChannelException)) x = new AsynchronousCloseException(); if (!(x instanceof IOException)) x = new IOException(x); result.setFailure(x); - - // release resources - if (overlapped != 0L) - ioCache.remove(overlapped); - } finally { - if (prepared && !pending) { - // return direct buffer(s) to cache if substituted - releaseBuffers(); + // release resources if I/O not pending + if (!pending) { + if (overlapped != 0L) + ioCache.remove(overlapped); + if (prepared) + releaseBuffers(); } end(); } diff --git a/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c b/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c index 97c49f60a..c9a1972f4 100644 --- a/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c +++ b/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c @@ -157,14 +157,13 @@ Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_read0(JNIEnv* env, jclass t WSABUF* lpWsaBuf = (WSABUF*) jlong_to_ptr(address); OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov); BOOL res; - DWORD nread = 0; DWORD flags = 0; ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED)); res = WSARecv(s, lpWsaBuf, (DWORD)count, - &nread, + NULL, &flags, lpOverlapped, NULL); @@ -175,17 +174,12 @@ Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_read0(JNIEnv* env, jclass t return IOS_UNAVAILABLE; } if (error == WSAESHUTDOWN) { - return 0; // input shutdown + return IOS_EOF; // input shutdown } JNU_ThrowIOExceptionWithLastError(env, "WSARecv failed"); return IOS_THROWN; } - if (nread == 0) { - // Handle graceful close or bytes not yet available cases - // via completion port notification. - return IOS_UNAVAILABLE; - } - return (jint)nread; + return IOS_UNAVAILABLE; } JNIEXPORT jint JNICALL @@ -196,13 +190,12 @@ Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_write0(JNIEnv* env, jclass WSABUF* lpWsaBuf = (WSABUF*) jlong_to_ptr(address); OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov); BOOL res; - DWORD nwritten; ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED)); res = WSASend(s, lpWsaBuf, (DWORD)count, - &nwritten, + NULL, 0, lpOverlapped, NULL); @@ -218,5 +211,5 @@ Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_write0(JNIEnv* env, jclass JNU_ThrowIOExceptionWithLastError(env, "WSASend failed"); return IOS_THROWN; } - return (jint)nwritten; + return IOS_UNAVAILABLE; } |