Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 342219 - Deadlock adding breakpoint
Summary: Deadlock adding breakpoint
Status: CLOSED DUPLICATE of bug 249951
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Debug (show other bugs)
Version: 3.6.1   Edit
Hardware: PC Windows 7
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: JDT-Debug-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-04-07 16:43 EDT by Marco Hunsicker CLA
Modified: 2013-12-06 10:45 EST (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Marco Hunsicker CLA 2011-04-07 16:43:10 EDT
Build Identifier: Build id: M20100909-0800

Eclipse is configured to saved dirty editors when launching the debugger. For a customer of mine, this triggers a custom action that alters any breakpoints/markers found in the dirty editor right during the save. This can lead to a deadlock because another process might try something similar:

Thread 1 (Editor Save Thread):
java.lang.Object.wait(long)

org.eclipse.core.internal.jobs.Semaphore.acquire(long)

org.eclipse.core.internal.jobs.OrderedLock.doAcquire(Semaphore, long)

org.eclipse.core.internal.jobs.OrderedLock.acquire(long)

org.eclipse.core.internal.jobs.OrderedLock.acquire()

org.eclipse.core.internal.resources.WorkManager.checkIn(ISchedulingRule, IProgressMonitor)

org.eclipse.core.internal.resources.Workspace.prepareOperation(ISchedulingRule, IProgressMonitor)

org.eclipse.core.internal.resources.Workspace.run(IWorkspaceRunnable, ISchedulingRule, int, IProgressMonitor)

org.eclipse.debug.core.model.Breakpoint.setAttribute(String, int)

org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint.incrementInstallCount()

org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint.registerRequest(EventRequest, JDIDebugTarget)

org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint.createRequest(JDIDebugTarget, ReferenceType)

org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint.addToTargetForLocalType(JDIDebugTarget, String)

org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint.createRequests(JDIDebugTarget)

org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint.addToTarget(JDIDebugTarget)

org.eclipse.jdt.internal.debug.core.breakpoints.JavaLineBreakpoint.addToTarget(JDIDebugTarget)

org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget.breakpointAdded(IBreakpoint)

org.eclipse.debug.internal.core.BreakpointManager$BreakpointNotifier.run()

org.eclipse.core.runtime.SafeRunner.run(ISafeRunnable)

org.eclipse.debug.internal.core.BreakpointManager$BreakpointNotifier.notify(IBreakpoint[], IMarkerDelta[], int)

org.eclipse.debug.internal.core.BreakpointManager.fireUpdate(List, List, int)

org.eclipse.debug.internal.core.BreakpointManager.addBreakpoints(IBreakpoint[], boolean)

org.eclipse.debug.internal.core.BreakpointManager.addBreakpoints(IBreakpoint[])

org.eclipse.debug.internal.core.BreakpointManager.addBreakpoint(IBreakpoint)

Thread 2:
java.lang.Object.wait(long)

org.eclipse.core.internal.jobs.Semaphore.acquire(long)

org.eclipse.core.internal.jobs.OrderedLock.doAcquire(Semaphore, long)

org.eclipse.core.internal.jobs.OrderedLock.acquire(long)

org.eclipse.core.internal.jobs.OrderedLock.acquire()

org.eclipse.core.internal.resources.WorkManager.checkIn(ISchedulingRule, IProgressMonitor)

org.eclipse.core.internal.resources.Workspace.prepareOperation(ISchedulingRule, IProgressMonitor)

org.eclipse.core.internal.resources.Workspace.run(IWorkspaceRunnable, ISchedulingRule, int, IProgressMonitor)

org.eclipse.debug.core.model.Breakpoint.setAttribute(String, int)

org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint.decrementInstallCount()

org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint.deregisterRequest(EventRequest, JDIDebugTarget)

org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint.removeRequests(JDIDebugTarget)

org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint.removeFromTarget(JDIDebugTarget)

org.eclipse.jdt.internal.debug.core.breakpoints.JavaLineBreakpoint.removeFromTarget(JDIDebugTarget)

org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget.removeAllBreakpoints()

org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget.cleanup()

org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget.terminated()

org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget.handleVMDeath(VMDeathEvent)

org.eclipse.jdt.internal.debug.core.EventDispatcher.dispatch(EventSet)

org.eclipse.jdt.internal.debug.core.EventDispatcher.access$0(EventDispatcher, EventSet)

org.eclipse.jdt.internal.debug.core.EventDispatcher$1.run(IProgressMonitor)

org.eclipse.core.internal.jobs.Worker.run()


While debugging, I noticed something weird. The save action holds a lock on the editor input. I would therefore assume that adding a marker would use this resource as well, but it tries to get a workspace lock!

The code in org.eclipse.debug.core.model.Breakpoint#getMarkerRule(IResource) uses the IResourceRuleFactory#markerRule(IResource) method, but instead of creating a rule, this method always returns 'null' (at least with my setup and probably for the customer as well, org.eclipse.core.internal.resources.Rules is used). I assume that this behavior causes the workspace lock to be acquired instead of using the same resource as the current process?

Reproducible: Couldn't Reproduce
Comment 1 Pawel Piech CLA 2011-04-08 00:08:19 EDT
Breakpoint listeners should never try to modify breakpoints inside a listener call, they should schedule a job instead.  I've seen dozens of such deadlocks.

For platform I wonder if we could create some kind of an assertion to detect this pattern.

(In reply to comment #0)
> used). I assume that this behavior causes the workspace lock to be acquired
> instead of using the same resource as the current process?

This is correct, the marker rule locks the whole workspace.  I suppose marker modifications happen rarely enough and are quick enough that the resource system folks didn't feel the need to invest in a more granular locking mechanism.
Comment 2 Marco Hunsicker CLA 2011-04-11 04:52:38 EDT
(In reply to comment #1)
> Breakpoint listeners should never try to modify breakpoints inside a listener
> call, they should schedule a job instead.  I've seen dozens of such deadlocks.

The action happens inside an editor save action right before or during debugging.

I've already changed the code to be run inside a workspace job and awaiting customer response whether this indeed fixes the problem.


> For platform I wonder if we could create some kind of an assertion to detect
> this pattern.

Now, that I know this limitation I can deal with it. Better documentation could help here. An assertion would certainly be good if possible.


> (In reply to comment #0)
> > used). I assume that this behavior causes the workspace lock to be acquired
> > instead of using the same resource as the current process?
> 
> This is correct, the marker rule locks the whole workspace.  I suppose marker
> modifications happen rarely enough and are quick enough that the resource
> system folks didn't feel the need to invest in a more granular locking
> mechanism.

The behavior somewhat contradicts the API. There is the specific IResourceRuleFactory#markerRule(IResource). I was quite surprised to learn that this creates a workspace lock.

In org.eclipse.core.internal.resources.Rules there is a comment that says that the "team hook currently cannot change this rule". Maybe it is already planned for a future version to expand here. It would certainly be welcomed.

Anyway, thanks very much for your quick action. Much appreciated.
Comment 3 James Blackburn CLA 2011-05-03 15:49:14 EDT
From the backtraces, it's not clear who holds the WS lock.

The WS  (which is different to WS root rule) is held when modifying the workspace.  No rules are held when modifying markers - both rule factories return null for marker modification.

Can you attach a full backtrace of the threads involved when Eclipse locks up?  If there's a resource change notification caused by the save, in progress then this could very well be: bug 249951
Comment 4 Michael Rennie CLA 2013-12-06 10:45:35 EST
Since the reported issue is with changing markers / resources while saving is occurring, it sounds more likely this is dupe of bug 249951.

I will close this as a dupe until the reporter provides the requested stack dumps (and they prove otherwise).

*** This bug has been marked as a duplicate of bug 249951 ***