|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.misc; |
|
|
|
import java.security.AccessControlContext; |
|
import java.security.AccessController; |
|
import java.security.ProtectionDomain; |
|
import java.security.PrivilegedAction; |
|
import java.util.concurrent.atomic.AtomicInteger; |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final class InnocuousThread extends Thread { |
|
private static final Unsafe UNSAFE; |
|
private static final long THREAD_LOCALS; |
|
private static final long INHERITABLE_THREAD_LOCALS; |
|
private static final ThreadGroup INNOCUOUSTHREADGROUP; |
|
private static final AccessControlContext ACC; |
|
private static final long INHERITEDACCESSCONTROLCONTEXT; |
|
private static final long CONTEXTCLASSLOADER; |
|
|
|
private static final AtomicInteger threadNumber = new AtomicInteger(1); |
|
private static String newName() { |
|
return "InnocuousThread-" + threadNumber.getAndIncrement(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public static Thread newSystemThread(Runnable target) { |
|
return newSystemThread(newName(), target); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static Thread newSystemThread(String name, Runnable target) { |
|
return new InnocuousThread(INNOCUOUSTHREADGROUP, |
|
target, name, null); |
|
} |
|
|
|
public InnocuousThread(Runnable target) { |
|
super(INNOCUOUSTHREADGROUP, target, newName()); |
|
UNSAFE.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, ACC); |
|
eraseThreadLocals(); |
|
} |
|
|
|
private InnocuousThread(ThreadGroup group, Runnable target, String name, ClassLoader tccl) { |
|
super(group, target, name, 0L); |
|
UNSAFE.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, ACC); |
|
UNSAFE.putOrderedObject(this, CONTEXTCLASSLOADER, tccl); |
|
eraseThreadLocals(); |
|
} |
|
|
|
@Override |
|
public ClassLoader getContextClassLoader() { |
|
|
|
return ClassLoader.getSystemClassLoader(); |
|
} |
|
|
|
@Override |
|
public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { |
|
// silently fail |
|
} |
|
|
|
@Override |
|
public void setContextClassLoader(ClassLoader cl) { |
|
throw new SecurityException("setContextClassLoader"); |
|
} |
|
|
|
|
|
private volatile boolean hasRun; |
|
|
|
@Override |
|
public void run() { |
|
if (Thread.currentThread() == this && !hasRun) { |
|
hasRun = true; |
|
super.run(); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void eraseThreadLocals() { |
|
UNSAFE.putObject(this, THREAD_LOCALS, null); |
|
UNSAFE.putObject(this, INHERITABLE_THREAD_LOCALS, null); |
|
} |
|
|
|
|
|
static { |
|
try { |
|
ACC = new AccessControlContext(new ProtectionDomain[] { |
|
new ProtectionDomain(null, null) |
|
}); |
|
|
|
|
|
UNSAFE = Unsafe.getUnsafe(); |
|
Class<?> tk = Thread.class; |
|
Class<?> gk = ThreadGroup.class; |
|
|
|
THREAD_LOCALS = UNSAFE.objectFieldOffset |
|
(tk.getDeclaredField("threadLocals")); |
|
INHERITABLE_THREAD_LOCALS = UNSAFE.objectFieldOffset |
|
(tk.getDeclaredField("inheritableThreadLocals")); |
|
INHERITEDACCESSCONTROLCONTEXT = UNSAFE.objectFieldOffset |
|
(tk.getDeclaredField("inheritedAccessControlContext")); |
|
CONTEXTCLASSLOADER = UNSAFE.objectFieldOffset |
|
(tk.getDeclaredField("contextClassLoader")); |
|
|
|
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; |
|
} |
|
final ThreadGroup root = group; |
|
INNOCUOUSTHREADGROUP = AccessController.doPrivileged( |
|
new PrivilegedAction<ThreadGroup>() { |
|
@Override |
|
public ThreadGroup run() { |
|
return new ThreadGroup(root, "InnocuousThreadGroup"); |
|
} |
|
}); |
|
} catch (Exception e) { |
|
throw new Error(e); |
|
} |
|
} |
|
} |