Closed Bug 279852 Opened 20 years ago Closed 20 years ago

nsWeakReference not threadsafe assertions due to TimerThread::Init


(Core :: XPCOM, defect)

Not set





(Reporter: dbaron, Assigned: darin.moz)


(Blocks 1 open bug)


(Whiteboard: [patch])


(1 file, 2 obsolete files)

In bug 234858, sicking made nsWeakReference use macros for its refcounting
rather than writing AddRef and Release by hand.  This caused some
nsWeakReference not threadsafe assertions.  The observers in question are
registered in TimerThread::Init on a non-main thread:

          observerService->AddObserver(this, "sleep_notification", PR_TRUE);
          observerService->AddObserver(this, "wake_notification", PR_TRUE);

at the stack:

TimerThread::Init() (/builds/trunk/mozilla/xpcom/threads/TimerThread.cpp:134)
nsTimerImpl::InitCommon(unsigned int, unsigned int)
nsTimerImpl::InitWithFuncCallback(void (*)(nsITimer*, void*), void*, unsigned
int, unsigned int) (/builds/trunk/mozilla/xpcom/threads/nsTimerImpl.cpp:253)
NS_NewTimer(nsITimer**, void (*)(nsITimer*, void*), void*, unsigned int,
unsigned int) (/builds/trunk/mozilla/xpcom/threads/nsTimerImpl.cpp:633)
nsRecyclingAllocator::Malloc(unsigned int, int)
nsRecyclingAllocatorImpl::Alloc(unsigned int)
nsPipe::GetWriteSegment(char*&, unsigned int&)
nsPipeOutputStream::WriteSegments(unsigned int (*)(nsIOutputStream*, void*,
char*, unsigned int, unsigned int, unsigned int*), void*, unsigned int, unsigned
int*) (/builds/trunk/mozilla/xpcom/io/nsPipe3.cpp:1071)
nsStreamCopierOB::DoCopy(unsigned int*, unsigned int*)
nsAStreamCopier::Process() (/builds/trunk/mozilla/xpcom/io/nsStreamUtils.cpp:320)
PL_HandleEvent (/builds/trunk/mozilla/xpcom/threads/plevent.c:698)
_pt_root (/builds/trunk/mozilla/nsprpub/pr/src/pthreads/ptthread.c:217)

I don't think *all* weak references should have to use threadsafe refcounting. 
It shouldn't be hard to make a subclass that did (nsMTWeakReference).  That
said, there may be other problems with using the observer service like this
Attached patch work in progress (obsolete) — Splinter Review
Actually, it's not so trivial, but this is partway there. 
nsSupportsThreadsafeWeakReference still needs a bit more work to be threadsafe.
 And I'm not crazy about the names.
Attached patch patch (insufficient) (obsolete) — Splinter Review
I think this should work, but I haven't thought it through too carefully.

It would be nice to be able to do this with atomic operations rather than
wasting space on a lock, though.  I'm not sure whether that's possible, though.
Assignee: dougt → dbaron
Attachment #172414 - Attachment is obsolete: true
Blocks: 279923
Comment on attachment 172416 [details] [diff] [review]
patch (insufficient)

>+  {
>+    mLock = PR_NewLock();
>+  }
>+  {
>+    PR_DestroyLock(mLock);
>+  }

you need to handle PR_NewLock failing.
Why does TimerThread need to implement nsISupportsWeakReference?  It seems to me
that it has to do with the AddObserver calls, but I don't understand why those
need to be weak references.  The RemoveObserver calls happen in the
TimerThread's destructor, and the TimerThread is meant to stick around for the
lifetime of the application, so it would seem to me that we could make those be
strong references and then just not bother calling RemoveObserver.  That would
mean that the observer service would keep the TimerThread object around for the
lifetime of the XPCOM session (i.e., until the observer service is shutdown). 
We use the same technique for other observers that need to stick around for the
entire XPCOM session.  So, perhaps that would be an alternative (and simpler)
solution here?

One more thing: the nsIObserverService has very ill-defined behavior in the
multithreaded use case.  it is troubling to me that this code is attempting to
use nsIObserverService across threads.
I was thinking it might be better to just copy & paste both classes instead of
using inheritance (the only extra codesize would be the copied QueryReferent
implementation, which is small) to save the virtual function call and make
things a little cleaner.

However, there are still some problems.  This patch doesn't handle the case of
QueryReferent on one thread racing with the destructor of
nsSupportsWeakReference on another thread, and I'm not sure how to handle that.
 In particular, the ~nsSupportsWeakReference happens well into the destruction
process of the object that inherits from it, and we really need QueryReferent
not to work much sooner.  If we didn't have (or need) refcount stabilization
we'd be able to detect this case by calling AddRef and Release on mReferent in
QueryReferent and looking at the return values, but we do.
Assignee: dbaron → dougt
another issue based on the stack trace in comment #0:

it looks like the recycling allocator is trying to create a timer on a thread
that does not have a nsIEventQueue associated with it.  that means that the
timer would never fire.  it's not a major bug since we use the cached i/o
buffers frequently, and the pool size is relatively small, but nonetheless it
seems like a bug we ought to fix.

long term i think we should have a way to associate a nsIEventTarget with the
current thread and have an API to expose it.  since the i/o threads do implement
nsIEventTarget and Timers only use the nsIEventTarget portion of nsIEventQueue,
this would be fairly trivial to fix.

there may be value in a threadsafe weakreference implementation, but it sounds
like a complicated thing to implement, and until we have a real consumer, i
think we should just take the short path to solving this bug.
Attachment #172416 - Attachment description: patch → patch (insufficient)
Attachment #172416 - Attachment is obsolete: true
fwiw, i'm fairly certain i'm such a customer. i have code which runs on threads
and might want to be a weak reference to either prefservice or observerservice.
but i'm in no hurry (it's not like xpcom or xpconnect are really threadsafe atm).
this affects imap as well, whenever a connection is closed...
The TimerThread::Init observer service usage was introduced by 197863.
The TimerThread::Init case should be fairly easy to fix by moving the
AddObserver calls to the main thread.
I'm testing a patch for this.
Assignee: dougt → darin
Target Milestone: --- → mozilla1.8beta2
Attached patch v1 patchSplinter Review
dbaron is away on vacation, or otherwise i would ask him for review on this. 
instead, i'll ask the folks who reviewed the patch i'm changing ;-)
Attachment #176961 - Flags: superreview?(bryner)
Attachment #176961 - Flags: review?(sfraser_bugs)
Attachment #176961 - Flags: superreview?(bryner) → superreview+
Comment on attachment 176961 [details] [diff] [review]
v1 patch

I'm a little worried that this might cause the TimerThread to be destroyed
later, therefore delaying the release of all the timers. Is this an issue?
It is not an issue.  If you read NS_ShutdownXPCOM you will see that
xpcom-shutdown happens before nsTimerImpl::Shutdown, which calls
TimerThread::Shutdown.  So, this should be ok :)
Comment on attachment 176961 [details] [diff] [review]
v1 patch

I'll take your word for it.
Attachment #176961 - Flags: review?(sfraser_bugs) → review+
Closed: 20 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.