Open Bug 901759 Opened 11 years ago Updated 2 months ago

Add nsIMessageManager::{Add,Remove}WeakMessageListener based on mozilla:MaybeWeakSet (bug 901746)

Categories

(Core :: General, defect)

defect

Tracking

()

People

(Reporter: justin.lebar+bug, Unassigned)

References

(Depends on 1 open bug)

Details

(Whiteboard: [MemShrink:P2])

Attachments

(1 file, 3 obsolete files)

I have patches which allow nsIMessageManager to add weak message listeners.

These patches also convert nsIMessageManager's strong message listeners to use a hashtable of lists, instead of a plain list.  This makes the strong message listeners perform more similarly to weak message listeners (which are implemented as a hashtable of hashsets).  If you like, I'd be happy to make regular message listeners be a hashtable of hashsets; I didn't do this because I was a bit worried about memory waste when we have many hashtables with just one or two elements.

smaug, I know you didn't really like this the last time we talked about it.  We /can/ do without this patch; I'm adding finalizers to weakrefs, so an object could implement a weak message listener itself.  But this is /much/ simpler for users of the API.

We've seen a lot of leaks stemming from message listeners, and based on the experience of finding and fixing those leaks, I think this is a good idea.
Attached patch Patch, v1 (obsolete) — Splinter Review
Attachment #786029 - Flags: review?(bugs)
Whiteboard: [MemShrink]
Comment on attachment 786029 [details] [diff] [review]
Patch, v1

Please document that weak listeners are called in random order!

>+  nsTArray<nsCOMPtr<nsIMessageListener> >* listeners = nullptr;
>+  if (!mStrongListeners.Get(aMessage, &listeners)) {
>+    mStrongListeners.Put(aMessage, new nsTArray<nsCOMPtr<nsIMessageListener> >());
>+    mStrongListeners.Get(aMessage, &listeners);
>+  }
Could you perhaps assign to listeners before Put, and put that value?
Then you wouldn't need to use Get


>+nsFrameMessageManager::AddWeakMessageListener(const nsAString& aMessage,
>+                                              nsIMessageListener* aListener)
>+{
>+  WeakSet<nsIMessageListener>* listeners = nullptr;
>+  mWeakListeners.Get(aMessage, &listeners);
>+  if (!listeners) {
>+    listeners = new WeakSet<nsIMessageListener>();
>+    mWeakListeners.Put(aMessage, listeners);
>+  }
>+
>+  // WeakSet::Add() returns false iff its arg can't be QI'ed to
>+  // nsISupportsWeakReference.
>+  if (!listeners->Add(aListener)) {
>+    return NS_ERROR_NO_INTERFACE;
>+  }
Could you even add a warning here, so that we see in the terminal that the call failed.


>+NS_IMETHODIMP
>+nsFrameMessageManager::RemoveWeakMessageListener(const nsAString& aMessage,
>+                                                 nsIMessageListener* aListener)
>+{
>+  WeakSet<nsIMessageListener>* listeners = nullptr;
>+  mWeakListeners.Get(aMessage, &listeners);
>+  if (!listeners) {
>+    return NS_OK;
>+  }
>+
>+  // WeakSet::Remove() returns false iff its arg can't be QI'ed to
>+  // nsISupportsWeakReference.
>+  if (!listeners->Remove(aListener)) {
>+    return NS_ERROR_NO_INTERFACE;
>+  }
And here too
>+  if (strongListeners) {
>+    for (uint32_t i = 0; i < strongListeners->Length(); i++) {
++i, please

>+      nsresult rv = DispatchMessage((*strongListeners)[i], aTarget, aMessage,
>+                                    aSync, aCloneData, aCpows, aJSONRetVal);
>+      NS_ENSURE_SUCCESS(rv, rv);
Hmm, should we actually just continue here. I think so.

>+    for (uint32_t i = 0; i < weakListeners.Length(); i++) {
>+      nsresult rv = DispatchMessage(weakListeners[i], aTarget, aMessage, aSync,
>+                                    aCloneData, aCpows, aJSONRetVal);
>+      NS_ENSURE_SUCCESS(rv, rv);
ditto


This should have at least some basic tests.
With that, r=me
Attachment #786029 - Flags: review?(bugs) → review+
Blocks: 900221
Attached patch Tests, v1 (obsolete) — Splinter Review
I tried writing a new test file and had a lot of difficulty getting it to work.  I hope you don't mind that I added it here; this looks like it's the test for the mm interface, anyway.
Attachment #786568 - Flags: review?(bugs)
> Hmm, should we actually just continue here. I think so.

Do you want me to make DispatchMessage return void, or should it continue to return nsresult?  If it continues to return nsresult, do you want to print a warning if the result indicates failure?
I think the right thing to do may be to have DispatchMessage return void but report its early returns with NS_ENSURE_TRUE_VOID() and so on.  This will let us see exactly which early return we took.
NS_ENSURE_TRUE_VOID() sounds good
Comment on attachment 786568 [details] [diff] [review]
Tests, v1

This is ok, but it would be nice to have a test which checks that the
weak listener, not owned by anyone, actually disappears at some point
(after gc+cc+gc?).
But if you add some similar kind of tests for the WeakSet, or WeakSet+ObserverService, this is enough.


(I want tests mainly to prevent regressions in the future.)
Attachment #786568 - Flags: review?(bugs) → review+
Whiteboard: [MemShrink] → [MemShrink:P2]
> But if you add some similar kind of tests for the WeakSet, or WeakSet+ObserverService, this is 
> enough.

This might be easier; I'll see.
Talking to bsmedberg (and hearing his issues with the patches in bug 901746) convinced me that we should try a simpler approach for b2g18.

I don't like this, because it's asymptotically extremely inefficient and doesn't prevent us from building a big array of nsWeakPtr's under some circumstances, so I really want to do what we have here.  But baby steps.
I'll file a new bug for the simpler, slower thing.
Summary: Add nsIMessageManager::{Add,Remove}WeakMessageListener → Add nsIMessageManager::{Add,Remove}WeakMessageListener based on mozilla:WeakSet (bug 901746)
No longer blocks: 900221
Summary: Add nsIMessageManager::{Add,Remove}WeakMessageListener based on mozilla:WeakSet (bug 901746) → Add nsIMessageManager::{Add,Remove}WeakMessageListener based on mozilla:MaybeWeakSet (bug 901746)
Attached patch Patch, v2Splinter Review
This is ready for review, but I want to get at least preliminary f+ on the patches this depends on before asking someone to look at it.

Tests have already landed.
Attachment #786029 - Attachment is obsolete: true
Attachment #786568 - Attachment is obsolete: true
This patch is nice because it's simpler than the old patch, and it also allows us to interleave strong and weak observers in our dispatch list.
Severity: normal → S3
Attachment #9385487 - Attachment is obsolete: true
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: