From 9b217a6d1d0f47b283d05fc6fb5cb0204cc9e81a 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 | 54 +++++++++++++++++++ 1 file changed, 54 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..76b4aa54a0 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,48 @@ 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.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();