Path: blob/master/src/java.base/share/classes/jdk/internal/misc/InnocuousThread.java
41159 views
/*1* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package jdk.internal.misc;2627import java.security.AccessControlContext;28import java.security.AccessController;29import java.security.ProtectionDomain;30import java.security.PrivilegedAction;31import java.util.concurrent.atomic.AtomicInteger;3233/**34* A thread that has no permissions, is not a member of any user-defined35* ThreadGroup and supports the ability to erase ThreadLocals.36*/37@SuppressWarnings("removal")38public final class InnocuousThread extends Thread {39private static final jdk.internal.misc.Unsafe UNSAFE;40private static final long THREAD_LOCALS;41private static final long INHERITABLE_THREAD_LOCALS;42private static final ThreadGroup INNOCUOUSTHREADGROUP;43private static final AccessControlContext ACC;44private static final long INHERITEDACCESSCONTROLCONTEXT;45private static final long CONTEXTCLASSLOADER;4647private static final AtomicInteger threadNumber = new AtomicInteger(1);48private static String newName() {49return "InnocuousThread-" + threadNumber.getAndIncrement();50}5152/**53* Returns a new InnocuousThread with an auto-generated thread name,54* and its context class loader is set to the system class loader.55*/56public static Thread newThread(Runnable target) {57return newThread(newName(), target);58}5960/**61* Returns a new InnocuousThread with its context class loader62* set to the system class loader.63*/64public static Thread newThread(String name, Runnable target) {65return newThread(name, target, -1);66}67/**68* Returns a new InnocuousThread with its context class loader69* set to the system class loader. The thread priority will be70* set to the given priority.71*/72public static Thread newThread(String name, Runnable target, int priority) {73if (System.getSecurityManager() == null) {74return createThread(name, target, ClassLoader.getSystemClassLoader(), priority);75}76return AccessController.doPrivileged(77new PrivilegedAction<Thread>() {78@Override79public Thread run() {80return createThread(name, target, ClassLoader.getSystemClassLoader(), priority);81}82});83}8485/**86* Returns a new InnocuousThread with an auto-generated thread name.87* Its context class loader is set to null.88*/89public static Thread newSystemThread(Runnable target) {90return newSystemThread(newName(), target);91}9293/**94* Returns a new InnocuousThread with null context class loader.95*/96public static Thread newSystemThread(String name, Runnable target) {97return newSystemThread(name, target, -1);98}99100/**101* Returns a new InnocuousThread with null context class loader.102* Thread priority is set to the given priority.103*/104public static Thread newSystemThread(String name, Runnable target, int priority) {105if (System.getSecurityManager() == null) {106return createThread(name, target, null, priority);107}108return AccessController.doPrivileged(109new PrivilegedAction<Thread>() {110@Override111public Thread run() {112return createThread(name, target, null, priority);113}114});115}116117private static Thread createThread(String name, Runnable target, ClassLoader loader, int priority) {118Thread t = new InnocuousThread(INNOCUOUSTHREADGROUP,119target, name, loader);120if (priority >= 0) {121t.setPriority(priority);122}123return t;124}125126private InnocuousThread(ThreadGroup group, Runnable target, String name, ClassLoader tccl) {127super(group, target, name, 0L, false);128UNSAFE.putReferenceRelease(this, INHERITEDACCESSCONTROLCONTEXT, ACC);129UNSAFE.putReferenceRelease(this, CONTEXTCLASSLOADER, tccl);130}131132@Override133public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) {134// silently fail135}136137@Override138public void setContextClassLoader(ClassLoader cl) {139// Allow clearing of the TCCL to remove the reference to the system classloader.140if (cl == null)141super.setContextClassLoader(null);142else143throw new SecurityException("setContextClassLoader");144}145146/**147* Drops all thread locals (and inherited thread locals).148*/149public final void eraseThreadLocals() {150UNSAFE.putReference(this, THREAD_LOCALS, null);151UNSAFE.putReference(this, INHERITABLE_THREAD_LOCALS, null);152}153154// ensure run method is run only once155private volatile boolean hasRun;156157@Override158public void run() {159if (Thread.currentThread() == this && !hasRun) {160hasRun = true;161super.run();162}163}164165// Use Unsafe to access Thread group and ThreadGroup parent fields166static {167try {168ACC = new AccessControlContext(new ProtectionDomain[] {169new ProtectionDomain(null, null)170});171172// Find and use topmost ThreadGroup as parent of new group173UNSAFE = jdk.internal.misc.Unsafe.getUnsafe();174Class<?> tk = Thread.class;175Class<?> gk = ThreadGroup.class;176177THREAD_LOCALS = UNSAFE.objectFieldOffset(tk, "threadLocals");178INHERITABLE_THREAD_LOCALS = UNSAFE.objectFieldOffset179(tk, "inheritableThreadLocals");180INHERITEDACCESSCONTROLCONTEXT = UNSAFE.objectFieldOffset181(tk, "inheritedAccessControlContext");182CONTEXTCLASSLOADER = UNSAFE.objectFieldOffset183(tk, "contextClassLoader");184185long tg = UNSAFE.objectFieldOffset(tk, "group");186long gp = UNSAFE.objectFieldOffset(gk, "parent");187ThreadGroup group = (ThreadGroup)188UNSAFE.getReference(Thread.currentThread(), tg);189190while (group != null) {191ThreadGroup parent = (ThreadGroup)UNSAFE.getReference(group, gp);192if (parent == null)193break;194group = parent;195}196final ThreadGroup root = group;197if (System.getSecurityManager() == null) {198INNOCUOUSTHREADGROUP = new ThreadGroup(root, "InnocuousThreadGroup");199} else {200INNOCUOUSTHREADGROUP = AccessController.doPrivileged(201new PrivilegedAction<ThreadGroup>() {202@Override203public ThreadGroup run() {204return new ThreadGroup(root, "InnocuousThreadGroup");205}206});207}208} catch (Exception e) {209throw new Error(e);210}211}212}213214215