Skip to content
Permalink
Browse files
Move inheritance text to class description. Treat TCCL as ITL
  • Loading branch information
AlanBateman committed Mar 2, 2021
1 parent 6f54c0a commit 17d5e3e06088016311f1da93d18ba751dd9a341c
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 58 deletions.
@@ -2026,6 +2026,30 @@ oop java_lang_Thread_VirtualThreads::get_THREAD_GROUP() {
}


int java_lang_Thread_ClassLoaders::_static_NOT_SUPPORTED_offset = 0;

#define THREAD_CLASS_LOADERS_STATIC_FIELDS_DO(macro) \
macro(_static_NOT_SUPPORTED_offset, k, "NOT_SUPPORTED", classloader_signature, true);

void java_lang_Thread_ClassLoaders::compute_offsets() {
assert(_static_NOT_SUPPORTED_offset == 0, "offsets should be initialized only once");

InstanceKlass* k = vmClasses::Thread_ClassLoaders_klass();
THREAD_CLASS_LOADERS_STATIC_FIELDS_DO(FIELD_COMPUTE_OFFSET);
}

#if INCLUDE_CDS
void java_lang_Thread_ClassLoaders::serialize_offsets(SerializeClosure* f) {
THREAD_CLASS_LOADERS_STATIC_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
}
#endif

oop java_lang_Thread_ClassLoaders::get_NOT_SUPPORTED() {
InstanceKlass* k = vmClasses::Thread_ClassLoaders_klass();
oop base = k->static_field_base_raw();
return base->obj_field(_static_NOT_SUPPORTED_offset);
}

int java_lang_Thread::_holder_offset;
int java_lang_Thread::_name_offset;
int java_lang_Thread::_contextClassLoader_offset;
@@ -497,6 +497,21 @@ class java_lang_Thread_VirtualThreads : AllStatic {
};


// Interface to java.lang.Thread$ClassLoaders objects

class java_lang_Thread_ClassLoaders : AllStatic {
private:
static int _static_NOT_SUPPORTED_offset;

static void compute_offsets();
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
public:
static oop get_NOT_SUPPORTED();

friend class JavaClasses;
};


// Interface to java.lang.ThreadGroup objects

class java_lang_ThreadGroup : AllStatic {
@@ -89,6 +89,7 @@
do_klass(Thread_klass, java_lang_Thread ) \
do_klass(Thread_FieldHolder_klass, java_lang_Thread_FieldHolder ) \
do_klass(Thread_VirtualThreads_klass, java_lang_Thread_VirtualThreads ) \
do_klass(Thread_ClassLoaders_klass, java_lang_Thread_ClassLoaders ) \
do_klass(ThreadGroup_klass, java_lang_ThreadGroup ) \
do_klass(VirtualThread_klass, java_lang_VirtualThread ) \
do_klass(Properties_klass, java_util_Properties ) \
@@ -64,6 +64,7 @@
template(java_lang_Thread, "java/lang/Thread") \
template(java_lang_Thread_FieldHolder, "java/lang/Thread$FieldHolder") \
template(java_lang_Thread_VirtualThreads, "java/lang/Thread$VirtualThreads") \
template(java_lang_Thread_ClassLoaders, "java/lang/Thread$ClassLoaders") \
template(java_lang_ThreadGroup, "java/lang/ThreadGroup") \
template(java_lang_VirtualThread, "java/lang/VirtualThread") \
template(java_lang_Cloneable, "java/lang/Cloneable") \
@@ -1274,6 +1274,8 @@ JvmtiEnv::GetThreadInfo(jthread thread, jvmtiThreadInfo* info_ptr) {
}

oop loader = java_lang_Thread::context_class_loader(thread_obj());
if (loader == java_lang_Thread_ClassLoaders::get_NOT_SUPPORTED())
loader = NULL;
context_class_loader = Handle(current_thread, loader);

{ const char *n;
@@ -85,14 +85,9 @@
* to the <i>current thread</i>, will return the {@code Thread} object for the virtual
* thread.
*
* <p> {@code Thread} defines a {@linkplain Builder} API, for creating threads. It
* also defines (for compatibility and customization reasons) constructors for
* creating platform threads. The constructors cannot be used to create virtual
* threads.
*
* <p> Platform threads are designated <i>daemon</i> or <i>non-daemon</i> threads.
* When the Java virtual machine starts up, there is usually one non-daemon
* thread (the thread that typically calls the applications's {@code main} method).
* thread (the thread that typically calls the application's {@code main} method).
* The Java virtual machine terminates when all started non-daemon threads have
* terminated. Unstarted daemon threads do not prevent the Java virtual machine from
* termination. The Java virtual machine can also be terminated by invoking the
@@ -101,6 +96,30 @@
* threads is meaningless and have no influence on when the Java virtual
* machine terminates.
*
* <p> In addition to the daemon status, platform threads have a {@linkplain
* #getPriority() thread priority} and are members of a {@linkplain ThreadGroup
* thread group}.
*
* <p> Threads have an optional name and optionally support {@link ThreadLocal}
* variables. Thread local variables are local to a thread, meaning a thread can
* set its copy of a variable to a value that is independent of the value set by
* other threads.
*
* <p> {@code Thread} defines a {@linkplain Builder} API, for creating threads. It
* also defines (for customization reasons) constructors for creating platform threads.
* The constructors cannot be used to create virtual threads. By default, creating
* a {@code Thread} inherits the initial values of {@link InheritableThreadLocal}
* variables and a number of characteristics from the parent thread:
* <ul>
* <li> Platform threads inherit the daemon status, priority, and thread-group.
* <li> Virtual threads are scheduled by the same scheduler as the parent thread
* when the parent thread is a virtual thread. Virtual threads use the default
* scheduler when the parent thread is a platform thread and scheduler has not
* been selected.
* <li> The {@linkplain #getContextClassLoader() context-class-loader} is treated
* as an inheritable thread local and is inherited by default.
* </ul>
*
* <p> Unless otherwise specified, passing a {@code null} argument to a constructor
* or method in this class will cause a {@link NullPointerException} to be thrown.
*
@@ -542,11 +561,6 @@ private Thread(ThreadGroup g, String name, int characteristics, Runnable task,
}
}

/* can't create a platform thread in the virtual thread group */
if ((VM.initLevel() >= 1) && g == VirtualThreads.THREAD_GROUP) {
g = VirtualThreads.OFFSPRING_THREAD_GROUP;
}

/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
@@ -563,20 +577,21 @@ private Thread(ThreadGroup g, String name, int characteristics, Runnable task,

this.name = name;
this.tid = primordial ? 1 : ThreadIdentifiers.next();
this.contextClassLoader = contextClassLoader(parent);
this.inheritedAccessControlContext = (acc != null) ? acc : AccessController.getContext();

// thread locals
if ((characteristics & NO_THREAD_LOCALS) != 0) {
this.threadLocals = ThreadLocal.ThreadLocalMap.NOT_SUPPORTED;
this.inheritableThreadLocals = ThreadLocal.ThreadLocalMap.NOT_SUPPORTED;
this.contextClassLoader = ClassLoaders.NOT_SUPPORTED;
} else if ((characteristics & NO_INHERIT_THREAD_LOCALS) == 0) {
ThreadLocal.ThreadLocalMap parentMap = parent.inheritableThreadLocals;
if (parentMap != null
&& parentMap != ThreadLocal.ThreadLocalMap.NOT_SUPPORTED
&& parentMap.size() > 0) {
this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parentMap);
}
this.contextClassLoader = contextClassLoader(parent);
}

// scoped variables
@@ -606,22 +621,24 @@ private Thread(ThreadGroup g, String name, int characteristics, Runnable task,

this.name = (name != null) ? name : "<unnamed>";
this.tid = ThreadIdentifiers.next();
this.contextClassLoader = contextClassLoader(parent);
this.inheritedAccessControlContext = VirtualThreads.ACCESS_CONTROL_CONTEXT;

// thread locals
if ((characteristics & NO_THREAD_LOCALS) != 0) {
this.threadLocals = ThreadLocal.ThreadLocalMap.NOT_SUPPORTED;
this.inheritableThreadLocals = ThreadLocal.ThreadLocalMap.NOT_SUPPORTED;
this.contextClassLoader = ClassLoaders.NOT_SUPPORTED;
} else if ((characteristics & NO_INHERIT_THREAD_LOCALS) == 0) {
ThreadLocal.ThreadLocalMap parentMap = parent.inheritableThreadLocals;
if (parentMap != null
&& parentMap != ThreadLocal.ThreadLocalMap.NOT_SUPPORTED
&& parentMap.size() > 0) {
this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parentMap);
}
this.contextClassLoader = contextClassLoader(parent);
}

// scoped variables
this.inheritableScopeLocalBindings = parent.inheritableScopeLocalBindings;

// no additional fields
@@ -731,21 +748,6 @@ public static Builder builder() {
* <li> The {@linkplain #factory() factory} method creates a {@code ThreadFactory}.
* </ul>
*
* <p> By default, Threads created with a builder, or with a {@code ThreadFactory}
* created from a builder, inherit the initial values of {@link
* InheritableThreadLocal} variables and some characteristics from the parent
* thread. Inheritance occurs when the {@code Thread} is created.
* <ul>
* <li> Platform threads inherit the {@linkplain #isDaemon() daemon status},
* {@linkplain #getPriority() thread priority} and {@linkplain ThreadGroup
* thread-group}.
* <li> Virtual threads inherit the scheduler when the parent thread is a
* virtual thread. Virtual threads use the default scheduler when the
* parent thread is a platform thread and scheduler has not been selected.
* <li> The {@linkplain #getContextClassLoader() context-class-loader} is always
* inherited (for security reasons, TBD if we should re-examine that).
* </ul>
*
* <p> Virtual threads created with a builder, or with a {@code ThreadFactory}
* created from a builder, have no {@link Permission permissions}.
*
@@ -2101,8 +2103,8 @@ static ThreadGroup getCurrentThreadGroup() {
* Returns an estimate of the number of active threads in the current
* thread's {@linkplain java.lang.ThreadGroup thread group} and its
* subgroups. Virtual threads are not considered active threads in a
* thread group so this method returns {@code 0} when invoked from
* a virtual thread.
* thread group so this method does not include virtual threads in the
* estimate.
*
* <p> The value returned is only an estimate because the number of
* threads may change dynamically while this method traverses internal
@@ -2124,7 +2126,7 @@ public static int activeCount() {
* invokes the {@link java.lang.ThreadGroup#enumerate(Thread[])}
* method of the current thread's thread group. Virtual threads are
* not considered active threads in a thread group so this method
* returns {@code 0} when invoked from a virtual thread.
* does not enumerate virtual threads.
*
* <p> An application might use the {@linkplain #activeCount activeCount}
* method to get an estimate of how big the array should be, however
@@ -2428,15 +2430,15 @@ public String toString() {
}

/**
* Returns the context {@code ClassLoader} for this thread. The context
* {@code ClassLoader} is provided by the creator of the thread for use
* by code running in this thread when loading classes and resources.
* If not {@linkplain #setContextClassLoader set}, the default is the
* {@code ClassLoader} context of the parent thread. The context
* {@code ClassLoader} of the
* primordial thread is typically set to the class loader used to load the
* application.
* Returns the context {@code ClassLoader} for this thread.
* The context {@code ClassLoader} may be set by the creator of the thread
* for use by code running in this thread when loading classes and resources.
* If not {@linkplain #setContextClassLoader set}, the default is to inherit
* the context class loader from the parent thread when creating the
* {@code Thread}.
*
* <p> The context {@code ClassLoader} of the primordial thread is typically
* set to the class loader used to load the application.
*
* @return the context {@code ClassLoader} for this thread, or {@code null}
* indicating the system class loader (or, failing that, the
@@ -2452,7 +2454,8 @@ public String toString() {
*/
@CallerSensitive
public ClassLoader getContextClassLoader() {
if (contextClassLoader == null)
if (contextClassLoader == null
|| contextClassLoader == ClassLoaders.NOT_SUPPORTED)
return null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
@@ -2463,13 +2466,11 @@ public ClassLoader getContextClassLoader() {
}

/**
* Sets the context ClassLoader for this Thread. The context
* ClassLoader can be set when a thread is created, and allows
* the creator of the thread to provide the appropriate class loader,
* through {@code getContextClassLoader}, to code running in the thread
* when loading classes and resources.
* Sets the context {@code ClassLoader} for this thread.
* The context {@code ClassLoader} may be set by the creator of the thread
* for use by code running in this thread when loading classes and resources.
*
* <p>If a security manager is present, its {@link
* <p> If a security manager is present, its {@link
* SecurityManager#checkPermission(java.security.Permission) checkPermission}
* method is invoked with a {@link RuntimePermission RuntimePermission}{@code
* ("setContextClassLoader")} permission to see if setting the context
@@ -2479,6 +2480,9 @@ public ClassLoader getContextClassLoader() {
* the context ClassLoader for this Thread, or null indicating the
* system class loader (or, failing that, the bootstrap class loader)
*
* @throws UnsupportedOperationException if this thread is not allowed
* to have its copy of thread-local variables
*
* @throws SecurityException
* if the current thread cannot set the context ClassLoader
*
@@ -2489,9 +2493,21 @@ public void setContextClassLoader(ClassLoader cl) {
if (sm != null) {
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
}
if (contextClassLoader == ClassLoaders.NOT_SUPPORTED) {
throw new UnsupportedOperationException();
}
contextClassLoader = cl;
}

private static class ClassLoaders {
static final ClassLoader NOT_SUPPORTED;
static {
PrivilegedAction<ClassLoader> pa = () -> new ClassLoader(null) { };
NOT_SUPPORTED = AccessController.doPrivileged(pa);
}
}


/**
* Returns {@code true} if and only if the current thread holds the
* monitor lock on the specified object.
@@ -3073,9 +3089,6 @@ private static class VirtualThreads {
// Thread group for virtual threads.
static final ThreadGroup THREAD_GROUP;

// Thread group for platform threads created by virtual threads
static final ThreadGroup OFFSPRING_THREAD_GROUP;

// AccessControlContext that doesn't support any permissions.
static final AccessControlContext ACCESS_CONTROL_CONTEXT;

@@ -3090,15 +3103,7 @@ public ThreadGroup run() {
}
};
ThreadGroup root = AccessController.doPrivileged(pa);

var vgroup = new ThreadGroup(root, "VirtualThreads", NORM_PRIORITY);
THREAD_GROUP = vgroup;

int priority = NORM_PRIORITY;
if (System.getSecurityManager() != null) {
priority = MIN_PRIORITY;
}
OFFSPRING_THREAD_GROUP = new ThreadGroup(vgroup, "VirtualThreads-offspring", priority);
THREAD_GROUP = new ThreadGroup(root, "VirtualThreads", NORM_PRIORITY);

ACCESS_CONTROL_CONTEXT = new AccessControlContext(new ProtectionDomain[] {
new ProtectionDomain(null, null)

0 comments on commit 17d5e3e

Please sign in to comment.