8026716: (aio) Enhance asynchronous channel handling
authoralanb
Thu, 19 Dec 2013 12:14:04 +0000
changeset 23894 7500e0f62a4a
parent 23893 1a92335b55bb
child 23895 ede5bb2c36bf
8026716: (aio) Enhance asynchronous channel handling Reviewed-by: chegar, ahgross
jdk/src/share/classes/sun/misc/InnocuousThread.java
jdk/src/share/classes/sun/nio/ch/Invoker.java
jdk/src/share/classes/sun/nio/ch/ThreadPool.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/misc/InnocuousThread.java	Thu Dec 19 12:14:04 2013 +0000
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. 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 GNUNSAFE General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUNSAFET
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICUNSAFELAR PUNSAFERPOSE.  See the GNUNSAFE 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 GNUNSAFE 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 UNSAFESA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 UNSAFESA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.misc;
+
+import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
+
+/**
+ * A thread that has no permissions, is not a member of any user-defined
+ * ThreadGroup and supports the ability to erase ThreadLocals.
+ *
+ * @implNote Based on the implementation of InnocuousForkJoinWorkerThread.
+ */
+public final class InnocuousThread extends Thread {
+    private static final Unsafe UNSAFE;
+    private static final ThreadGroup THREADGROUP;
+    private static final AccessControlContext ACC;
+    private static final long THREADLOCALS;
+    private static final long INHERITABLETHREADLOCALS;
+    private static final long INHERITEDACCESSCONTROLCONTEXT;
+
+    public InnocuousThread(Runnable target) {
+        super(THREADGROUP, target, "anInnocuousThread");
+        UNSAFE.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, ACC);
+        eraseThreadLocals();
+    }
+
+    @Override
+    public ClassLoader getContextClassLoader() {
+        // always report system class loader
+        return ClassLoader.getSystemClassLoader();
+    }
+
+    @Override
+    public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) {
+        // silently fail
+    }
+
+    @Override
+    public void setContextClassLoader(ClassLoader cl) {
+        throw new SecurityException("setContextClassLoader");
+    }
+
+    // ensure run method is run only once
+    private volatile boolean hasRun;
+
+    @Override
+    public void run() {
+        if (Thread.currentThread() == this && !hasRun) {
+            hasRun = true;
+            super.run();
+        }
+    }
+
+    /**
+     * Drops all thread locals (and inherited thread locals).
+     */
+    public void eraseThreadLocals() {
+        UNSAFE.putObject(this, THREADLOCALS, null);
+        UNSAFE.putObject(this, INHERITABLETHREADLOCALS, null);
+    }
+
+    // Use Unsafe to access Thread group and ThreadGroup parent fields
+    static {
+        try {
+            ACC = new AccessControlContext(new ProtectionDomain[] {
+                new ProtectionDomain(null, null)
+            });
+
+            // Find and use topmost ThreadGroup as parent of new group
+            UNSAFE = Unsafe.getUnsafe();
+            Class<?> tk = Thread.class;
+            Class<?> gk = ThreadGroup.class;
+
+            THREADLOCALS = UNSAFE.objectFieldOffset
+                (tk.getDeclaredField("threadLocals"));
+            INHERITABLETHREADLOCALS = UNSAFE.objectFieldOffset
+                (tk.getDeclaredField("inheritableThreadLocals"));
+            INHERITEDACCESSCONTROLCONTEXT = UNSAFE.objectFieldOffset
+                (tk.getDeclaredField("inheritedAccessControlContext"));
+
+            long tg = UNSAFE.objectFieldOffset(tk.getDeclaredField("group"));
+            long gp = UNSAFE.objectFieldOffset(gk.getDeclaredField("parent"));
+            ThreadGroup group = (ThreadGroup)
+                UNSAFE.getObject(Thread.currentThread(), tg);
+
+            while (group != null) {
+                ThreadGroup parent = (ThreadGroup)UNSAFE.getObject(group, gp);
+                if (parent == null)
+                    break;
+                group = parent;
+            }
+            THREADGROUP = new ThreadGroup(group, "InnocuousThreadGroup");
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+}
--- a/jdk/src/share/classes/sun/nio/ch/Invoker.java	Fri Dec 20 15:43:41 2013 +0400
+++ b/jdk/src/share/classes/sun/nio/ch/Invoker.java	Thu Dec 19 12:14:04 2013 +0000
@@ -130,6 +130,18 @@
 
         // clear interrupt
         Thread.interrupted();
+
+        // clear thread locals when in default thread pool
+        if (System.getSecurityManager() != null) {
+            Thread me = Thread.currentThread();
+            if (me instanceof sun.misc.InnocuousThread) {
+                GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();
+                ((sun.misc.InnocuousThread)me).eraseThreadLocals();
+                if (thisGroupAndInvokeCount != null) {
+                    myGroupAndInvokeCount.set(thisGroupAndInvokeCount);
+                }
+            }
+        }
     }
 
     /**
--- a/jdk/src/share/classes/sun/nio/ch/ThreadPool.java	Fri Dec 20 15:43:41 2013 +0400
+++ b/jdk/src/share/classes/sun/nio/ch/ThreadPool.java	Thu Dec 19 12:14:04 2013 +0000
@@ -27,6 +27,7 @@
 
 import java.util.concurrent.*;
 import java.security.AccessController;
+import java.security.PrivilegedAction;
 import sun.security.action.GetPropertyAction;
 import sun.security.action.GetIntegerAction;
 
@@ -39,14 +40,6 @@
         "java.nio.channels.DefaultThreadPool.threadFactory";
     private static final String DEFAULT_THREAD_POOL_INITIAL_SIZE =
         "java.nio.channels.DefaultThreadPool.initialSize";
-    private static final ThreadFactory defaultThreadFactory = new ThreadFactory() {
-         @Override
-         public Thread newThread(Runnable r) {
-             Thread t = new Thread(r);
-             t.setDaemon(true);
-             return t;
-        }
-     };
 
     private final ExecutorService executor;
 
@@ -79,7 +72,22 @@
     }
 
     static ThreadFactory defaultThreadFactory() {
-        return defaultThreadFactory;
+        if (System.getSecurityManager() == null) {
+            return (Runnable r) -> {
+                Thread t = new Thread(r);
+                t.setDaemon(true);
+                return t;
+            };
+        } else {
+            return (Runnable r) -> {
+                PrivilegedAction<Thread> action = () -> {
+                    Thread t = new sun.misc.InnocuousThread(r);
+                    t.setDaemon(true);
+                    return t;
+               };
+               return AccessController.doPrivileged(action);
+           };
+        }
     }
 
     private static class DefaultThreadPoolHolder {
@@ -100,7 +108,7 @@
         // default to thread factory that creates daemon threads
         ThreadFactory threadFactory = getDefaultThreadPoolThreadFactory();
         if (threadFactory == null)
-            threadFactory = defaultThreadFactory;
+            threadFactory = defaultThreadFactory();
         // create thread pool
         ExecutorService executor = Executors.newCachedThreadPool(threadFactory);
         return new ThreadPool(executor, false, initialSize);