This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 156443

Summary: Deadlock on Source vs. CloneableOpenSupport$Listener in EventSupport$DocListener.propertyChange
Product: editor Reporter: Jesse Glick <jglick>
Component: Parsing & IndexingAssignee: issues@editor <issues>
Status: RESOLVED FIXED    
Severity: blocker CC: issues, mslama, phejl
Priority: P3 Keywords: THREAD
Version: 6.x   
Hardware: All   
OS: All   
Issue Type: DEFECT Exception Reporter:

Description Jesse Glick 2009-01-07 20:27:23 UTC
090105; IDE froze opening a source file. Bug seems to be in EventSupport$DocListener.propertyChange - you are not
permitted to acquire a lock in a listener callback.

Found one Java-level deadlock:
=============================
"OpenIDE-request-processor-1":
  waiting to lock monitor 0x09397be8 (object 0x67ea9128, a org.netbeans.modules.parsing.api.Source),
  which is held by "JavaSourceTaskFactory"
"JavaSourceTaskFactory":
  waiting to lock monitor 0x09aa3470 (object 0x67e970d8, a org.openide.windows.CloneableOpenSupport$Listener),
  which is held by "Document Processing"
"Document Processing":
  waiting to lock monitor 0x09397be8 (object 0x67ea9128, a org.netbeans.modules.parsing.api.Source),
  which is held by "JavaSourceTaskFactory"

Java stack information for the threads listed above:
===================================================
"OpenIDE-request-processor-1":
	at org.netbeans.modules.parsing.api.Source$MySourceAccessor.getCache(Source.java:547)
	- waiting to lock <0x67ea9128> (a org.netbeans.modules.parsing.api.Source)
	at org.netbeans.modules.parsing.spi.Scheduler$1.run(Scheduler.java:147)
	at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:573)
	at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:1005)
"JavaSourceTaskFactory":
	at org.openide.text.CloneableEditorSupport.getDocument(CloneableEditorSupport.java:876)
	- waiting to lock <0x67e970d8> (a org.openide.windows.CloneableOpenSupport$Listener)
	at org.netbeans.modules.java.source.parsing.JavacParser$DocListener.<init>(JavacParser.java:970)
	at org.netbeans.modules.java.source.parsing.JavacParser.<init>(JavacParser.java:237)
	at org.netbeans.modules.java.source.parsing.JavacParserFactory.createParser(JavacParserFactory.java:64)
	at org.netbeans.modules.java.source.parsing.JavacParserFactory.createParser(JavacParserFactory.java:56)
	at org.netbeans.modules.parsing.impl.SourceCache.getParser(SourceCache.java:153)
	- locked <0x67ea9128> (a org.netbeans.modules.parsing.api.Source)
	at org.netbeans.modules.parsing.impl.event.EventSupport.init(EventSupport.java:125)
	- locked <0x67ea9198> (a org.netbeans.modules.parsing.impl.event.EventSupport)
	at org.netbeans.modules.parsing.api.Source.assignListeners(Source.java:390)
	at org.netbeans.modules.parsing.api.Source.access$500(Source.java:99)
	at org.netbeans.modules.parsing.api.Source$MySourceAccessor.assignListeners(Source.java:490)
	at org.netbeans.modules.parsing.impl.TaskProcessor.handleAddRequests(TaskProcessor.java:491)
	at org.netbeans.modules.parsing.impl.TaskProcessor.addPhaseCompletionTasks(TaskProcessor.java:308)
	at org.netbeans.modules.parsing.impl.TaskProcessor.addPhaseCompletionTasks(TaskProcessor.java:280)
	at org.netbeans.modules.parsing.impl.Utilities.addParserResultTask(Utilities.java:121)
	at org.netbeans.modules.java.source.JavaSourceAccessor.addPhaseCompletionTask(JavaSourceAccessor.java:174)
	at org.netbeans.api.java.source.JavaSourceTaskFactory$3.addPhaseCompletionTask(JavaSourceTaskFactory.java:247)
	at org.netbeans.api.java.source.JavaSourceTaskFactory.stateChangedImpl(JavaSourceTaskFactory.java:202)
	at org.netbeans.api.java.source.JavaSourceTaskFactory.access$000(JavaSourceTaskFactory.java:80)
	at org.netbeans.api.java.source.JavaSourceTaskFactory$1.run(JavaSourceTaskFactory.java:141)
	at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:573)
	at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:1005)
"Document Processing":
	at org.netbeans.modules.parsing.api.Source._getDocument(Source.java:356)
	- waiting to lock <0x67ea9128> (a org.netbeans.modules.parsing.api.Source)
	at org.netbeans.modules.parsing.api.Source.getDocument(Source.java:221)
	at org.netbeans.modules.parsing.impl.event.EventSupport$DocListener.propertyChange(EventSupport.java:205)
	at org.openide.util.WeakListenerImpl$PropertyChange.propertyChange(WeakListenerImpl.java:186)
	at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:339)
	at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:276)
	at org.openide.text.CloneableEditorSupport.firePropertyChange(CloneableEditorSupport.java:496)
	at org.openide.text.CloneableEditorSupport.fireDocumentChange(CloneableEditorSupport.java:2204)
	at org.openide.text.CloneableEditorSupport.access$1300(CloneableEditorSupport.java:120)
	at org.openide.text.CloneableEditorSupport$2.doRun(CloneableEditorSupport.java:653)
	- locked <0x67e970d8> (a org.openide.windows.CloneableOpenSupport$Listener)
	at org.openide.text.CloneableEditorSupport$2.run(CloneableEditorSupport.java:621)
	at org.netbeans.editor.GuardedDocument.runAtomic(GuardedDocument.java:324)
	at org.openide.text.NbDocument.runAtomic(NbDocument.java:384)
	at org.openide.text.CloneableEditorSupport$2.doRun(CloneableEditorSupport.java:631)
	at org.openide.text.CloneableEditorSupport$2.run(CloneableEditorSupport.java:621)
	at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:573)
	at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:1005)
Comment 1 Vitezslav Stejskal 2009-01-08 09:35:53 UTC
> 090105; IDE froze opening a source file. Bug seems to be in EventSupport$DocListener.propertyChange - you are not
> permitted to acquire a lock in a listener callback.

Well, I thought that listener callbacks are not supposed to be called when the caller holds a lock. I don't see anything
in javadoc for EditorCookie.Observable.add{remove}PCL saying that added listeners will be called when an internal lock
in CloneableEditorSupport is held.

I know CES contains complex code for loading documents and maybe there is a good reason for doing things the way how
they are done now. But it definitely is not a common practice and should be mentioned in javadoc.
Comment 2 Vitezslav Stejskal 2009-01-08 09:40:43 UTC
*** Issue 156461 has been marked as a duplicate of this issue. ***
Comment 3 Vitezslav Stejskal 2009-01-08 09:41:08 UTC
*** Issue 156340 has been marked as a duplicate of this issue. ***
Comment 4 mslama 2009-01-08 10:47:54 UTC
I am just moving firing change document event out of CES internal lock. This should fix this issue. See issue #155326.
Comment 5 Vitezslav Stejskal 2009-01-08 11:21:00 UTC
Thanks a lot Marku. I'll leave this open until we are sure that your change fixed the problem.
Comment 6 Jesse Glick 2009-01-08 17:06:53 UTC
"listener callbacks are not supposed to be called when the caller holds a lock" - unfortunately this is not avoidable in
general, assuming you want to fire events synchronously, which is generally desirable (makes behavior more predictable
and testable).

"I don't see anything in Javadoc for [...].addPCL saying that added listeners will be called when an internal lock [...]
is held" - the onus is not on the event source. The onus is on listeners to not acquire their own locks. This is a
general fact for any listener so it need not be specifically mentioned in Javadoc.
Comment 7 Vitezslav Stejskal 2009-01-12 11:20:52 UTC
> The onus is on listeners to not acquire their own locks. This is a general fact for any listener so it need not
> be specifically mentioned in Javadoc.

Are you sure Jesse? This is in contrast with how I believe we have been approaching these problems in Netbeans so far.
Anyway, Marek changed CloneableOpenSupport not to call listeners when holding the lock, which I think fixed this problem.
Comment 8 Jesse Glick 2009-01-12 22:16:25 UTC
"this is in contrast with how I believe we have been approaching these problems in NetBeans so far" - I can't track
every deadlock reported & solved in NB, but my general advice is that a listener should never acquire a lock or perform
other potentially blocking actions. There are many cases where listeners must be notified and calling code is holding a
lock, where moving the notification out of the lock would not be practical.
Comment 9 mslama 2009-01-13 08:45:07 UTC
Yes it is not always possible to move event firing out of lock especially when code spans over multiple modules. Example
is issue #155680 where call of DataEditorSupport.Env.getTime() -> FileObject.refresh can cause fileChange event from fs.
But I cannot call getTime() later so I had to workaround this by another way. In this case this fileChange event can be
ignore. It is just to show that it is not always possible to move event firing out of lock.
Comment 10 Vitezslav Stejskal 2009-01-19 12:09:40 UTC
*** Issue 156995 has been marked as a duplicate of this issue. ***
Comment 11 Vitezslav Stejskal 2009-02-02 11:52:13 UTC
This seems to be really fixed. Thanks Marku.