diff options
| author | Thomas Watson | 2011-12-05 15:28:17 +0000 |
|---|---|---|
| committer | Thomas Watson | 2011-12-05 15:28:17 +0000 |
| commit | 44ee7bd0b5acc75f463828913fe1192bfb49e7ac (patch) | |
| tree | 87a5a73c8ba0905cf84f339ad00385c062df44c4 | |
| parent | 4310fe13b178ffc8857be4067d76420a09650fd0 (diff) | |
| download | rt.equinox.framework-44ee7bd0b5acc75f463828913fe1192bfb49e7ac.tar.gz rt.equinox.framework-44ee7bd0b5acc75f463828913fe1192bfb49e7ac.tar.xz rt.equinox.framework-44ee7bd0b5acc75f463828913fe1192bfb49e7ac.zip | |
Bug 361533 - Deadlock on startup when using Spring OSGi
| -rw-r--r-- | bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java | 77 |
1 files changed, 49 insertions, 28 deletions
diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java index da6943da9..2a3d0b271 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java @@ -47,6 +47,7 @@ public class ClasspathManager { private final static String PROP_CLASSLOADER_LOCK = "osgi.classloader.lock"; //$NON-NLS-1$ private final static String VALUE_CLASSNAME_LOCK = "classname"; //$NON-NLS-1$ private final static boolean LOCK_CLASSNAME = VALUE_CLASSNAME_LOCK.equals(FrameworkProperties.getProperty(PROP_CLASSLOADER_LOCK)); + private final static Class<?>[] NULL_CLASS_RESULT = new Class[2]; private final BaseData data; private final String[] classpath; @@ -452,10 +453,10 @@ public class ClasspathManager { try { for (int i = 0; i < hooks.length; i++) hooks[i].preFindLocalClass(classname, this); - if (LOCK_CLASSNAME || isParallelClassLoader) - result = findLocalClass_LockClassName(classname, hooks); - else - result = findLocalClass_LockClassLoader(classname, hooks); + result = findLoadedClass(classname); + if (result != null) + return result; + result = findLocalClassImpl(classname, hooks); return result; } finally { for (int i = 0; i < hooks.length; i++) @@ -463,28 +464,23 @@ public class ClasspathManager { } } - private Class<?> findLocalClass_LockClassName(String classname, ClassLoadingStatsHook[] hooks) throws ClassNotFoundException { - boolean initialLock = lockClassName(classname); - try { - return findLocalClassImpl(classname, hooks); - } finally { - if (initialLock) - unlockClassName(classname); + private Class<?> findLoadedClass(String classname) { + if (LOCK_CLASSNAME || isParallelClassLoader) { + boolean initialLock = lockClassName(classname); + try { + return classloader.publicFindLoaded(classname); + } finally { + if (initialLock) + unlockClassName(classname); + } } - } - - private Class<?> findLocalClass_LockClassLoader(String classname, ClassLoadingStatsHook[] hooks) throws ClassNotFoundException { synchronized (classloader) { - return findLocalClassImpl(classname, hooks); + return classloader.publicFindLoaded(classname); } } private Class<?> findLocalClassImpl(String classname, ClassLoadingStatsHook[] hooks) throws ClassNotFoundException { - // must call findLoadedClass here even if it was called earlier, - // the findLoadedClass and defineClass calls must be atomic - Class<?> result = classloader.publicFindLoaded(classname); - if (result != null) - return result; + Class<?> result = null; for (int i = 0; i < entries.length; i++) { if (entries[i] != null) { result = findClassImpl(classname, entries[i], hooks); @@ -504,7 +500,7 @@ public class ClasspathManager { throw new ClassNotFoundException(classname); } - private boolean lockClassName(String classname) throws ClassNotFoundException { + private boolean lockClassName(String classname) { synchronized (classNameLocks) { Object lockingThread = classNameLocks.get(classname); Thread current = Thread.currentThread(); @@ -520,7 +516,7 @@ public class ClasspathManager { lockingThread = classNameLocks.get(classname); } catch (InterruptedException e) { current.interrupt(); - throw new ClassNotFoundException(classname, e); + throw (LinkageError) new LinkageError(classname).initCause(e); } } } @@ -535,7 +531,7 @@ public class ClasspathManager { private Class<?> findClassImpl(String name, ClasspathEntry classpathEntry, ClassLoadingStatsHook[] hooks) { if (Debug.DEBUG_LOADER) - Debug.println("BundleClassLoader[" + classpathEntry.getBundleFile() + "].findClass(" + name + ")"); //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ + Debug.println("BundleClassLoader[" + classpathEntry.getBundleFile() + "].findClassImpl(" + name + ")"); //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ String filename = name.replace('.', '/').concat(".class"); //$NON-NLS-1$ BundleEntry entry = classpathEntry.getBundleFile().getEntry(filename); if (entry == null) @@ -549,7 +545,6 @@ public class ClasspathManager { Debug.println(" IOException reading " + filename + " from " + classpathEntry.getBundleFile()); //$NON-NLS-1$ //$NON-NLS-2$ return null; } - if (Debug.DEBUG_LOADER) { Debug.println(" read " + classbytes.length + " bytes from " + classpathEntry.getBundleFile() + "/" + filename); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ Debug.println(" defining class " + name); //$NON-NLS-1$ @@ -590,19 +585,45 @@ public class ClasspathManager { private Class<?> defineClass(String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClassLoadingStatsHook[] statsHooks) { ClassLoadingHook[] hooks = data.getAdaptor().getHookRegistry().getClassLoadingHooks(); byte[] modifiedBytes = classbytes; - Class<?> result = null; + // The result holds two Class objects. + // The first slot to either a pre loaded class or the newly defined class. + // The second slot is only set to a newly defined class object if it was successfully defined + Class<?>[] result = NULL_CLASS_RESULT; try { for (int i = 0; i < hooks.length; i++) { modifiedBytes = hooks[i].processClass(name, classbytes, classpathEntry, entry, this); if (modifiedBytes != null) classbytes = modifiedBytes; } - - result = classloader.defineClass(name, classbytes, classpathEntry, entry); + if (LOCK_CLASSNAME || isParallelClassLoader) { + boolean initialLock = lockClassName(name); + try { + result = defineClassHoldingLock(name, classbytes, classpathEntry, entry); + } finally { + if (initialLock) + unlockClassName(name); + } + } else { + synchronized (classloader) { + result = defineClassHoldingLock(name, classbytes, classpathEntry, entry); + } + } } finally { for (int i = 0; i < statsHooks.length; i++) - statsHooks[i].recordClassDefine(name, result, classbytes, classpathEntry, entry, this); + // only pass the newly defined class to the hook + statsHooks[i].recordClassDefine(name, result[1], classbytes, classpathEntry, entry, this); } + // return either the pre-loaded class or the newly defined class + return result[0]; + } + + private Class<?>[] defineClassHoldingLock(String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry) { + Class<?>[] result = new Class[2]; + // must call findLoadedClass here even if it was called earlier, + // the findLoadedClass and defineClass calls must be atomic + result[0] = classloader.publicFindLoaded(name); + if (result[0] == null) + result[0] = result[1] = classloader.defineClass(name, classbytes, classpathEntry, entry); return result; } |
