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 20874 - Racecondition - results in two debugger windows!
Summary: Racecondition - results in two debugger windows!
Status: CLOSED FIXED
Alias: None
Product: debugger
Classification: Unclassified
Component: Code (show other bugs)
Version: 3.x
Hardware: Sun Solaris
: P2 blocker (vote)
Assignee: Jan Jancura
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2002-02-26 00:17 UTC by Torbjorn Norbye
Modified: 2003-06-30 17:31 UTC (History)
2 users (show)

See Also:
Issue Type: DEFECT
Exception Reporter:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Torbjorn Norbye 2002-02-26 00:17:09 UTC
I've encountered a problem where the debugging window shows up -twice-
on the debugging workspace.  The other day I thought I had identified
it as a problem between DebuggerWindowPerformer and DebuggerViewAction.

But, even after working around that problem I have reproduced the bug.
Luckily, this time I had inserted Thread.dumpStack in DebuggerWindow's
constructor, so now I can see what the problem is.

Here's what happens. The debugger starter action switches to the
debugging workspace (by calling DebuggerModule.changeWorkspace) and then
starts EnterpriseDebugger.startDebugger. This calls my start debugger, and I call DebuggerWindowPerformer.getDebuggerWindow()
to obtain a reference to the debugger window. This causes the debugger
window to be created.   So far so good.

But then shortly thereafter, some window system code kicks in which
ALSO creates the debugger window, through reflection (see below stacktrace),
presumably from saved window settings or window system XML files defining
the debugger window.  I'm guessing this is happening because changeWorkspace() call, including all window restoration, has not completed
when changeWorkspace() returns, so my startDebugger code is running
before the window system is done.

Since the window system code is just calling newInstance, it does not
use the already-created debugger window that DebuggerWindowPerformer
knows about!

The end result is that the user sits with two debugger windows on the
desktop.

I think I can work around this by moving my
   DebuggerWindowPerfomer.getDebuggerWindow
call out to a later point. But the problem is - I don't know how long I
have to wait before it is safe.  Also, by moving this code out I may 
introduce new bugs.  (I'm adding component listeners to the debugging
window to be able to catch window exposure events for the views contained
inside the debugger window.)

I wasn't sure if this was a debuggercore bug or a window system bug,
but I'll start with the debuggercore category since I haven't seen this
problem in other areas. Is there some way to "wait" (kind of like a
SwingUtilities.invokeAndWait()) for the window system to complete the
workspace switch before resuming with my startDebugger code?

Here is the stack trace.

java.lang.Exception: Stack trace
	at java.lang.Thread.dumpStack(Thread.java:1071)
	at org.netbeans.modules.debugger.support.nodes.DebuggerWindow.<init>(DebuggerWindow.java:115)
	at org.netbeans.modules.debugger.support.actions.DebuggerWindowPerformer.getDebuggerWindow(DebuggerWindowPerformer.java:62)
	at com.sun.forte.st.ipe.debugger.IpeDebugger.startDebugger(IpeDebugger.java:589)
	at org.netbeans.modules.debugger.multisession.EnterpriseDebugger.startSession(EnterpriseDebugger.java:406)
	at org.netbeans.modules.debugger.multisession.EnterpriseDebugger.startDebugger(EnterpriseDebugger.java:202)
	at com.sun.forte.st.ipe.debugger.AttachProcessDialog.doAttach(AttachProcessDialog.java:209)
	at com.sun.forte.st.ipe.debugger.AttachProcessDialog.showWindow(AttachProcessDialog.java:437)
	at com.sun.forte.st.ipe.debugger.actions.AttachToProcessAction.performAction(AttachToProcessAction.java:46)
	at org.openide.util.actions.CallableSystemAction.actionPerformed(CallableSystemAction.java:69)
	at org.netbeans.core.ModuleActions$1.run(ModuleActions.java:105)
	at org.openide.util.Task.run(Task.java:152)
	at org.openide.util.RequestProcessor$ProcessorThread.run(RequestProcessor.java:622)



java.lang.Exception: Stack trace
	at java.lang.Thread.dumpStack(Thread.java:1071)
	at org.netbeans.modules.debugger.support.nodes.DebuggerWindow.<init>(DebuggerWindow.java:115)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:274)
	at java.lang.Class.newInstance0(Class.java:296)
	at java.lang.Class.newInstance(Class.java:249)
	at org.openide.loaders.XMLSettingsSupport$SettingsRecognizer.instanceCreate(XMLSettingsSupport.java:455)
	at org.openide.loaders.InstanceDataObject$SettingsInstance.instanceCreate(InstanceDataObject.java:1215)
	at org.netbeans.core.windows.PersistenceManager.lookupTCInstance(PersistenceManager.java:350)
	at org.netbeans.core.windows.WindowManagerImpl.lookupTCInstance(WindowManagerImpl.java:877)
	at org.netbeans.core.windows.layers.TCRefImpl.getTopComponent(TCRefImpl.java:357)
	at org.netbeans.core.windows.layers.TCRefImpl.updateMode(TCRefImpl.java:198)
	at org.netbeans.core.windows.layers.ModeData$CookiesImpl.addComponents(ModeData.java:764)
	at org.netbeans.core.windows.layers.ModeData$CookiesImpl.updateComponents(ModeData.java:629)
	at org.netbeans.core.windows.layers.ModeData$CookiesImpl.loadDataSection(ModeData.java:1090)
	at org.netbeans.core.windows.layers.ModeData$CookiesImpl.updateProperties(ModeData.java:487)
	at org.netbeans.core.windows.layers.ModeData$CookiesImpl.updateAll(ModeData.java:397)
	at org.netbeans.core.windows.layers.ModeData$CookiesImpl.createInstance(ModeData.java:341)
	at org.netbeans.core.windows.layers.ICFolderImpl$R.run(ICFolderImpl.java:261)
	at org.netbeans.core.windows.layers.ICFolderImpl.instanceCreate(ICFolderImpl.java:123)
	at org.netbeans.core.windows.layers.WorkspaceData$InstanceCookieImpl.createModes(WorkspaceData.java:470)
	at org.netbeans.core.windows.layers.WorkspaceData$InstanceCookieImpl.updateModes(WorkspaceData.java:407)
	at org.netbeans.core.windows.layers.WorkspaceData$InstanceCookieImpl.updateAll(WorkspaceData.java:342)
	at org.netbeans.core.windows.layers.WorkspaceData$InstanceCookieImpl.loadDataSection(WorkspaceData.java:667)
	at org.netbeans.core.windows.WorkspaceImpl.ensureSectionLoaded(WorkspaceImpl.java:958)
	at org.netbeans.core.windows.WorkspaceImpl.setVisible(WorkspaceImpl.java:687)
	at org.netbeans.core.windows.WindowManagerImpl$1.run(WindowManagerImpl.java:431)
	at org.netbeans.core.windows.WindowManagerImpl.setCurrentWorkspace(WindowManagerImpl.java:392)
	at org.netbeans.core.windows.WorkspaceImpl$1.run(WorkspaceImpl.java:468)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:178)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:443)
	at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:190)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:144)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:130)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:98)

(If you need to look at some of the involved source files that are
not in NetBeans, the ifdef source files are part of the forte for java
closed source repository if you can get to that. If not let me know
and I'll send them to you.)
Comment 1 Torbjorn Norbye 2002-02-26 00:21:13 UTC
This was using the orion_ea branch (which I think is tied closely
to release33), with JDK 1.4 - FCS on Solaris 8.

I'm hoping this can be addressed in 3.3.2. The duplicate debugging
window is a serious problem for our users because some windows
docked in it are inherently singletons (e.g. the terminal emulators
to the slave processes, dbx and the user's program) so one window
does not work and if the user is trying to use the "wrong" window
the product seems completely broken.
Comment 2 Torbjorn Norbye 2002-02-26 03:00:00 UTC
One additional note that might be interesting to note:
  the initial startDebugger is running on the thread
"org.netbeans.core.ModuleActions-1", and the second
call (the window system reflection) is on "AWT-EventQueue-0".
Comment 3 Jan Jancura 2002-02-28 16:00:36 UTC
Looks like really serious problem. Our Debugger Window is definitely
not a singleton. We have special instance for each workspace - at
least. And for a future we would like to have more "Debugger Window"
like component on one workspace too. I think you wanted something like
this too.

So, you will have probably the same problem, when somebody will open
DW on some nonDebugger workspace :(( 

So what can we do. If you want to force to deserialize Debugger Window
before you switch to debuger workspace, you can ask WindowManager for
all debugger workspace, and d.workspace for "debugger" mode, and
debugger mode for all TopComponents. It should fix your problem.

But if you really want to have only one instance of some view, you
should create some wrapper component. So you will have one wrapper
component for each workspace, you will listen on current one and move
your one inner component to it.

Hanz
Comment 4 Torbjorn Norbye 2002-03-08 22:22:48 UTC
I think the problem is something else.  I've earlier identified
that DebuggerWindowPerformer and DebuggerViewAction can get
"out of sync"; DebuggerWindowPerformer is supposed to enforce that
only a single debugger window exists -per workspace-, but 
DebuggerViewAction can violate that.

Today I was able to reproduce the problem again, and this time
it's a slightly different flavor.    Luckily, I still had my
"Thread.dumpStack" and "Thread.currentThread().getName()" output
calls in the DebuggerWindow's constructor, so I could see the order
and why two debugger windows were created on the same workspace.

FIRST, the window system deserializes the saved window state,
which in turn results in a DebuggerWindow getting created, on
the AWT thread.  This is all correct.

But THEN, DebuggerWindowPerformer gets called. It checks its
map to see if there is a DebuggerWindow stored for the current
workspace, and since there isn't, it too creates a new window!!!

(I'll show the two stack traces below).

The problem is that DebuggerWindowPerformer does not know about
the DebuggerWindow which is created by the window system 
deserialization!

I see a couple of different possible solutions here:
(1) Instead of DebuggerWindowPerformer.getDebuggerWindow
    having its own record of debugger windows, just
    look it up from the window system each time
    (workspace -> findMode -> getTopComponents)

(2) (better) Like the code works today, but in the case
    where you get null back from the debuggerWindow
    HashMap, THEN go look in the window system to see
    if the window exists.

(3) In the DebuggerWindow class itself, update the
    DebuggerWindowPerformer hashmap every time a new
    debugger window is created. 

Here's a patch to DebuggerWindowPerformer which implements
solution #2:

--- DebuggerWindowPerformer.java        4 Jan 2002 13:53:22 -0000    
  1.9.2.3
+++ DebuggerWindowPerformer.java        8 Mar 2002 22:18:34 -0000
@@ -59,6 +59,23 @@
         
         DebuggerWindow dw = (DebuggerWindow) debuggerWindow.get (w);
         if (dw == null) {
+           // Let's make doubly sure that the window has NOT been
created.
+           Workspace ws = TopManager.getDefault().getWindowManager().
+               getCurrentWorkspace();
+           org.openide.windows.Mode mode =
+               ws.findMode("debugger"); // NOI18N - from debugger.wsmode
+           if (mode != null) {
+               TopComponent[] tcs = mode.getTopComponents();
+               for (int i = 0; i < tcs.length; i++) {
+                   if (tcs[i] instanceof DebuggerWindow) {
+                       // Yes, window already exists on workspace!
+                       DebuggerWindow dw = (DebuggerWindow)tcs[i];
+                       debuggerWindow.put (w, dw);
+                       return dw;
+                   }
+               }
+           }
+           
             dw = new DebuggerWindow ();
             debuggerWindow.put (w, dw);
             //S ystem.out.println
("DebuggerWindowPerformer.getDebuggerWindow (new DW created) return: "
+ dw.hashCode () + " :for " + w);



Here are the trace messages when the problem manifested itself
on my system:

Name of executing thread is AWT-EventQueue-0
java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Thread.java:1071)
    at
org.netbeans.modules.debugger.support.nodes.DebuggerWindow.<init>(DebuggerWindow.java:117)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native
Method)
    at
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:274)
    at
org.openide.windows.TopComponent$Replacer.readObject(TopComponent.java:757)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:324)
    at
java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:809)
    at
java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1733)
    at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1636)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1264)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:322)
    at
org.openide.loaders.XMLSettingsSupport$SettingsRecognizer.readSerial(XMLSettingsSupport.java:400)
    at
org.openide.loaders.XMLSettingsSupport$SettingsRecognizer.instanceCreate(XMLSettingsSupport.java:430)
    at
org.openide.loaders.InstanceDataObject$SettingsInstance.instanceCreate(InstanceDataObject.java:1215)
    at
org.netbeans.core.windows.PersistenceManager.lookupTCInstance(PersistenceManager.java:350)
    at
org.netbeans.core.windows.WindowManagerImpl.lookupTCInstance(WindowManagerImpl.java:877)
    at
org.netbeans.core.windows.layers.TCRefImpl.getTopComponent(TCRefImpl.java:357)
    at
org.netbeans.core.windows.layers.TCRefImpl.updateMode(TCRefImpl.java:198)
    at
org.netbeans.core.windows.layers.ModeData$CookiesImpl.addComponents(ModeData.java:764)
    at
org.netbeans.core.windows.layers.ModeData$CookiesImpl.updateComponents(ModeData.java:629)
    at
org.netbeans.core.windows.layers.ModeData$CookiesImpl.updateAll(ModeData.java:401)
    at
org.netbeans.core.windows.layers.ModeData$CookiesImpl.loadDataSection(ModeData.java:1067)
    at
org.netbeans.core.windows.ModeImpl.ensureSectionLoaded(ModeImpl.java:2099)
    at
org.netbeans.core.windows.ModeImpl.doGetTopComponents(ModeImpl.java:779)
    at
org.netbeans.core.windows.ModeImpl.getTopComponents(ModeImpl.java:766)
    at
org.netbeans.core.windows.WorkspaceImpl.findMode(WorkspaceImpl.java:571)
    at
org.openide.text.CloneableEditor.openOnOtherWorkspaces(CloneableEditor.java:724)
    at org.openide.text.CloneableEditor.open(CloneableEditor.java:279)
    at org.openide.windows.TopComponent.open(TopComponent.java:199)
    at
org.openide.windows.CloneableOpenSupport.openCloneableTopComponent(CloneableOpenSupport.java:159)
    at
org.openide.windows.CloneableOpenSupport$1.run(CloneableOpenSupport.java:67)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:178)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:443)
    at
java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:190)
    at
java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:144)
    at
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:130)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:98)



Name of executing thread is AWT-EventQueue-0
java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Thread.java:1071)
    at
org.netbeans.modules.debugger.support.nodes.DebuggerWindow.<init>(DebuggerWindow.java:117)
    at
org.netbeans.modules.debugger.support.actions.DebuggerWindowPerformer.getDebuggerWindow(DebuggerWindowPerformer.java:62)
    at
com.sun.forte.st.ipe.debugger.IpeDebugger.continueStartup(IpeDebugger.java:672)
    at
com.sun.forte.st.ipe.debugger.IpeDebugger$2.run(IpeDebugger.java:657)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:178)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:443)
    at
java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:190)
    at
java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:144)
    at
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:130)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:98)

Comment 5 Torbjorn Norbye 2002-03-08 22:38:48 UTC
P.S. Line 72 of DebuggerWindowPerformer.java (-after- applying the
patch) should begin "dw =", not "DebuggerWindow dw =". Sorry.
Comment 6 Torbjorn Norbye 2002-03-22 18:15:30 UTC
Can this be fixed for 3.3.2? The bug is causing lots of problems
in Orion EE. At JavaOne next week the demo people have been taught
to restart the IDE repeatedly until the race condition does not
manifest itself. This is obviously not a good situation :-)

I believe my suggested fix above works, and that it additionally
adds no risk to your debugger - it simply enforces something the
code already assumes to be true (which I've observed is not always
true, and in that case it takes corrective action; it makes sure
there is only one debugger window on a particular workspace.)
Comment 7 Jan Jancura 2002-04-04 15:39:57 UTC
fixed in main trunk and orion_fcs
Comment 8 Marek Grummich 2003-01-13 09:39:28 UTC
Verified.
Comment 9 Quality Engineering 2003-06-30 17:31:49 UTC
Resolved for 3.3.x or earlier, no new info since then -> closing.