Hi,
Since nobody complained about my context class loader fix, I'm checking
it in. I also made the generation of anonymous thread names thread safe
and corrected the security check in getContextClassLoader.
Regards,
Jeroen
2006-05-19 Jeroen Frijters <[EMAIL PROTECTED]>
* java/lang/Thread.java
(contextClassLoaderIsSystemClassLoader): New field.
(Thread(ThreadGroup,Runnable)): Call createAnonymousThreadName.
(Thread(VMThread,String,int,boolean)): Call
createAnonymousThreadName
and set contextClassLoaderIsSystemClassLoader.
(Thread(ThreadGroup,Runnable,String,long)):
Set contextClassLoaderIsSystemClassLoader.
(createAnonymousThreadName): New method.
(getContextClassLoader): Check
contextClassLoaderIsSystemClassLoader
and fixed security check.
(setContextClassLoader): Clear
contextClassLoaderIsSystemClassLoader.
Index: java/lang/Thread.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/Thread.java,v
retrieving revision 1.22
diff -u -r1.22 Thread.java
--- java/lang/Thread.java 9 May 2006 14:42:13 -0000 1.22
+++ java/lang/Thread.java 19 May 2006 09:33:13 -0000
@@ -38,6 +38,7 @@
package java.lang;
+import gnu.classpath.VMStackWalker;
import gnu.java.util.WeakIdentityHashMap;
import java.security.Permission;
import java.util.Map;
@@ -131,7 +132,8 @@
/** The context classloader for this Thread. */
private ClassLoader contextClassLoader;
-
+ private boolean contextClassLoaderIsSystemClassLoader;
+
/** This thread's ID. */
private final long threadId;
@@ -248,7 +250,7 @@
*/
public Thread(ThreadGroup group, Runnable target)
{
- this(group, target, "Thread-" + ++numAnonymousThreadsCreated, 0);
+ this(group, target, createAnonymousThreadName(), 0);
}
/**
@@ -364,6 +366,8 @@
priority = current.priority;
daemon = current.daemon;
contextClassLoader = current.contextClassLoader;
+ contextClassLoaderIsSystemClassLoader =
+ current.contextClassLoaderIsSystemClassLoader;
group.addThread(this);
InheritableThreadLocal.newChildThread(this);
@@ -373,6 +377,9 @@
* Used by the VM to create thread objects for threads started outside
* of Java. Note: caller is responsible for adding the thread to
* a group and InheritableThreadLocal.
+ * Note: This constructor should not call any methods that could result
+ * in a call to Thread.currentThread(), because that makes life harder
+ * for the VM.
*
* @param vmThread the native thread
* @param name the thread name or null to use the default naming scheme
@@ -384,16 +391,32 @@
this.vmThread = vmThread;
this.runnable = null;
if (name == null)
- name = "Thread-" + ++numAnonymousThreadsCreated;
+ name = createAnonymousThreadName();
this.name = name;
this.priority = priority;
this.daemon = daemon;
- this.contextClassLoader = ClassLoader.getSystemClassLoader();
+ // By default the context class loader is the system class loader,
+ // we set a flag to signal this because we don't want to call
+ // ClassLoader.getSystemClassLoader() at this point, because on
+ // VMs that lazily create the system class loader that might result
+ // in running user code (when a custom system class loader is specified)
+ // and that user code could call Thread.currentThread().
+ // ClassLoader.getSystemClassLoader() can also return null, if the system
+ // is currently in the process of constructing the system class loader
+ // (and, as above, the constructiong sequence calls Thread.currenThread()).
+ contextClassLoaderIsSystemClassLoader = true;
synchronized (Thread.class)
{
this.threadId = nextThreadId++;
}
+ }
+ /**
+ * Generate a name for an anonymous thread.
+ */
+ private static synchronized String createAnonymousThreadName()
+ {
+ return "Thread-" + ++numAnonymousThreadsCreated;
}
/**
@@ -746,12 +769,18 @@
*/
public synchronized ClassLoader getContextClassLoader()
{
- // Bypass System.getSecurityManager, for bootstrap efficiency.
+ ClassLoader loader = contextClassLoaderIsSystemClassLoader ?
+ ClassLoader.getSystemClassLoader() : contextClassLoader;
+ // Check if we may get the classloader
SecurityManager sm = SecurityManager.current;
- if (sm != null)
- // XXX Don't check this if the caller's class loader is an ancestor.
- sm.checkPermission(new RuntimePermission("getClassLoader"));
- return contextClassLoader;
+ if (loader != null && sm != null)
+ {
+ // Get the calling classloader
+ ClassLoader cl = VMStackWalker.getCallingClassLoader();
+ if (cl != null && !cl.isAncestorOf(loader))
+ sm.checkPermission(new RuntimePermission("getClassLoader"));
+ }
+ return loader;
}
/**
@@ -772,6 +801,7 @@
if (sm != null)
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
this.contextClassLoader = classloader;
+ contextClassLoaderIsSystemClassLoader = false;
}
/**