NativeEventThread's run() method's infinite loop was implemented. The
loop looks like this:
while (null != this.browserControlCanvas) {
synchronized (this.browserControlCanvas.getTreeLock()) {
nativeProcessEvents(nativeWebShell);
if (null != listenersToAdd && !listenersToAdd.isEmpty()) {
tempEnum = listenersToAdd.elements();
while (tempEnum.hasMoreElements()) {
nativeAddListener(nativeWebShell,
(WebclientEventListener)
tempEnum.nextElement());
}
listenersToAdd.clear();
}
}
}
The problem I was observing was that
nativeProcessEvents(nativeWebShell) would crash due to the fact that
the nativeWebShell, which is actually an WebShellInitContext instance,
had been de-allocated. This de-allocation happens as a result of the
WindowControlImpl.delete() method, which looks like this:
public void delete()
{
Assert.assert(null != eventThread, "eventThread shouldn't be null at delete time");
eventThread.delete();
eventThread = null;
nativeDestroyInitContext(nativeWebShell);
nativeWebShell = -1;
}
nativeDestroyInitContext de-allocates the WebShellInitContextInstance.
You can see that the first thing done is to delete the eventThread().
NativeEventThread.delete() looks like this:
public void delete()
{
// setting this to null causes the run thread to exit
synchronized(this.browserControlCanvas.getTreeLock()) {
browserControlCanvas = null;
}
...
}
If you compare NativeEventThread.delete() with the infinite loop in
NativeEventThread.run(), you'll see that the fact that they both
synchronize on the same object doesn't protect us from the following
case:
NativeEventThread: The infinite loop checks to see if the
browserControlCanvas is null, then does synchronize on
browserControlCanvas.getTreeLock(), then calls processNativeEvents().
meanwhile
WindowControlImpl thread: delete() calls NativeEventThread.delete(),
which does synchronize on browserControlCanvas.getTreeLock().
During NativeEventThread.delete(), synchronized section,
browserControlCanvas is set to null.
NativeEventThread: because the check for null browserControlCanvas
occurrs outside of the synchronized block, it's not recheked, and
thus, the event loop continues to process when it shouldn't.
The fix is to change the event loop to look like this:
while (true) {
synchronized (this.browserControlCanvas.getTreeLock()) {
// this has to be inside the synchronized block!
if (null == this.browserControlCanvas) {
return;
}
nativeProcessEvents(nativeWebShell);
if (null != listenersToAdd && !listenersToAdd.isEmpty()) {
tempEnum = listenersToAdd.elements();
while (tempEnum.hasMoreElements()) {
nativeAddListener(nativeWebShell,
(WebclientEventListener)
tempEnum.nextElement());
}
listenersToAdd.clear();
}
}
}
a couple weeks and just hadn't gotten around to checking it in yet.
I noticed that during a normal sending of a message, we were loading a string bundle 6 times! (most of this was to display
progress information during the send procedure). This caused us to hit the disk 6 times. With these changes, we
cache the string bundle in the compose string bundle service so we only hit the disk once.
nsIWebProgressListener.
Right now, the only methods that are hooked up are signaling when the doc loader is busy loading a document and
when it is done loading a document.
we override it in news, and we'll use this as our hook to update the counts for all the
newsgroups for a give server. right now, PerformExpand() only gets called on a double
click but eventually, it will be hooked up to the twisty. r=bienvenu