Skip to content

Commit

Permalink
Defer initialization of classpath to the background if called from main
Browse files Browse the repository at this point in the history
Currently there are some bad behaving UI components in the eclipse IDE
that trigger resolving of the classpath containers in the process of
creating 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 decrease time from starting eclipse until UI is shown
noticeable.

Fix #1481
  • Loading branch information
laeubi committed Jan 7, 2025
1 parent 5baaa6d commit 588fad8
Showing 1 changed file with 67 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,86 @@
*******************************************************************************/
package org.eclipse.pde.internal.core;

import java.lang.StackWalker.Option;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jdt.core.ClasspathContainerInitializer;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.pde.core.plugin.IPluginModelBase;

public class RequiredPluginsInitializer extends ClasspathContainerInitializer {

private static final AtomicBoolean WARNING_LOGGED = new AtomicBoolean();

private static final Map<IJavaProject, Job> JOB_MAP = new ConcurrentHashMap<>();

private static final Job initPDEJob = Job.create(PDECoreMessages.PluginModelManager_InitializingPluginModels,
monitor -> {
if (!PDECore.getDefault().getModelManager().isInitialized()) {
PDECore.getDefault().getModelManager().targetReloaded(monitor);
}
});

private static StackWalker walker = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE);

@Override
public void initialize(IPath containerPath, IJavaProject javaProject) throws CoreException {
if (isCalledWhileWorkbenchStartup()) {
// See https://github.com/eclipse-pde/eclipse.pde/issues/1481
if (WARNING_LOGGED.compareAndSet(false, true)) {
ILog.get().warn(
"RequiredPluginsInitializer called from within the Application startup thread this will badly impact your IDE performance!", //$NON-NLS-1$
new RuntimeException("Called from Application startup thread thread here")); //$NON-NLS-1$
}
JOB_MAP.compute(javaProject, (jp, oldjob) -> {
if (oldjob != null) {
oldjob.cancel();
}
Job job = Job.create(PDECoreMessages.PluginModelManager_InitializingPluginModels, m -> {
if (oldjob != null) {
try {
oldjob.join();
} catch (InterruptedException e) {
}
}
setClasspath(jp);
});
job.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
JOB_MAP.remove(jp);
}
});
job.schedule();
return job;
});
return;
}
Job job = JOB_MAP.get(javaProject);
if (job != null) {
try {
job.join();
} catch (InterruptedException e) {
}
}
setClasspath(javaProject);
}

protected void setClasspath(IJavaProject javaProject) throws JavaModelException {
IProject project = javaProject.getProject();
// The first project to be built may initialize the PDE models, potentially long running, so allow cancellation
PluginModelManager manager = PDECore.getDefault().getModelManager();
Expand Down Expand Up @@ -85,4 +142,14 @@ public void requestClasspathContainerUpdate(IPath containerPath, IJavaProject pr
JavaCore.setClasspathContainer(containerPath, new IJavaProject[] {project}, new IClasspathContainer[] {containerSuggestion}, null);
}

private static boolean isCalledWhileWorkbenchStartup() {

return walker.walk(frames -> {
return frames.anyMatch(sf -> {
return "org.eclipse.e4.ui.internal.workbench.E4Workbench".equals(sf.getClassName()) //$NON-NLS-1$
&& "createAndRunUI".equals(sf.getMethodName()); //$NON-NLS-1$
});
});
}

}

0 comments on commit 588fad8

Please sign in to comment.