Skip to content

Commit 2abd597

Browse files
committed
Defer initialization of classpath to the background if called from main
Currently there are some bad behaving UI components in the eclipse IDE that trigger resolving of the classpath containers in the UI, this leads to very bad startup performance and even deadlocks in startup. This now detects the issue, logs a warning of the offending component and defer the initialization of classpath to a background job, this currently increase time from starting eclipse until UI is shown noticeable. Fix eclipse-pde#1481
1 parent 5baaa6d commit 2abd597

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

ui/org.eclipse.pde.core/META-INF/MANIFEST.MF

+2
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,5 @@ Bundle-ActivationPolicy: lazy
135135
Automatic-Module-Name: org.eclipse.pde.core
136136
Service-Component: OSGI-INF/org.eclipse.pde.internal.core.annotations.OSGiAnnotationsClasspathContributor.xml,
137137
OSGI-INF/org.eclipse.pde.internal.core.bnd.PdeBndAdapter.xml
138+
DynamicImport-Package: org.eclipse.swt.widgets
139+

ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/RequiredPluginsInitializer.java

+66
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,33 @@
1313
*******************************************************************************/
1414
package org.eclipse.pde.internal.core;
1515

16+
import java.lang.reflect.Method;
17+
import java.util.Map;
18+
import java.util.concurrent.ConcurrentHashMap;
19+
import java.util.concurrent.atomic.AtomicBoolean;
20+
1621
import org.eclipse.core.resources.IProject;
1722
import org.eclipse.core.runtime.CoreException;
23+
import org.eclipse.core.runtime.ILog;
1824
import org.eclipse.core.runtime.IPath;
1925
import org.eclipse.core.runtime.IStatus;
2026
import org.eclipse.core.runtime.Status;
27+
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
2128
import org.eclipse.core.runtime.jobs.Job;
29+
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
2230
import org.eclipse.jdt.core.ClasspathContainerInitializer;
2331
import org.eclipse.jdt.core.IClasspathContainer;
2432
import org.eclipse.jdt.core.IJavaProject;
2533
import org.eclipse.jdt.core.JavaCore;
34+
import org.eclipse.jdt.core.JavaModelException;
2635
import org.eclipse.pde.core.plugin.IPluginModelBase;
2736

2837
public class RequiredPluginsInitializer extends ClasspathContainerInitializer {
2938

39+
private static final AtomicBoolean WARNING_LOGGED = new AtomicBoolean();
40+
41+
private static final Map<IJavaProject, Job> JOB_MAP = new ConcurrentHashMap<>();
42+
3043
private static final Job initPDEJob = Job.create(PDECoreMessages.PluginModelManager_InitializingPluginModels,
3144
monitor -> {
3245
if (!PDECore.getDefault().getModelManager().isInitialized()) {
@@ -36,6 +49,48 @@ public class RequiredPluginsInitializer extends ClasspathContainerInitializer {
3649

3750
@Override
3851
public void initialize(IPath containerPath, IJavaProject javaProject) throws CoreException {
52+
if (isCalledFromUI()) {
53+
// See https://github.com/eclipse-pde/eclipse.pde/issues/1481
54+
if (WARNING_LOGGED.compareAndSet(false, true)) {
55+
ILog.get().warn(
56+
"RequiredPluginsInitializer called from within the UI thread this will badly impact your IDE performance!", //$NON-NLS-1$
57+
new RuntimeException("Called from main thread here")); //$NON-NLS-1$
58+
}
59+
JOB_MAP.compute(javaProject, (jp, oldjob) -> {
60+
if (oldjob != null) {
61+
oldjob.cancel();
62+
}
63+
Job job = Job.create(PDECoreMessages.PluginModelManager_InitializingPluginModels, m -> {
64+
if (oldjob != null) {
65+
try {
66+
oldjob.join();
67+
} catch (InterruptedException e) {
68+
}
69+
}
70+
setClasspath(jp);
71+
});
72+
job.addJobChangeListener(new JobChangeAdapter() {
73+
@Override
74+
public void done(IJobChangeEvent event) {
75+
JOB_MAP.remove(jp);
76+
}
77+
});
78+
job.schedule();
79+
return job;
80+
});
81+
return;
82+
}
83+
Job job = JOB_MAP.get(javaProject);
84+
if (job != null) {
85+
try {
86+
job.join();
87+
} catch (InterruptedException e) {
88+
}
89+
}
90+
setClasspath(javaProject);
91+
}
92+
93+
protected void setClasspath(IJavaProject javaProject) throws JavaModelException {
3994
IProject project = javaProject.getProject();
4095
// The first project to be built may initialize the PDE models, potentially long running, so allow cancellation
4196
PluginModelManager manager = PDECore.getDefault().getModelManager();
@@ -85,4 +140,15 @@ public void requestClasspathContainerUpdate(IPath containerPath, IJavaProject pr
85140
JavaCore.setClasspathContainer(containerPath, new IJavaProject[] {project}, new IClasspathContainer[] {containerSuggestion}, null);
86141
}
87142

143+
private static boolean isCalledFromUI() {
144+
try {
145+
Class<?> display = RequiredPluginsInitializer.class.getClassLoader()
146+
.loadClass("org.eclipse.swt.widgets.Display"); //$NON-NLS-1$
147+
Method findDisplay = display.getMethod("findDisplay", Thread.class); //$NON-NLS-1$
148+
return findDisplay.invoke(null, Thread.currentThread()) != null;
149+
} catch (Exception e) {
150+
}
151+
return false;
152+
}
153+
88154
}

0 commit comments

Comments
 (0)