eclipse.platform icon indicating copy to clipboard operation
eclipse.platform copied to clipboard

Random UI freezes because of never ending `IOConsolePartitioner...processPendingPartitions`

Open sebthom opened this issue 1 month ago • 6 comments

Let's make sure issue is not already fixed in latest builds first.

Steps to reproduce

I don't know, the freezes happen randomly. I have not seen a common pattern. I noticed the issue since upgrading to Eclipse 2025-09

I expected: The UI not permanently freeze

But got: Eclipse does not respond, I have to kill the process

Here is some relevant log output

From <workspace>/.metadata/.log

!ENTRY org.eclipse.ui.monitoring 2 0 2025-11-17 17:58:47.323
!MESSAGE UI freeze of 27s at 17:58:20.373
!SUBENTRY 1 org.eclipse.ui.monitoring 1 0 2025-11-17 17:58:47.323
!MESSAGE Sample at 17:58:31.030 (+10,657s)
Thread 'main' tid=1 (RUNNABLE)
!STACK 0
Stack Trace
	at org.eclipse.swt.internal.win32.OS.ScriptShape(Native Method)
	at org.eclipse.swt.graphics.TextLayout.shape(TextLayout.java:3674)
	at org.eclipse.swt.graphics.TextLayout.shape(TextLayout.java:3760)
	at org.eclipse.swt.graphics.TextLayout.computeRuns(TextLayout.java:513)
	at org.eclipse.swt.graphics.TextLayout.getBounds(TextLayout.java:1793)
	at org.eclipse.swt.custom.StyledTextRenderer.calculate(StyledTextRenderer.java:307)
	at org.eclipse.swt.custom.StyledTextRenderer.getLineHeight(StyledTextRenderer.java:758)
	at org.eclipse.swt.custom.StyledTextRenderer.getLineHeight(StyledTextRenderer.java:749)
	at org.eclipse.swt.custom.StyledText.getLinePixel(StyledText.java:3906)
	at org.eclipse.swt.custom.StyledText.handleTextChanging(StyledText.java:6156)
	at org.eclipse.swt.custom.StyledText$5.textChanging(StyledText.java:5438)
	at org.eclipse.ui.internal.console.ConsoleDocumentAdapter.documentAboutToBeChanged(ConsoleDocumentAdapter.java:418)
	at org.eclipse.jface.text.AbstractDocument.fireDocumentAboutToBeChanged(AbstractDocument.java:636)
	at org.eclipse.jface.text.AbstractDocument.replace(AbstractDocument.java:1082)
	at org.eclipse.jface.text.AbstractDocument.replace(AbstractDocument.java:1109)
	at org.eclipse.ui.internal.console.ConsoleDocument.replace(ConsoleDocument.java:74)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.applyOutputToDocument(IOConsolePartitioner.java:1145)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.applyStreamOutput(IOConsolePartitioner.java:968)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.processPendingPartitions(IOConsolePartitioner.java:805)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.runInUIThread(IOConsolePartitioner.java:763)
	at org.eclipse.ui.progress.UIJob.lambda$0(UIJob.java:148)
	at org.eclipse.ui.progress.UIJob$$Lambda/0x00000007c0f18800.run(Unknown Source)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:40)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:132)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:4135)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3751)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1151)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1042)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:153)
	at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:678)
	at org.eclipse.ui.internal.Workbench$$Lambda/0x00000007c033fc70.run(Unknown Source)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:583)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:173)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:185)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:219)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:149)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:115)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:467)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:298)
	at [email protected]/java.lang.invoke.DirectMethodHandle$Holder.invokeStatic(DirectMethodHandle$Holder)
	at [email protected]/java.lang.invoke.LambdaForm$MH/0x00000007c018d800.invoke(LambdaForm$MH)
	at [email protected]/java.lang.invoke.LambdaForm$MH/0x00000007c018dc00.invokeExact_MT(LambdaForm$MH)
	at [email protected]/jdk.internal.reflect.DirectMethodHandleAccessor.invokeImpl(DirectMethodHandleAccessor.java:155)
	at [email protected]/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at [email protected]/java.lang.reflect.Method.invoke(Method.java:580)
	at app//org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:627)
	at app//org.eclipse.equinox.launcher.Main.basicRun(Main.java:575)
	at app//org.eclipse.equinox.launcher.Main.run(Main.java:1431)
!SUBENTRY 1 org.eclipse.ui.monitoring 1 0 2025-11-17 17:58:47.323
!MESSAGE Sample at 17:58:36.358 (+5,328s)
Thread 'main' tid=1 (RUNNABLE)
!STACK 0
Stack Trace
	at org.eclipse.swt.internal.win32.OS.ScriptShape(Native Method)
	at org.eclipse.swt.graphics.TextLayout.shape(TextLayout.java:3674)
	at org.eclipse.swt.graphics.TextLayout.shape(TextLayout.java:3760)
	at org.eclipse.swt.graphics.TextLayout.computeRuns(TextLayout.java:513)
	at org.eclipse.swt.graphics.TextLayout.getBounds(TextLayout.java:1793)
	at org.eclipse.swt.custom.StyledTextRenderer.calculate(StyledTextRenderer.java:307)
	at org.eclipse.swt.custom.StyledTextRenderer.getLineHeight(StyledTextRenderer.java:758)
	at org.eclipse.swt.custom.StyledTextRenderer.getLineHeight(StyledTextRenderer.java:749)
	at org.eclipse.swt.custom.StyledText.getLinePixel(StyledText.java:3906)
	at org.eclipse.swt.custom.StyledText.handleTextChanging(StyledText.java:6156)
	at org.eclipse.swt.custom.StyledText$5.textChanging(StyledText.java:5438)
	at org.eclipse.ui.internal.console.ConsoleDocumentAdapter.documentAboutToBeChanged(ConsoleDocumentAdapter.java:418)
	at org.eclipse.jface.text.AbstractDocument.fireDocumentAboutToBeChanged(AbstractDocument.java:636)
	at org.eclipse.jface.text.AbstractDocument.replace(AbstractDocument.java:1082)
	at org.eclipse.jface.text.AbstractDocument.replace(AbstractDocument.java:1109)
	at org.eclipse.ui.internal.console.ConsoleDocument.replace(ConsoleDocument.java:74)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.applyOutputToDocument(IOConsolePartitioner.java:1145)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.applyStreamOutput(IOConsolePartitioner.java:968)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.processPendingPartitions(IOConsolePartitioner.java:805)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.runInUIThread(IOConsolePartitioner.java:763)
	at org.eclipse.ui.progress.UIJob.lambda$0(UIJob.java:148)
	at org.eclipse.ui.progress.UIJob$$Lambda/0x00000007c0f18800.run(Unknown Source)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:40)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:132)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:4135)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3751)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1151)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1042)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:153)
	at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:678)
	at org.eclipse.ui.internal.Workbench$$Lambda/0x00000007c033fc70.run(Unknown Source)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:583)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:173)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:185)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:219)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:149)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:115)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:467)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:298)
	at [email protected]/java.lang.invoke.DirectMethodHandle$Holder.invokeStatic(DirectMethodHandle$Holder)
	at [email protected]/java.lang.invoke.LambdaForm$MH/0x00000007c018d800.invoke(LambdaForm$MH)
	at [email protected]/java.lang.invoke.LambdaForm$MH/0x00000007c018dc00.invokeExact_MT(LambdaForm$MH)
	at [email protected]/jdk.internal.reflect.DirectMethodHandleAccessor.invokeImpl(DirectMethodHandleAccessor.java:155)
	at [email protected]/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at [email protected]/java.lang.reflect.Method.invoke(Method.java:580)
	at app//org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:627)
	at app//org.eclipse.equinox.launcher.Main.basicRun(Main.java:575)
	at app//org.eclipse.equinox.launcher.Main.run(Main.java:1431)
...

!SUBENTRY 1 org.eclipse.ui.monitoring 1 0 2025-11-17 18:02:22.371
!MESSAGE Sample at 18:02:13.451 (+10,657s)
Thread 'main' tid=1 (RUNNABLE)
!STACK 0
Stack Trace
	at org.eclipse.swt.internal.win32.OS.ScriptShape(Native Method)
	at org.eclipse.swt.graphics.TextLayout.shape(TextLayout.java:3674)
	at org.eclipse.swt.graphics.TextLayout.shape(TextLayout.java:3760)
	at org.eclipse.swt.graphics.TextLayout.computeRuns(TextLayout.java:513)
	at org.eclipse.swt.graphics.TextLayout.getBounds(TextLayout.java:1793)
	at org.eclipse.swt.custom.StyledTextRenderer.calculate(StyledTextRenderer.java:307)
	at org.eclipse.swt.custom.StyledTextRenderer.getLineHeight(StyledTextRenderer.java:758)
	at org.eclipse.swt.custom.StyledTextRenderer.getLineHeight(StyledTextRenderer.java:749)
	at org.eclipse.swt.custom.StyledText.getLinePixel(StyledText.java:3906)
	at org.eclipse.swt.custom.StyledText.handleTextChanging(StyledText.java:6156)
	at org.eclipse.swt.custom.StyledText$5.textChanging(StyledText.java:5438)
	at org.eclipse.ui.internal.console.ConsoleDocumentAdapter.documentAboutToBeChanged(ConsoleDocumentAdapter.java:418)
	at org.eclipse.jface.text.AbstractDocument.fireDocumentAboutToBeChanged(AbstractDocument.java:636)
	at org.eclipse.jface.text.AbstractDocument.replace(AbstractDocument.java:1082)
	at org.eclipse.jface.text.AbstractDocument.replace(AbstractDocument.java:1109)
	at org.eclipse.ui.internal.console.ConsoleDocument.replace(ConsoleDocument.java:74)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.applyOutputToDocument(IOConsolePartitioner.java:1145)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.applyStreamOutput(IOConsolePartitioner.java:968)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.processPendingPartitions(IOConsolePartitioner.java:805)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.runInUIThread(IOConsolePartitioner.java:763)
	at org.eclipse.ui.progress.UIJob.lambda$0(UIJob.java:148)
	at org.eclipse.ui.progress.UIJob$$Lambda/0x00000007c0f18800.run(Unknown Source)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:40)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:132)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:4135)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3751)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1151)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1042)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:153)
	at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:678)
	at org.eclipse.ui.internal.Workbench$$Lambda/0x00000007c033fc70.run(Unknown Source)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:583)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:173)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:185)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:219)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:149)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:115)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:467)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:298)
	at [email protected]/java.lang.invoke.DirectMethodHandle$Holder.invokeStatic(DirectMethodHandle$Holder)
	at [email protected]/java.lang.invoke.LambdaForm$MH/0x00000007c018d800.invoke(LambdaForm$MH)
	at [email protected]/java.lang.invoke.LambdaForm$MH/0x00000007c018dc00.invokeExact_MT(LambdaForm$MH)
	at [email protected]/jdk.internal.reflect.DirectMethodHandleAccessor.invokeImpl(DirectMethodHandleAccessor.java:155)
	at [email protected]/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at [email protected]/java.lang.reflect.Method.invoke(Method.java:580)
	at app//org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:627)
	at app//org.eclipse.equinox.launcher.Main.basicRun(Main.java:575)
	at app//org.eclipse.equinox.launcher.Main.run(Main.java:1431)
!SUBENTRY 1 org.eclipse.ui.monitoring 1 0 2025-11-17 18:02:22.371
!MESSAGE Sample at 18:02:18.778 (+5,327s)
Thread 'main' tid=1 (RUNNABLE)
!STACK 0
Stack Trace
	at org.eclipse.swt.internal.win32.OS.ScriptShape(Native Method)
	at org.eclipse.swt.graphics.TextLayout.shape(TextLayout.java:3674)
	at org.eclipse.swt.graphics.TextLayout.shape(TextLayout.java:3760)
	at org.eclipse.swt.graphics.TextLayout.computeRuns(TextLayout.java:513)
	at org.eclipse.swt.graphics.TextLayout.getBounds(TextLayout.java:1793)
	at org.eclipse.swt.custom.StyledTextRenderer.calculate(StyledTextRenderer.java:307)
	at org.eclipse.swt.custom.StyledTextRenderer.getLineHeight(StyledTextRenderer.java:758)
	at org.eclipse.swt.custom.StyledTextRenderer.getLineHeight(StyledTextRenderer.java:749)
	at org.eclipse.swt.custom.StyledText.getLinePixel(StyledText.java:3906)
	at org.eclipse.swt.custom.StyledText.handleTextChanging(StyledText.java:6156)
	at org.eclipse.swt.custom.StyledText$5.textChanging(StyledText.java:5438)
	at org.eclipse.ui.internal.console.ConsoleDocumentAdapter.documentAboutToBeChanged(ConsoleDocumentAdapter.java:418)
	at org.eclipse.jface.text.AbstractDocument.fireDocumentAboutToBeChanged(AbstractDocument.java:636)
	at org.eclipse.jface.text.AbstractDocument.replace(AbstractDocument.java:1082)
	at org.eclipse.jface.text.AbstractDocument.replace(AbstractDocument.java:1109)
	at org.eclipse.ui.internal.console.ConsoleDocument.replace(ConsoleDocument.java:74)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.applyOutputToDocument(IOConsolePartitioner.java:1145)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.applyStreamOutput(IOConsolePartitioner.java:968)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.processPendingPartitions(IOConsolePartitioner.java:805)
	at org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.runInUIThread(IOConsolePartitioner.java:763)
	at org.eclipse.ui.progress.UIJob.lambda$0(UIJob.java:148)
	at org.eclipse.ui.progress.UIJob$$Lambda/0x00000007c0f18800.run(Unknown Source)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:40)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:132)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:4135)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3751)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1151)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1042)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:153)
	at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:678)
	at org.eclipse.ui.internal.Workbench$$Lambda/0x00000007c033fc70.run(Unknown Source)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:583)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:173)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:185)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:219)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:149)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:115)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:467)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:298)
	at [email protected]/java.lang.invoke.DirectMethodHandle$Holder.invokeStatic(DirectMethodHandle$Holder)
	at [email protected]/java.lang.invoke.LambdaForm$MH/0x00000007c018d800.invoke(LambdaForm$MH)
	at [email protected]/java.lang.invoke.LambdaForm$MH/0x00000007c018dc00.invokeExact_MT(LambdaForm$MH)
	at [email protected]/jdk.internal.reflect.DirectMethodHandleAccessor.invokeImpl(DirectMethodHandleAccessor.java:155)
	at [email protected]/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at [email protected]/java.lang.reflect.Method.invoke(Method.java:580)
	at app//org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:627)
	at app//org.eclipse.equinox.launcher.Main.basicRun(Main.java:575)
	at app//org.eclipse.equinox.launcher.Main.run(Main.java:1431)

Tested under this environment:

  • OS & version: Windows 10
  • Eclipse IDE/Platform version (as shown in Help > About): Version: 2025-09 (4.37.0) Build id: 20250905-1456

Community

  • [/] I understand reporting an issue to this OSS project does not mandate anyone to fix it. Other contributors may consider the issue, or not, at their own convenience. The most efficient way to get it fixed is that I fix it myself and contribute it back as a good quality patch to the project.

sebthom avatar Nov 17 '25 17:11 sebthom

I let codex (gpt 5.1 high) analyze the issue:

UI freeze involving IOConsolePartitioner and console text layout

1. Evidence from workspace.log

  • The log in workspace.log reports a UI freeze of ~31 seconds:
    • !ENTRY org.eclipse.ui.monitoring 2 0 2025-11-17 18:00:18.276
    • !MESSAGE UI freeze of 31s at 17:59:47.709
  • Samples during the freeze show the main UI thread (Thread 'main' tid=1 (RUNNABLE)) busy, not blocked on a lock.
  • Representative sampled stack (abridged):
    • org.eclipse.swt.internal.win32.OS.ScriptShape / ScriptGetLogicalWidths / ScriptBreak
    • org.eclipse.swt.graphics.TextLayout.computeRuns / getBounds
    • org.eclipse.swt.custom.StyledTextRenderer.calculate / getLineHeight
    • org.eclipse.swt.custom.StyledText.handleTextChanging
    • org.eclipse.swt.custom.StyledText$5.textChanging
    • org.eclipse.ui.internal.console.ConsoleDocumentAdapter.documentAboutToBeChanged(ConsoleDocumentAdapter.java:418)
    • org.eclipse.jface.text.AbstractDocument.replace(...)
    • org.eclipse.ui.internal.console.ConsoleDocument.replace(...)
    • org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.applyOutputToDocument(IOConsolePartitioner.java:1145)
    • org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.applyStreamOutput(IOConsolePartitioner.java:968)
    • org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.processPendingPartitions(IOConsolePartitioner.java:805)
    • org.eclipse.ui.internal.console.IOConsolePartitioner$QueueProcessingJob.runInUIThread(IOConsolePartitioner.java:763)
    • SWT event loop / workbench run loop.

Conclusion: the UI thread is CPU-bound inside SWT text layout invoked as part of console document updates triggered by IOConsolePartitioner.QueueProcessingJob.

2. Relevant code in this repository

2.1 IOConsolePartitioner (debug/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/IOConsolePartitioner.java)

  • Maintains console partitions and a bounded queue of pending output:
    • MAX_BUFFER_BYTES = 16_000_000 (approx 16 MB).
    • BlockingQueue<PendingPartition> pendingPartitions = new LinkedBlockingQueue<>(MAX_BUFFER_BYTES / 8192);
    • Comment: up to ~16 MB pending when the debuggee produces output faster than it can be processed.
  • Output from streams is enqueued via:
    • public void streamAppended(IOConsoleOutputStream stream, String s)
      • Wraps text in PendingPartition and offers into pendingPartitions.
      • On failure, calls helpProgress(); if called on the UI thread (Display.getCurrent() != null), it directly calls queueJob.processPendingPartitions().
      • Schedules queueJob after enqueuing.
  • QueueProcessingJob is a UIJob:
    • public IStatus runInUIThread(IProgressMonitor monitor) calls processPendingPartitions().
    • processPendingPartitions():
      • Drains the entire queue into a local list: pendingPartitions.drainTo(pendingCopy);.
      • Under synchronized (partitions):
        • Calls applyStreamOutput(pendingCopy, sizeHint);
        • Then checkFinished();
        • Then checkBufferSize(); (trimming if high-water mark is exceeded).
  • applyStreamOutput(...):
    • Runs entirely under the partitions lock and on the UI thread.
    • Iterates all PendingPartitions, interprets control characters, computes partition updates, and accumulates text into a StringBuilder content.
    • Calls applyOutputToDocument(content.toString(), nextWriteOffset, replaceLength) at various points and once at the end.
  • applyOutputToDocument(...):
    • Sets updateType = DocUpdateType.OUTPUT.
    • Executes document.replace(offset, length, text) (JFace document API).
    • This replace triggers ConsoleDocumentAdapter.documentAboutToBeChanged, which in turn fires TextChangingEvent to StyledText, causing expensive SWT TextLayout recalculation.

2.2 Console buffer trimming

  • High/low watermark configuration:
    • In IOConsole (debug/org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsole.java), setWaterMarks(int low, int high) validates and forwards to the partitioner:
      • partitioner.setWaterMarks(low, high);
    • In IOConsolePartitioner.setWaterMarks(...):
      • Stores lowWaterMark and highWaterMark.
      • Schedules checkBufferSize() via ConsolePlugin.getStandardDisplay().asyncExec(this::checkBufferSize);.
  • checkBufferSize():
    • If document != null && highWaterMark > 0 and document.getLength() > highWaterMark:
      • Calls trim(length - lowWaterMark, true); synchronously in the UI thread.
  • trim(...):
    • Uses document.getLineOfOffset(...) / getLineOffset(...) to find the cut position.
    • Either clears the whole document or:
      • Adjusts the first partition and then document.replace(0, cutOffset, "").
      • Rebuilds partition offsets and adjusts outputOffset.
    • All of this runs under synchronized (partitions) and on the UI thread, again invoking StyledText text layout.
  • Debug consoles (ProcessConsole) configure watermarks from user preferences:
    • In ProcessConsole.init():
      • If CONSOLE_LIMIT_CONSOLE_OUTPUT is true, calls setWaterMarks(lowWater, highWater).
      • If the preference is false, it calls setWaterMarks(-1, -1), which disables trimming (highWaterMark remains negative).

2.3 ConsoleDocumentAdapter

  • ConsoleDocumentAdapter (debug/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/ConsoleDocumentAdapter.java) bridges the JFace document and SWT StyledText.
  • documentAboutToBeChanged(DocumentEvent event) builds a TextChangingEvent and notifies TextChangeListeners (including StyledText):
    • This drives StyledText.handleTextChanging(...) and ultimately TextLayout (computeRuns, getBounds, etc), which is exactly what appears on the hot stack frames in the freeze sampling.
  • In fixed-width / wrapping mode, ConsoleDocumentAdapter does extra work to recompute wrapped lines, which amplifies the cost of each document change for large documents.

3. Analysis of the freeze

  1. The freeze is not a deadlock but a long CPU-bound operation on the main UI thread.
    • The thread state is RUNNABLE with hot frames inside OS.ScriptShape / ScriptGetLogicalWidths / ScriptBreak, indicating heavy text shaping and layout.
  2. The call chain ties the expensive layout directly to console output processing:
    • IOConsolePartitioner$QueueProcessingJob.runInUIThreadprocessPendingPartitionsapplyStreamOutputapplyOutputToDocumentdocument.replaceConsoleDocumentAdapter.documentAboutToBeChangedStyledText.handleTextChangingTextLayout.computeRuns → native shaping.
  3. QueueProcessingJob drains all pending output (pendingPartitions.drainTo(...)) and processes it in one UI job, while holding the partitions lock.
    • In the worst case, up to ~16 MB of pending text (the queue’s capacity) can be processed in one go.
    • Each large document.replace on a big document forces StyledText to recompute layout, which scales poorly with document size, line length, and wrapping.
  4. If console output limiting is disabled (watermarks -1, -1), the console document can grow without bound.
    • That makes each subsequent layout more expensive, especially with word wrap or complex fonts.
    • Even when limit is enabled, the current implementation still applies all pending output to the document and then trims, so text that will be discarded still passes through layout.
  5. helpProgress() can run processPendingPartitions() directly on whichever thread is calling streamAppended(...).
    • If any code writes to the console from the UI thread (not the usual case, but possible), helpProgress() can run the entire QueueProcessingJob synchronously inside a UI event or paint, further increasing the chance of visible stalls.

Net effect: under heavy or bursty console output, particularly with disabled or high watermarks and word wrapping, QueueProcessingJob can issue very large document.replace operations from the UI thread, forcing StyledText to do large-scale layout and text shaping. This can easily consume tens of seconds of CPU time, manifesting as the reported UI freeze.

4. Potential fixes in this code base

Below are concrete directions for fixes that can be implemented in this repository. They focus on limiting the amount of work done per UI pass and avoiding layout for text that will be discarded.

4.1 Limit work per QueueProcessingJob run

Problem:

  • processPendingPartitions() drains the entire pendingPartitions queue and processes all output in one runInUIThread call.
  • With high-volume output, this can mean processing many megabytes in a single UI job, blocking the UI for a long time.

Potential change:

  • Introduce an upper bound on the amount of text processed in a single UI run, e.g.:
    • MAX_CHARS_PER_RUN (e.g. 256k or 512k characters), or
    • MAX_PENDING_PER_RUN (limited number of PendingPartition entries).
  • Modify processPendingPartitions() to:
    • Accumulate PendingPartitions from pendingPartitions until the per-run limit is reached.
    • Leave remaining entries in the queue.
    • After applyStreamOutput(...) completes, reschedule queueJob if the queue is still non-empty.

Expected impact:

  • Each runInUIThread execution becomes bounded in time, preventing 10+ second single-pass stalls.
  • Console throughput remains high, but updates are amortized over multiple UI jobs, giving the event loop a chance to process other events between chunks.
  • This is a local change in IOConsolePartitioner.QueueProcessingJob and does not alter public API.

Notes:

  • The existing comment about draining the whole buffer to “skip drawing text that exceeds the console buffer size” would need updating.
    • Even with chunking, checkBufferSize() can still be used to ensure trimming, but the layout cost will be distributed across multiple jobs instead of a single massive update.

4.2 Avoid layout work for text that will be trimmed

Problem:

  • When the console has a high-water mark configured and a large amount of new text arrives, we currently:
    • Apply all text to the document via applyStreamOutput(...) and applyOutputToDocument(...).
    • Then run checkBufferSize() and trim(...) to enforce watermarks.
  • Text that is immediately trimmed still incurs the full cost of layout and partitioning.

Potential change:

  • Before building the final content in applyStreamOutput(...), compute how much of the pending text would actually be visible after trimming:
    • Use document.getLength(), highWaterMark, and lowWaterMark to determine the maximum number of characters worth appending.
    • Skip or partially skip older pending segments that are guaranteed to be trimmed away, updating outputOffset/partitions as if the characters had been written, but without calling document.replace for them.
  • Only call applyOutputToDocument(...) with the subset of text that will remain in the document after trimming.

Expected impact:

  • Reduces the amount of text StyledText must lay out for long-running consoles that are already beyond their configured buffer size.
  • Works especially well when debuggee output exceeds the configured high water mark by a large margin in short bursts.

Complexity considerations:

  • Partition and outputOffset bookkeeping still need to reflect the full logical output, even for skipped regions.
  • This is more invasive than chunking, so it is a second-stage optimization after per-run limits.

4.3 Enforce safer defaults and bounds for console buffer size

Problem:

  • If users disable CONSOLE_LIMIT_CONSOLE_OUTPUT in debug preferences, setWaterMarks(-1, -1) disables trimming entirely.
  • A single console can then accumulate very large documents, making every layout operation expensive.

Potential change:

  • In ProcessConsole.init() and propertyChange(...), clamp watermarks to reasonable maxima even when the preference suggests “unlimited”:
    • Example: if user disables the limit, internally use a large but finite default (e.g. 1–5 million characters) instead of -1.
    • Alternatively, introduce a hard upper bound on highWaterMark (e.g. Math.min(configuredHigh, MAX_SAFE_HIGH_WATER_MARK)).

Expected impact:

  • Prevents pathological console sizes that can lead to multi-second layout times, while still respecting the intention of “large” buffers.
  • Requires careful communication or release notes, since it slightly changes the behavior of the “unlimited” setting.

4.4 Guard against synchronous processing from the UI thread

Problem:

  • helpProgress() calls processPendingPartitions() directly when Display.getCurrent() != null, i.e. when streamAppended(...) is invoked on the UI thread.

Potential change:

  • Change helpProgress() so that it never runs processPendingPartitions() synchronously on the UI thread:
    • Always schedule queueJob instead (possibly with schedule(0)).
    • If necessary, keep a small timeout/back-pressure mechanism for non-UI threads only.

Expected impact:

  • Ensures that even if code writes to the console from the UI thread, it does not trigger an unbounded chunk of console processing in the middle of unrelated UI logic.

5. Summary

  • The freeze reported in workspace.log is caused by heavy SWT TextLayout work on the main UI thread during console output updates.
  • The concrete code path runs through IOConsolePartitioner.QueueProcessingJob, which currently:
    • Drains up to ~16 MB of pending output in a single UI job,
    • Performs all parsing and partition updates under a lock in the UI thread, and
    • Applies large document.replace operations that trigger expensive StyledText layout via ConsoleDocumentAdapter.
  • Under high or bursty output, especially with large/unchecked console buffers and word wrapping, this can lead to multi-second UI stalls even though the thread is not blocked on locks.
  • The most promising fixes within this repository are:
    • Limiting per-run work in QueueProcessingJob (chunking pending output),
    • Avoiding layout for text that will immediately be trimmed,
    • Enforcing safer bounds on console buffer size, and
    • Avoiding direct processPendingPartitions() calls from the UI thread.

These changes keep console behavior functionally the same while significantly reducing the risk of long UI freezes caused by console output processing.

sebthom avatar Nov 17 '25 17:11 sebthom

Have you enabled "line wrapping" in the Console? That may require extra CPU cycles...

iloveeclipse avatar Nov 17 '25 18:11 iloveeclipse

Yes it was enabled. Console buffer size is already set to only 20.000 chars.

I'll try to disable it but it should not freeze the whole UI for minutes. I waited for 5 minutes and killed the process.

sebthom avatar Nov 17 '25 18:11 sebthom

Do you have any monitor scaling (i.e., zoom != 100%) enabled for either the monitor your application window is placed on or for your primary monitor? I have to admit that I don't know well the involved code, but I have seen how sensitive the TextLayout is to not properly fitting calculated sizes between itself and the StyledText, which may cause errors or long running calculations. There are many pixel/point conversions used in TextLayout, so it could be that some of the calculated values' rounding is unfortunately off at specific zooms or with specific configurations (such as the mentioned line wrapping, which probably also operates on pixel/point converted values).

HeikoKlare avatar Nov 17 '25 19:11 HeikoKlare

No I am not using any scaling.

Image

Unfortunately I couldn't determined a specific usage pattern that results in the freeze. It just randomly freezes.

sebthom avatar Nov 17 '25 19:11 sebthom

Thank you! Still good to know, as we can exclude that category of potential causes then.

HeikoKlare avatar Nov 17 '25 19:11 HeikoKlare