From 6a16fed13a623ea0661d7716e2e5df598f09456f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Tue, 17 Dec 2024 12:00:01 +0100 Subject: [PATCH] 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 https://github.com/eclipse-pde/eclipse.pde/issues/1481 --- .../core/RequiredPluginsInitializer.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/RequiredPluginsInitializer.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/RequiredPluginsInitializer.java index a639647fbb..9ce9bd5687 100644 --- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/RequiredPluginsInitializer.java +++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/RequiredPluginsInitializer.java @@ -13,20 +13,32 @@ *******************************************************************************/ package org.eclipse.pde.internal.core; +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 JOB_MAP = new ConcurrentHashMap<>(); + private static final Job initPDEJob = Job.create(PDECoreMessages.PluginModelManager_InitializingPluginModels, monitor -> { if (!PDECore.getDefault().getModelManager().isInitialized()) { @@ -36,6 +48,39 @@ public class RequiredPluginsInitializer extends ClasspathContainerInitializer { @Override public void initialize(IPath containerPath, IJavaProject javaProject) throws CoreException { + if ("main".equals(Thread.currentThread().getName())) { //$NON-NLS-1$ + // See https://github.com/eclipse-pde/eclipse.pde/issues/1481 + if (WARNING_LOGGED.compareAndSet(false, true)) { + ILog.get().warn( + "RequiredPluginsInitializer called from within the UI thread this will badly impact your IDE performance!", //$NON-NLS-1$ + new RuntimeException("Called from main thread here")); //$NON-NLS-1$ + } + JOB_MAP.computeIfAbsent(javaProject, jp -> { + Job job = Job.create(PDECoreMessages.PluginModelManager_InitializingPluginModels, m -> { + 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();