apache / apache/netbeans

Soft deadlock on clicking Manage in Inspect and Transform dialog

Open
#4,510 2 comments 0 reactions 0 assignees View on GitHub
Java kind:bug os:macos
Dominant language
Java
Stars
3.1k
Forks
935
Avg merge
2d 3h
Merged PRs (30d)
17

Description

### Apache NetBeans version

Apache NetBeans 15 release candidate

### What happened

IDE locks up after opening the Inspect and Transform dialog against a Java source, and then clicking Manage.

I've seen this a couple of times, so I pulled a thread-dump.

The root cause is that `InspectAndRefactorPanel` takes a lock on itself in `manageConfigurationsActionPerformed`, but that lock is shared with the inherited synchronized method `addContainerListener`.

Via accessibility support, the `AppKit` thread (the native Mac OS event thread) is blocked on adding a container listener to the panel, in order to show the dialog - but it cannot because the AWT thread is holding the lock. The AWT thread will hold the lock until the native dialog is opened, which it never will be, because the AppKit thread is blocked on the lock.

*Simple Solution*: `manageConfigurationsActionPerformed` - if it needs to be synchronized at all - must use a private lock not shared by any inherited methods.

(and in general, never write `synchronized` methods in a Swing component or use `synchronized(this)` in one - you have no idea what else you're sharing the lock with, and what you're sharing it with will vary by look and feel and OS)

```
"AppKit Thread" #21 daemon prio=5 os_prio=31 cpu=5255367.20ms elapsed=216720.56s tid=0x000000011e89d400 nid=0x103 waiting for monitor entry [0x000000016b738000]
java.lang.Thread.State: BLOCKED (on object monitor)
at java.awt.Container.addContainerListener(java.desktop@17.0.3/Container.java:2149)
- waiting to lock <0x00000007b0da2638> (a org.netbeans.modules.java.hints.spiimpl.refactoring.InspectAndRefactorPanel)
at java.awt.Container$AccessibleAWTContainer.addPropertyChangeListener(java.desktop@17.0.3/Container.java:3920)
at javax.swing.JComponent$AccessibleJComponent.addPropertyChangeListener(java.desktop@17.0.3/JComponent.java:3820)
at sun.lwawt.macosx.CAccessible.addNotificationListeners(java.desktop@17.0.3/CAccessible.java:108)
at sun.lwawt.macosx.CAccessible.(java.desktop@17.0.3/CAccessible.java:90)
at sun.lwawt.macosx.CAccessible.getCAccessible(java.desktop@17.0.3/CAccessible.java:61)

"AWT-EventQueue-0" #25 prio=6 os_prio=31 cpu=7806878.27ms elapsed=216720.38s tid=0x000000011fb41000 nid=0x11f03 runnable [0x000000016f5d7000]
java.lang.Thread.State: RUNNABLE
at java.util.PriorityQueue.siftUpComparable(java.base@17.0.3/PriorityQueue.java:651)
at java.util.PriorityQueue.siftUp(java.base@17.0.3/PriorityQueue.java:639)
at java.util.PriorityQueue.offer(java.base@17.0.3/PriorityQueue.java:330)
at java.util.concurrent.DelayQueue.offer(java.base@17.0.3/DelayQueue.java:147)
at java.util.concurrent.DelayQueue.add(java.base@17.0.3/DelayQueue.java:133)
at javax.swing.TimerQueue.addTimer(java.desktop@17.0.3/TimerQueue.java:139)
at javax.swing.TimerQueue.addTimer(java.desktop@17.0.3/TimerQueue.java:123)
at javax.swing.Timer.start(java.desktop@17.0.3/Timer.java:553)
at com.apple.laf.AquaProgressBarUI$Animator.actionPerformed(java.desktop@17.0.3/AquaProgressBarUI.java:498)
at javax.swing.Timer.fireActionPerformed(java.desktop@17.0.3/Timer.java:311)
at javax.swing.Timer$DoPostEvent.run(java.desktop@17.0.3/Timer.java:243)
at java.awt.event.InvocationEvent.dispatch(java.desktop@17.0.3/InvocationEvent.java:318)
at java.awt.EventQueue.dispatchEventImpl(java.desktop@17.0.3/EventQueue.java:771)
at java.awt.EventQueue$4.run(java.desktop@17.0.3/EventQueue.java:722)
at java.awt.EventQueue$4.run(java.desktop@17.0.3/EventQueue.java:716)
at java.security.AccessController.executePrivileged(java.base@17.0.3/AccessController.java:776)
at java.security.AccessController.doPrivileged(java.base@17.0.3/AccessController.java:399)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(java.base@17.0.3/ProtectionDomain.java:86)
at java.awt.EventQueue.dispatchEvent(java.desktop@17.0.3/EventQueue.java:741)
at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:136)
at java.awt.EventDispatchThread.pumpOneEventForFilters(java.desktop@17.0.3/EventDispatchThread.java:203)
at java.awt.EventDispatchThread.pumpEventsForFilter(java.desktop@17.0.3/EventDispatchThread.java:124)
at java.awt.EventDispatchThread.pumpEventsForFilter(java.desktop@17.0.3/EventDispatchThread.java:117)
at java.awt.WaitDispatchSupport$2.run(java.desktop@17.0.3/WaitDispatchSupport.java:191)
at java.awt.WaitDispatchSupport$4.run(java.desktop@17.0.3/WaitDispatchSupport.java:236)
at java.awt.WaitDispatchSupport$4.run(java.desktop@17.0.3/WaitDispatchSupport.java:234)
at java.security.AccessController.executePrivileged(java.base@17.0.3/AccessController.java:776)
at java.security.AccessController.doPrivileged(java.base@17.0.3/AccessController.java:318)
at java.awt.WaitDispatchSupport.enter(java.desktop@17.0.3/WaitDispatchSupport.java:234)
at java.awt.Dialog.show(java.desktop@17.0.3/Dialog.java:1080)
at org.netbeans.core.windows.services.NbPresenter.superShow(NbPresenter.java:1074)
at org.netbeans.core.windows.services.NbPresenter.doShow(NbPresenter.java:1124)
at org.netbeans.core.windows.services.NbPresenter.run(NbPresenter.java:1096)
at org.netbeans.core.windows.services.NbPresenter.run(NbPresenter.java:106)
at org.netbeans.modules.openide.util.NbMutexEventProvider$Event.doEventAccess(NbMutexEventProvider.java:123)
at org.netbeans.modules.openide.util.NbMutexEventProvider$Event.readAccess(NbMutexEventProvider.java:77)
at org.netbeans.modules.openide.util.LazyMutexImplementation.readAccess(LazyMutexImplementation.java:71)
at org.openide.util.Mutex.readAccess(Mutex.java:199)
at org.netbeans.core.windows.services.NbPresenter.show(NbPresenter.java:1081)
at java.awt.Component.show(java.desktop@17.0.3/Component.java:1728)
at java.awt.Component.setVisible(java.desktop@17.0.3/Component.java:1675)
at java.awt.Window.setVisible(java.desktop@17.0.3/Window.java:1036)
at java.awt.Dialog.setVisible(java.desktop@17.0.3/Dialog.java:1016)
at org.netbeans.modules.java.hints.spiimpl.refactoring.InspectAndRefactorPanel.manageRefactorings(InspectAndRefactorPanel.java:639)
- locked <0x00000007b0da2638> (a org.netbeans.modules.java.hints.spiimpl.refactoring.InspectAndRefactorPanel)
at org.netbeans.modules.java.hints.spiimpl.refactoring.InspectAndRefactorPanel.manageConfigurationsActionPerformed(InspectAndRefactorPanel.java:386)
```

### How to reproduce

Just attempt to open the dialog on a similarly Mac OS.

### Did this work correctly in an earlier version?

No / Don't know

### Operating System

Mac OS X 21.4.0, Apple Silicon 10 Core MacBook Pro

### JDK

Amazon Corretto 17

### Apache NetBeans packaging

Own source build

### Anything else

I have opened the dialog successfully, so not every time - it appears to depend on how the AppKit thread's tasks get scheduled relative to the AWT thread's tasks.

### Are you willing to submit a pull request?

Yes

### Code of Conduct

Yes

Contributor guide

Open the contributing guide

Research direction

Start in org.netbeans.modules.java.hints.spiimpl.refactoring.InspectAndRefactorPanel, especially manageConfigurationsActionPerformed and manageRefactorings, using the supplied thread dump and line references. Reproduce by opening Inspect and Transform on a Java source and clicking Manage on macOS. Done means the Manage dialog opens without the AppKit and AWT threads blocking each other.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
desktop
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.