>> In bug 1218297 we saw a case where dispatch to a thread (the socket
>> transport service thread in this case) fails because the thread has
>> already shut down. In our brave new world, nsThread simply leaks the
>> runnable. It can't release the reference it holds, because that would
>> reintroduce the race condition we wanted to avoid, and it can't
>> release the reference on the correct thread so it's already gone away.
>>
>
>I am a bit confused with this, if the executing thread has already shut
>down, why would releasing the reference dispatching thread holds
>reintroduce the race condition? Who is racing with dispatching thread?
It doesn't re-introduce a race. What it may do is cause the same effect
as a lost race, whereby an object meant to be released on the target
thread gets released on the sending thread. If the object is a
non-threadsafe object (say, for example, a JS success or failure
callback object), then releasing it on the sending thread is Bad. This
is the same thing that can happen in a race where you have:
What used to happen:
{
RefPtr<Foo> bar = new FooRunnable(nonthreadsafe_object);
target_thread->Dispatch(bar, ...);
// Note: Dispatch in this (old-style) case takes a new reference to
// bar. And the runnable may run and release that reference before
// Dispatch() returns! And if Dispatch() fails, you always 'lose'
// the race.
}
// bar drops the reference. If the runnable ran already, this is
// the last reference and it gets destroyed here. If it hasn't run,
// it gets destroyed on the target thread.
New way (already_AddRefed<>):
{
RefPtr<Foo> bar = new FooRunnable(nonthreadsafe_object);
target_thread->Dispatch(bar.forget(), ...);
// bar is always destroyed on the target thread - unless
// Dispatch() fails, in which case it leaks (for safety).
}
or:
other_thread->Dispatch(do_AddRef(new FooRunnable(nonthreadsafe_object)),
...);
If you use the old-style (raw ptr Dispatch) as a lot of the tree still
does, it will now leak on Dispatch() failure instead of possibly
wrong-thread releasing:
nsThread.h:
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
Since Dispatch(already_AddRefed<>,...) leaks on failure, this means that
Dispatch(raw_ptr,...) now leaks on failure (which is what engendered
this discussion). You can override this behavior with a check of the
result of Dispatch() and a manual Release if it fails (and you know
the object is entirely threadsafe).
We could add DispatchFallible() (DispatchNeverLeaks()?) if that's a
wide-enough pattern; part of my question in that case is "did the caller
really expect Dispatch to possibly fail, and what implications does such
a failure have to the rest of the system?"
--
Randell Jesup, Mozilla Corp
remove "news" for personal email
_______________________________________________
dev-platform mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-platform