Bug 1155059: Patch 1&2 - Convert Dispatch() and friends to already_AddRefed<> r=froydnj

Modify Dispatch IDL and code to deal with MSVC issues with overloaded templates r=froydnj
This commit is contained in:
Randell Jesup 2015-07-09 23:21:46 -04:00
parent 89e710906c
commit c87c478f4f
28 changed files with 358 additions and 145 deletions

View File

@ -77,6 +77,10 @@ public:
NS_DECL_NSIREQUEST
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIEVENTTARGET
// missing from NS_DECL_NSIEVENTTARGET because MSVC
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
explicit WebSocketImpl(WebSocket* aWebSocket)
: mWebSocket(aWebSocket)
@ -2582,7 +2586,7 @@ class WorkerRunnableDispatcher final : public WorkerRunnable
public:
WorkerRunnableDispatcher(WebSocketImpl* aImpl, WorkerPrivate* aWorkerPrivate,
nsIRunnable* aEvent)
already_AddRefed<nsIRunnable>&& aEvent)
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
, mWebSocketImpl(aImpl)
, mEvent(aEvent)
@ -2627,11 +2631,19 @@ private:
} // anonymous namespace
NS_IMETHODIMP
WebSocketImpl::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
WebSocketImpl::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
{
nsCOMPtr<nsIRunnable> event(aEvent);
return Dispatch(event.forget(), aFlags);
}
NS_IMETHODIMP
WebSocketImpl::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
{
nsCOMPtr<nsIRunnable> event_ref(aEvent);
// If the target is the main-thread we can just dispatch the runnable.
if (mIsMainThread) {
return NS_DispatchToMainThread(aEvent);
return NS_DispatchToMainThread(event_ref.forget());
}
MutexAutoLock lock(mMutex);
@ -2648,7 +2660,7 @@ WebSocketImpl::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
// If the target is a worker, we have to use a custom WorkerRunnableDispatcher
// runnable.
nsRefPtr<WorkerRunnableDispatcher> event =
new WorkerRunnableDispatcher(this, mWorkerPrivate, aEvent);
new WorkerRunnableDispatcher(this, mWorkerPrivate, event_ref.forget());
if (!event->Dispatch(nullptr)) {
return NS_ERROR_FAILURE;

View File

@ -647,19 +647,19 @@ void
MediaOperationTask::ReturnCallbackError(nsresult rv, const char* errorLog)
{
MM_LOG(("%s , rv=%d", errorLog, rv));
NS_DispatchToMainThread(new ReleaseMediaOperationResource(mStream.forget(),
mOnTracksAvailableCallback.forget()));
NS_DispatchToMainThread(do_AddRef(new ReleaseMediaOperationResource(mStream.forget(),
mOnTracksAvailableCallback.forget())));
nsString log;
log.AssignASCII(errorLog);
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess;
nsRefPtr<MediaMgrError> error = new MediaMgrError(
NS_LITERAL_STRING("InternalError"), log);
NS_DispatchToMainThread(
NS_DispatchToMainThread(do_AddRef(
new ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>(onSuccess,
mOnFailure,
*error,
mWindowID));
mWindowID)));
}
/**
@ -1067,9 +1067,9 @@ public:
MOZ_ASSERT(!mOnSuccess);
MOZ_ASSERT(!mOnFailure);
NS_DispatchToMainThread(runnable);
NS_DispatchToMainThread(runnable.forget());
// Do after ErrorCallbackRunnable Run()s, as it checks active window list
NS_DispatchToMainThread(new GetUserMediaListenerRemove(mWindowID, mListener));
NS_DispatchToMainThread(do_AddRef(new GetUserMediaListenerRemove(mWindowID, mListener)));
}
void
@ -1111,12 +1111,12 @@ public:
peerIdentity = new PeerIdentity(mConstraints.mPeerIdentity);
}
NS_DispatchToMainThread(new GetUserMediaStreamRunnable(
NS_DispatchToMainThread(do_AddRef(new GetUserMediaStreamRunnable(
mOnSuccess, mOnFailure, mWindowID, mListener,
(mAudioDevice? mAudioDevice->GetSource() : nullptr),
(mVideoDevice? mVideoDevice->GetSource() : nullptr),
peerIdentity
));
)));
MOZ_ASSERT(!mOnSuccess);
MOZ_ASSERT(!mOnFailure);
@ -1290,7 +1290,7 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId, MediaSourceEnum aVideoType
}
SourceSet* handoff = result.forget();
NS_DispatchToMainThread(NewRunnableFrom([id, handoff]() mutable {
NS_DispatchToMainThread(do_AddRef(NewRunnableFrom([id, handoff]() mutable {
ScopedDeletePtr<SourceSet> result(handoff); // grab result
nsRefPtr<MediaManager> mgr = MediaManager_GetInstance();
if (!mgr) {
@ -1301,7 +1301,7 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId, MediaSourceEnum aVideoType
p->Resolve(result.forget());
}
return NS_OK;
}));
})));
}));
return p.forget();
}
@ -2253,7 +2253,7 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
// must explicitly do this before dispatching the reply, since the reply may kill us with Stop()
mBackend = nullptr; // last reference, will invoke Shutdown() again
if (NS_FAILED(NS_DispatchToMainThread(mReply))) {
if (NS_FAILED(NS_DispatchToMainThread(mReply.forget()))) {
LOG(("Will leak thread: DispatchToMainthread of reply runnable failed in MediaManager shutdown"));
}
}
@ -2727,7 +2727,7 @@ GetUserMediaCallbackMediaStreamListener::NotifyFinished(MediaStreamGraph* aGraph
{
mFinished = true;
Invalidate(); // we know it's been activated
NS_DispatchToMainThread(new GetUserMediaListenerRemove(mWindowID, this));
NS_DispatchToMainThread(do_AddRef(new GetUserMediaListenerRemove(mWindowID, this)));
}
// Called from the MediaStreamGraph thread

View File

@ -45,7 +45,19 @@ public:
// Forward behaviour to wrapped thread pool implementation.
NS_FORWARD_SAFE_NSITHREADPOOL(mPool);
NS_FORWARD_SAFE_NSIEVENTTARGET(mEventTarget);
// See bug 1155059 - MSVC forces us to not declare Dispatch normally in idl
// NS_FORWARD_SAFE_NSIEVENTTARGET(mEventTarget);
nsresult Dispatch(nsIRunnable *event, uint32_t flags) { return !mEventTarget ? NS_ERROR_NULL_POINTER : mEventTarget->Dispatch(event, flags); }
NS_IMETHOD DispatchFromScript(nsIRunnable *event, uint32_t flags) override {
return Dispatch(event, flags);
}
NS_IMETHOD Dispatch(already_AddRefed<nsIRunnable>&& event, uint32_t flags) override
{ return !mEventTarget ? NS_ERROR_NULL_POINTER : mEventTarget->Dispatch(Move(event), flags); }
NS_IMETHOD IsOnCurrentThread(bool *_retval) override { return !mEventTarget ? NS_ERROR_NULL_POINTER : mEventTarget->IsOnCurrentThread(_retval); }
// Creates necessary statics. Called once at startup.
static void InitStatics();

View File

@ -1218,7 +1218,11 @@ Promise::MaybeReportRejected()
// will leak. See Bug 958684.
nsRefPtr<AsyncErrorReporter> r =
new AsyncErrorReporter(CycleCollectedJSRuntime::Get()->Runtime(), xpcReport);
NS_DispatchToMainThread(r);
nsRefPtr<AsyncErrorReporter> sacrifice = r;
// If this fails, we know NS_DispatchToMainThread leaked on purpose, and we don't want that
if (NS_FAILED(NS_DispatchToMainThread(sacrifice.forget()))) {
r->Release();
}
}
#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
@ -1635,7 +1639,7 @@ PromiseWorkerProxy::RunCallback(JSContext* aCx,
if (!runnable->Dispatch(aCx)) {
nsRefPtr<WorkerControlRunnable> runnable =
new PromiseWorkerProxyControlRunnable(mWorkerPrivate, this);
mWorkerPrivate->DispatchControlRunnable(runnable);
mWorkerPrivate->DispatchControlRunnable(runnable.forget());
}
}

View File

@ -1756,7 +1756,7 @@ RuntimeService::ScheduleWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
nsCOMPtr<nsIRunnable> runnable =
new WorkerThreadPrimaryRunnable(aWorkerPrivate, thread, JS_GetParentRuntime(aCx));
if (NS_FAILED(thread->DispatchPrimaryRunnable(friendKey, runnable))) {
if (NS_FAILED(thread->DispatchPrimaryRunnable(friendKey, runnable.forget()))) {
UnregisterWorker(aCx, aWorkerPrivate);
JS_ReportError(aCx, "Could not dispatch to thread!");
return false;

View File

@ -1838,7 +1838,14 @@ public:
protected:
NS_IMETHOD
Dispatch(nsIRunnable* aRunnable, uint32_t aFlags) override
DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) override
{
nsCOMPtr<nsIRunnable> runnable(aRunnable);
return Dispatch(runnable.forget(), aFlags);
}
NS_IMETHOD
Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags) override
{
// This should only happen on the timer thread.
MOZ_ASSERT(!NS_IsMainThread());
@ -1849,7 +1856,8 @@ protected:
// Run the runnable we're given now (should just call DummyCallback()),
// otherwise the timer thread will leak it... If we run this after
// dispatch running the event can race against resetting the timer.
aRunnable->Run();
nsCOMPtr<nsIRunnable> runnable(aRunnable);
runnable->Run();
// This can fail if we're racing to terminate or cancel, should be handled
// by the terminate or cancel code.
@ -2872,10 +2880,11 @@ WorkerPrivateParent<Derived>::WrapObject(JSContext* aCx, JS::Handle<JSObject*> a
template <class Derived>
nsresult
WorkerPrivateParent<Derived>::DispatchPrivate(WorkerRunnable* aRunnable,
WorkerPrivateParent<Derived>::DispatchPrivate(already_AddRefed<WorkerRunnable>&& aRunnable,
nsIEventTarget* aSyncLoopTarget)
{
// May be called on any thread!
nsRefPtr<WorkerRunnable> runnable(aRunnable);
WorkerPrivate* self = ParentAsWorkerPrivate();
@ -2886,7 +2895,7 @@ WorkerPrivateParent<Derived>::DispatchPrivate(WorkerRunnable* aRunnable,
if (!self->mThread) {
if (ParentStatus() == Pending || self->mStatus == Pending) {
mPreStartRunnables.AppendElement(aRunnable);
mPreStartRunnables.AppendElement(runnable);
return NS_OK;
}
@ -2904,9 +2913,9 @@ WorkerPrivateParent<Derived>::DispatchPrivate(WorkerRunnable* aRunnable,
nsresult rv;
if (aSyncLoopTarget) {
rv = aSyncLoopTarget->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
rv = aSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
} else {
rv = self->mThread->Dispatch(WorkerThreadFriendKey(), aRunnable);
rv = self->mThread->DispatchAnyThread(WorkerThreadFriendKey(), runnable.forget());
}
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -2956,13 +2965,11 @@ WorkerPrivateParent<Derived>::DisableDebugger()
template <class Derived>
nsresult
WorkerPrivateParent<Derived>::DispatchControlRunnable(
WorkerControlRunnable* aWorkerControlRunnable)
already_AddRefed<WorkerControlRunnable>&& aWorkerControlRunnable)
{
// May be called on any thread!
MOZ_ASSERT(aWorkerControlRunnable);
nsRefPtr<WorkerControlRunnable> runnable = aWorkerControlRunnable;
nsRefPtr<WorkerControlRunnable> runnable(aWorkerControlRunnable);
MOZ_ASSERT(runnable);
WorkerPrivate* self = ParentAsWorkerPrivate();
@ -2996,13 +3003,13 @@ WorkerPrivateParent<Derived>::DispatchControlRunnable(
template <class Derived>
nsresult
WorkerPrivateParent<Derived>::DispatchDebuggerRunnable(
WorkerRunnable *aDebuggerRunnable)
already_AddRefed<WorkerRunnable>&& aDebuggerRunnable)
{
// May be called on any thread!
MOZ_ASSERT(aDebuggerRunnable);
nsRefPtr<WorkerRunnable> runnable(aDebuggerRunnable);
nsRefPtr<WorkerRunnable> runnable = aDebuggerRunnable;
MOZ_ASSERT(runnable);
WorkerPrivate* self = ParentAsWorkerPrivate();
@ -3026,19 +3033,20 @@ WorkerPrivateParent<Derived>::DispatchDebuggerRunnable(
template <class Derived>
already_AddRefed<WorkerRunnable>
WorkerPrivateParent<Derived>::MaybeWrapAsWorkerRunnable(nsIRunnable* aRunnable)
WorkerPrivateParent<Derived>::MaybeWrapAsWorkerRunnable(already_AddRefed<nsIRunnable>&& aRunnable)
{
// May be called on any thread!
MOZ_ASSERT(aRunnable);
nsCOMPtr<nsIRunnable> runnable(aRunnable);
MOZ_ASSERT(runnable);
nsRefPtr<WorkerRunnable> workerRunnable =
WorkerRunnable::FromRunnable(aRunnable);
WorkerRunnable::FromRunnable(runnable);
if (workerRunnable) {
return workerRunnable.forget();
}
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(aRunnable);
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(runnable);
if (!cancelable) {
MOZ_CRASH("All runnables destined for a worker thread must be cancelable!");
}
@ -5447,7 +5455,7 @@ WorkerPrivate::RunBeforeNextEvent(nsIRunnable* aRunnable)
// to run.
if (mPreemptingRunnableInfos.Length() == 1 && !NS_HasPendingEvents(mThread)) {
nsRefPtr<DummyRunnable> dummyRunnable = new DummyRunnable(this);
if (NS_FAILED(Dispatch(dummyRunnable))) {
if (NS_FAILED(Dispatch(dummyRunnable.forget()))) {
NS_WARNING("RunBeforeNextEvent called after the thread is shutting "
"down!");
mPreemptingRunnableInfos.Clear();
@ -7140,7 +7148,7 @@ WorkerPrivate::SetThread(WorkerThread* aThread)
if (!mPreStartRunnables.IsEmpty()) {
for (uint32_t index = 0; index < mPreStartRunnables.Length(); index++) {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
mThread->Dispatch(friendKey, mPreStartRunnables[index])));
mThread->DispatchAnyThread(friendKey, mPreStartRunnables[index].forget())));
}
mPreStartRunnables.Clear();
}
@ -7400,9 +7408,19 @@ NS_INTERFACE_MAP_END
template <class Derived>
NS_IMETHODIMP
WorkerPrivateParent<Derived>::
EventTarget::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
EventTarget::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags)
{
nsCOMPtr<nsIRunnable> event(aRunnable);
return Dispatch(event.forget(), aFlags);
}
template <class Derived>
NS_IMETHODIMP
WorkerPrivateParent<Derived>::
EventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags)
{
// May be called on any thread!
nsCOMPtr<nsIRunnable> event(aRunnable);
// Workers only support asynchronous dispatch for now.
if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
@ -7419,12 +7437,12 @@ EventTarget::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
return NS_ERROR_UNEXPECTED;
}
if (aRunnable) {
workerRunnable = mWorkerPrivate->MaybeWrapAsWorkerRunnable(aRunnable);
if (event) {
workerRunnable = mWorkerPrivate->MaybeWrapAsWorkerRunnable(event.forget());
}
nsresult rv =
mWorkerPrivate->DispatchPrivate(workerRunnable, mNestedEventTarget);
mWorkerPrivate->DispatchPrivate(workerRunnable.forget(), mNestedEventTarget);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

View File

@ -233,7 +233,7 @@ private:
ErrorResult& aRv);
nsresult
DispatchPrivate(WorkerRunnable* aRunnable, nsIEventTarget* aSyncLoopTarget);
DispatchPrivate(already_AddRefed<WorkerRunnable>&& aRunnable, nsIEventTarget* aSyncLoopTarget);
public:
virtual JSObject*
@ -258,19 +258,19 @@ public:
}
nsresult
Dispatch(WorkerRunnable* aRunnable)
Dispatch(already_AddRefed<WorkerRunnable>&& aRunnable)
{
return DispatchPrivate(aRunnable, nullptr);
return DispatchPrivate(Move(aRunnable), nullptr);
}
nsresult
DispatchControlRunnable(WorkerControlRunnable* aWorkerControlRunnable);
DispatchControlRunnable(already_AddRefed<WorkerControlRunnable>&& aWorkerControlRunnable);
nsresult
DispatchDebuggerRunnable(WorkerRunnable* aDebuggerRunnable);
DispatchDebuggerRunnable(already_AddRefed<WorkerRunnable>&& aDebuggerRunnable);
already_AddRefed<WorkerRunnable>
MaybeWrapAsWorkerRunnable(nsIRunnable* aRunnable);
MaybeWrapAsWorkerRunnable(already_AddRefed<nsIRunnable>&& aRunnable);
already_AddRefed<nsIEventTarget>
GetEventTarget();

View File

@ -136,25 +136,27 @@ WorkerRunnable::Dispatch(JSContext* aCx)
bool
WorkerRunnable::DispatchInternal()
{
nsRefPtr<WorkerRunnable> runnable(this);
if (mBehavior == WorkerThreadModifyBusyCount ||
mBehavior == WorkerThreadUnchangedBusyCount) {
if (IsDebuggerRunnable()) {
return NS_SUCCEEDED(mWorkerPrivate->DispatchDebuggerRunnable(this));
return NS_SUCCEEDED(mWorkerPrivate->DispatchDebuggerRunnable(runnable.forget()));
} else {
return NS_SUCCEEDED(mWorkerPrivate->Dispatch(this));
return NS_SUCCEEDED(mWorkerPrivate->Dispatch(runnable.forget()));
}
}
MOZ_ASSERT(mBehavior == ParentThreadUnchangedBusyCount);
if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
return NS_SUCCEEDED(parent->Dispatch(this));
return NS_SUCCEEDED(parent->Dispatch(runnable.forget()));
}
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
MOZ_ASSERT(mainThread);
return NS_SUCCEEDED(mainThread->Dispatch(this, NS_DISPATCH_NORMAL));
return NS_SUCCEEDED(mainThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
}
void
@ -422,7 +424,8 @@ bool
WorkerSyncRunnable::DispatchInternal()
{
if (mSyncLoopTarget) {
return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(this, NS_DISPATCH_NORMAL));
nsRefPtr<WorkerSyncRunnable> runnable(this);
return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
}
return WorkerRunnable::DispatchInternal();
@ -482,7 +485,8 @@ StopSyncLoopRunnable::DispatchInternal()
{
MOZ_ASSERT(mSyncLoopTarget);
return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(this, NS_DISPATCH_NORMAL));
nsRefPtr<StopSyncLoopRunnable> runnable(this);
return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
}
void
@ -518,18 +522,20 @@ WorkerControlRunnable::Cancel()
bool
WorkerControlRunnable::DispatchInternal()
{
nsRefPtr<WorkerControlRunnable> runnable(this);
if (mBehavior == WorkerThreadUnchangedBusyCount) {
return NS_SUCCEEDED(mWorkerPrivate->DispatchControlRunnable(this));
return NS_SUCCEEDED(mWorkerPrivate->DispatchControlRunnable(runnable.forget()));
}
if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
return NS_SUCCEEDED(parent->DispatchControlRunnable(this));
return NS_SUCCEEDED(parent->DispatchControlRunnable(runnable.forget()));
}
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
MOZ_ASSERT(mainThread);
return NS_SUCCEEDED(mainThread->Dispatch(this, NS_DISPATCH_NORMAL));
return NS_SUCCEEDED(mainThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
}
void
@ -560,8 +566,9 @@ WorkerMainThreadRunnable::Dispatch(JSContext* aCx)
AutoSyncLoopHolder syncLoop(mWorkerPrivate);
mSyncLoopTarget = syncLoop.EventTarget();
nsRefPtr<WorkerMainThreadRunnable> runnable(this);
if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
if (NS_FAILED(NS_DispatchToMainThread(runnable.forget(), NS_DISPATCH_NORMAL))) {
JS_ReportError(aCx, "Failed to dispatch to main thread!");
return false;
}

View File

@ -139,11 +139,13 @@ WorkerThread::SetWorker(const WorkerThreadFriendKey& /* aKey */,
nsresult
WorkerThread::DispatchPrimaryRunnable(const WorkerThreadFriendKey& /* aKey */,
nsIRunnable* aRunnable)
already_AddRefed<nsIRunnable>&& aRunnable)
{
nsCOMPtr<nsIRunnable> runnable(aRunnable);
#ifdef DEBUG
MOZ_ASSERT(PR_GetCurrentThread() != mThread);
MOZ_ASSERT(aRunnable);
MOZ_ASSERT(runnable);
{
MutexAutoLock lock(mLock);
@ -152,7 +154,7 @@ WorkerThread::DispatchPrimaryRunnable(const WorkerThreadFriendKey& /* aKey */,
}
#endif
nsresult rv = nsThread::Dispatch(aRunnable, NS_DISPATCH_NORMAL);
nsresult rv = nsThread::Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -161,8 +163,8 @@ WorkerThread::DispatchPrimaryRunnable(const WorkerThreadFriendKey& /* aKey */,
}
nsresult
WorkerThread::Dispatch(const WorkerThreadFriendKey& /* aKey */,
WorkerRunnable* aWorkerRunnable)
WorkerThread::DispatchAnyThread(const WorkerThreadFriendKey& /* aKey */,
already_AddRefed<WorkerRunnable>&& aWorkerRunnable)
{
// May be called on any thread!
@ -181,8 +183,9 @@ WorkerThread::Dispatch(const WorkerThreadFriendKey& /* aKey */,
}
}
#endif
nsCOMPtr<nsIRunnable> runnable(aWorkerRunnable);
nsresult rv = nsThread::Dispatch(aWorkerRunnable, NS_DISPATCH_NORMAL);
nsresult rv = nsThread::Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -197,9 +200,17 @@ WorkerThread::Dispatch(const WorkerThreadFriendKey& /* aKey */,
NS_IMPL_ISUPPORTS_INHERITED0(WorkerThread, nsThread)
NS_IMETHODIMP
WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
WorkerThread::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags)
{
nsCOMPtr<nsIRunnable> runnable(aRunnable);
return Dispatch(runnable.forget(), aFlags);
}
NS_IMETHODIMP
WorkerThread::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags)
{
// May be called on any thread!
nsCOMPtr<nsIRunnable> runnable(aRunnable); // in case we exit early
// Workers only support asynchronous dispatch.
if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
@ -209,8 +220,8 @@ WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
const bool onWorkerThread = PR_GetCurrentThread() == mThread;
#ifdef DEBUG
if (aRunnable && !onWorkerThread) {
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(aRunnable);
if (runnable && !onWorkerThread) {
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(runnable);
{
MutexAutoLock lock(mLock);
@ -245,18 +256,14 @@ WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
}
}
nsIRunnable* runnableToDispatch;
nsRefPtr<WorkerRunnable> workerRunnable;
if (aRunnable && onWorkerThread) {
workerRunnable = workerPrivate->MaybeWrapAsWorkerRunnable(aRunnable);
runnableToDispatch = workerRunnable;
nsresult rv;
if (runnable && onWorkerThread) {
nsRefPtr<WorkerRunnable> workerRunnable = workerPrivate->MaybeWrapAsWorkerRunnable(runnable.forget());
rv = nsThread::Dispatch(workerRunnable.forget(), NS_DISPATCH_NORMAL);
} else {
runnableToDispatch = aRunnable;
rv = nsThread::Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
}
nsresult rv = nsThread::Dispatch(runnableToDispatch, NS_DISPATCH_NORMAL);
if (!onWorkerThread && workerPrivate) {
// We need to wake the worker thread if we're not already on the right
// thread and the dispatch succeeded.

View File

@ -66,11 +66,11 @@ public:
nsresult
DispatchPrimaryRunnable(const WorkerThreadFriendKey& aKey,
nsIRunnable* aRunnable);
already_AddRefed<nsIRunnable>&& aRunnable);
nsresult
Dispatch(const WorkerThreadFriendKey& aKey,
WorkerRunnable* aWorkerRunnable);
DispatchAnyThread(const WorkerThreadFriendKey& aKey,
already_AddRefed<WorkerRunnable>&& aWorkerRunnable);
uint32_t
RecursionDepth(const WorkerThreadFriendKey& aKey) const;
@ -84,7 +84,10 @@ private:
// This should only be called by consumers that have an
// nsIEventTarget/nsIThread pointer.
NS_IMETHOD
Dispatch(nsIRunnable* aRunnable, uint32_t aFlags) override;
Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags) override;
NS_IMETHOD
DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) override;
};
} // namespace workers

View File

@ -44,7 +44,7 @@ RunOnThreadInternal(nsIEventTarget *thread, nsIRunnable *runnable, uint32_t flag
return rv;
}
if (!on) {
return thread->Dispatch(runnable_ref, flags);
return thread->Dispatch(runnable_ref.forget(), flags);
}
}
return runnable_ref->Run();

View File

@ -154,13 +154,21 @@ nsSocketTransportService::GetThreadSafely()
}
NS_IMETHODIMP
nsSocketTransportService::Dispatch(nsIRunnable *event, uint32_t flags)
nsSocketTransportService::DispatchFromScript(nsIRunnable *event, uint32_t flags)
{
SOCKET_LOG(("STS dispatch [%p]\n", event));
nsCOMPtr<nsIRunnable> event_ref(event);
return Dispatch(event_ref.forget(), flags);
}
NS_IMETHODIMP
nsSocketTransportService::Dispatch(already_AddRefed<nsIRunnable>&& event, uint32_t flags)
{
nsCOMPtr<nsIRunnable> event_ref(event);
SOCKET_LOG(("STS dispatch [%p]\n", event_ref.get()));
nsCOMPtr<nsIThread> thread = GetThreadSafely();
nsresult rv;
rv = thread ? thread->Dispatch(event, flags) : NS_ERROR_NOT_INITIALIZED;
rv = thread ? thread->Dispatch(event_ref.forget(), flags) : NS_ERROR_NOT_INITIALIZED;
if (rv == NS_ERROR_UNEXPECTED) {
// Thread is no longer accepting events. We must have just shut it
// down on the main thread. Pretend we never saw it.

View File

@ -81,6 +81,10 @@ public:
NS_DECL_NSITHREADOBSERVER
NS_DECL_NSIRUNNABLE
NS_DECL_NSIOBSERVER
// missing from NS_DECL_NSIEVENTTARGET because MSVC
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
nsSocketTransportService();

View File

@ -504,8 +504,16 @@ NS_IMPL_ISUPPORTS(nsStreamTransportService,
nsIObserver)
NS_IMETHODIMP
nsStreamTransportService::Dispatch(nsIRunnable *task, uint32_t flags)
nsStreamTransportService::DispatchFromScript(nsIRunnable *task, uint32_t flags)
{
nsCOMPtr<nsIRunnable> event(task);
return Dispatch(event.forget(), flags);
}
NS_IMETHODIMP
nsStreamTransportService::Dispatch(already_AddRefed<nsIRunnable>&& task, uint32_t flags)
{
nsCOMPtr<nsIRunnable> event(task); // so it gets released on failure paths
nsCOMPtr<nsIThreadPool> pool;
{
mozilla::MutexAutoLock lock(mShutdownLock);
@ -515,7 +523,7 @@ nsStreamTransportService::Dispatch(nsIRunnable *task, uint32_t flags)
pool = mPool;
}
NS_ENSURE_TRUE(pool, NS_ERROR_NOT_INITIALIZED);
return pool->Dispatch(task, flags);
return pool->Dispatch(event.forget(), flags);
}
NS_IMETHODIMP

View File

@ -21,6 +21,10 @@ public:
NS_DECL_NSISTREAMTRANSPORTSERVICE
NS_DECL_NSIEVENTTARGET
NS_DECL_NSIOBSERVER
// missing from NS_DECL_NSIEVENTTARGET because MSVC
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
nsresult Init();

View File

@ -475,9 +475,10 @@ DataChannelConnection::StartDefer()
{
nsresult rv;
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::START_DEFER,
this, (DataChannel *) nullptr));
nsCOMPtr<nsIRunnable> msg = new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::START_DEFER,
this, (DataChannel *) nullptr);
NS_DispatchToMainThread(msg.forget());
return;
}

View File

@ -167,14 +167,25 @@ NS_DispatchToCurrentThread(nsIRunnable* aEvent)
// because it owns main thread only objects, so it is not safe to
// release them here.
NS_METHOD
NS_DispatchToMainThread(nsIRunnable* aEvent, uint32_t aDispatchFlags)
NS_DispatchToMainThread(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aDispatchFlags)
{
nsCOMPtr<nsIRunnable> event(aEvent);
nsCOMPtr<nsIThread> thread;
nsresult rv = NS_GetMainThread(getter_AddRefs(thread));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
// NOTE: if you stop leaking here, adjust Promise::MaybeReportRejected(),
// which assumes a leak here, or split into leaks and no-leaks versions
nsIRunnable* temp = event.forget().take(); // leak without using "unused <<" due to Windows (boo)
return temp ? rv : rv; // to make compiler not bletch on us
}
return thread->Dispatch(aEvent, aDispatchFlags);
return thread->Dispatch(event.forget(), aDispatchFlags);
}
NS_METHOD
NS_DispatchToMainThread(nsIRunnable* aEvent, uint32_t aDispatchFlags)
{
nsCOMPtr<nsIRunnable> event(aEvent);
return NS_DispatchToMainThread(event.forget(), aDispatchFlags);
}
#ifndef XPCOM_GLUE_AVOID_NSPR

View File

@ -121,6 +121,9 @@ extern NS_METHOD NS_DispatchToCurrentThread(nsIRunnable* aEvent);
extern NS_METHOD
NS_DispatchToMainThread(nsIRunnable* aEvent,
uint32_t aDispatchFlags = NS_DISPATCH_NORMAL);
extern NS_METHOD
NS_DispatchToMainThread(already_AddRefed<nsIRunnable>&& aEvent,
uint32_t aDispatchFlags = NS_DISPATCH_NORMAL);
#ifndef XPCOM_GLUE_AVOID_NSPR
/**

View File

@ -109,7 +109,7 @@ LazyIdleThread::EnableIdleTimeout()
if (mThread) {
nsCOMPtr<nsIRunnable> runnable(new nsRunnable());
if (NS_FAILED(Dispatch(runnable, NS_DISPATCH_NORMAL))) {
if (NS_FAILED(Dispatch(runnable.forget(), NS_DISPATCH_NORMAL))) {
NS_WARNING("Failed to dispatch!");
}
}
@ -302,7 +302,7 @@ LazyIdleThread::ShutdownThread()
PreDispatch();
rv = mThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
rv = mThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -343,7 +343,7 @@ LazyIdleThread::ShutdownThread()
runnable.swap(queuedRunnables[index]);
MOZ_ASSERT(runnable, "Null runnable?!");
if (NS_FAILED(Dispatch(runnable, NS_DISPATCH_NORMAL))) {
if (NS_FAILED(Dispatch(runnable.forget(), NS_DISPATCH_NORMAL))) {
NS_ERROR("Failed to re-dispatch queued runnable!");
}
}
@ -395,10 +395,18 @@ NS_IMPL_QUERY_INTERFACE(LazyIdleThread, nsIThread,
nsIObserver)
NS_IMETHODIMP
LazyIdleThread::Dispatch(nsIRunnable* aEvent,
LazyIdleThread::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
{
nsCOMPtr<nsIRunnable> event(aEvent);
return Dispatch(event.forget(), aFlags);
}
NS_IMETHODIMP
LazyIdleThread::Dispatch(already_AddRefed<nsIRunnable>&& aEvent,
uint32_t aFlags)
{
ASSERT_OWNING_THREAD();
nsCOMPtr<nsIRunnable> event(aEvent); // avoid leaks
// LazyIdleThread can't always support synchronous dispatch currently.
if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
@ -412,7 +420,7 @@ LazyIdleThread::Dispatch(nsIRunnable* aEvent,
// If our thread is shutting down then we can't actually dispatch right now.
// Queue this runnable for later.
if (UseRunnableQueue()) {
mQueuedRunnables->AppendElement(aEvent);
mQueuedRunnables->AppendElement(event);
return NS_OK;
}
@ -423,7 +431,7 @@ LazyIdleThread::Dispatch(nsIRunnable* aEvent,
PreDispatch();
return mThread->Dispatch(aEvent, aFlags);
return mThread->Dispatch(event.forget(), aFlags);
}
NS_IMETHODIMP
@ -557,7 +565,7 @@ LazyIdleThread::AfterProcessNextEvent(nsIThreadInternal* /* aThread */,
return NS_ERROR_UNEXPECTED;
}
nsresult rv = mOwningThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
nsresult rv = mOwningThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

View File

@ -45,6 +45,10 @@ public:
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSITHREADOBSERVER
NS_DECL_NSIOBSERVER
// missing from NS_DECL_NSIEVENTTARGET because MSVC
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
enum ShutdownMethod
{

View File

@ -84,6 +84,13 @@ nsEventQueue::GetEvent(bool aMayWait, nsIRunnable** aResult)
void
nsEventQueue::PutEvent(nsIRunnable* aRunnable)
{
nsCOMPtr<nsIRunnable> event(aRunnable);
PutEvent(event.forget());
}
void
nsEventQueue::PutEvent(already_AddRefed<nsIRunnable>&& aRunnable)
{
// Avoid calling AddRef+Release while holding our monitor.
nsCOMPtr<nsIRunnable> event(aRunnable);

View File

@ -10,6 +10,8 @@
#include <stdlib.h>
#include "mozilla/ReentrantMonitor.h"
#include "nsIRunnable.h"
#include "nsCOMPtr.h"
#include "mozilla/AlreadyAddRefed.h"
// A threadsafe FIFO event queue...
class nsEventQueue
@ -24,6 +26,7 @@ public:
// a strong reference to the event after this method returns. This method
// cannot fail.
void PutEvent(nsIRunnable* aEvent);
void PutEvent(already_AddRefed<nsIRunnable>&& aEvent);
// This method gets an event from the event queue. If mayWait is true, then
// the method will block the calling thread until an event is available. If

View File

@ -5,29 +5,28 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
#include "nsIRunnable.idl"
%{C++
#include "nsCOMPtr.h"
#include "mozilla/AlreadyAddRefed.h"
%}
interface nsIRunnable;
native alreadyAddRefed_nsIRunnable(already_AddRefed<nsIRunnable>&&);
[scriptable, uuid(4e8febe4-6631-49dc-8ac9-308c1cb9b09c)]
[scriptable, uuid(f9d60700-e6dc-4a72-9537-689058655472)]
interface nsIEventTarget : nsISupports
{
/* until we can get rid of all uses, keep the non-alreadyAddRefed<> version */
/**
* Dispatch an event to this event target. This function may be called from
* any thread, and it may be called re-entrantly.
*
* @param event
* The event to dispatch.
* @param flags
* The flags modifying event dispatch. The flags are described in detail
* below.
*
* @throws NS_ERROR_INVALID_ARG
* Indicates that event is null.
* @throws NS_ERROR_UNEXPECTED
* Indicates that the thread is shutting down and has finished processing
* events, so this event would never run and has not been dispatched.
* This must be non-virtual due to issues with MSVC 2013's ordering of
* vtbls for overloads. With other platforms we can leave this virtual
* and avoid adding lots of Dispatch() methods to classes inheriting this.
*/
void dispatch(in nsIRunnable event, in unsigned long flags);
%{C++
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
%}
/**
* This flag specifies the default mode of event dispatch, whereby the event
@ -45,7 +44,7 @@ interface nsIEventTarget : nsISupports
* given event to be processed.
*/
const unsigned long DISPATCH_SYNC = 1;
/**
* Check to see if this event target is associated with the current thread.
*
@ -55,6 +54,41 @@ interface nsIEventTarget : nsISupports
* this method).
*/
boolean isOnCurrentThread();
/**
* Dispatch an event to this event target. This function may be called from
* any thread, and it may be called re-entrantly.
*
* @param event
* The alreadyAddRefed<> event to dispatch
* @param flags
* The flags modifying event dispatch. The flags are described in detail
* below.
*
* @throws NS_ERROR_INVALID_ARG
* Indicates that event is null.
* @throws NS_ERROR_UNEXPECTED
* Indicates that the thread is shutting down and has finished processing
* events, so this event would never run and has not been dispatched.
*/
[noscript, binaryname(Dispatch)] void dispatchFromC(in alreadyAddRefed_nsIRunnable event, in unsigned long flags);
/**
* Version of Dispatch to expose to JS, which doesn't require an alreadyAddRefed<>
* (it will be converted to that internally)
*
* @param event
* The (raw) event to dispatch.
* @param flags
* The flags modifying event dispatch. The flags are described in detail
* below.
*
* @throws NS_ERROR_INVALID_ARG
* Indicates that event is null.
* @throws NS_ERROR_UNEXPECTED
* Indicates that the thread is shutting down and has finished processing
* events, so this event would never run and has not been dispatched.
*/
[binaryname(DispatchFromScript)] void dispatch(in nsIRunnable event, in unsigned long flags);
};
%{C++

View File

@ -27,7 +27,7 @@ interface nsIThreadPoolListener : nsISupports
* anonymous (unnamed) worker threads. An event dispatched to the thread pool
* will be run on the next available worker thread.
*/
[scriptable, uuid(53675068-cb3a-40e5-a026-1be5a97c9b23)]
[scriptable, uuid(cacd4a2e-2655-4ff8-894c-10c15883cd0a)]
interface nsIThreadPool : nsIEventTarget
{
/**

View File

@ -480,7 +480,7 @@ nsThread::Init()
// that mThread is set properly.
{
MutexAutoLock lock(mLock);
mEventsRoot.PutEvent(startup);
mEventsRoot.PutEvent(startup); // retain a reference
}
// Wait for thread to call ThreadManager::SetupCurrentThread, which completes
@ -501,6 +501,13 @@ nsThread::InitCurrentThread()
nsresult
nsThread::PutEvent(nsIRunnable* aEvent, nsNestedEventTarget* aTarget)
{
nsCOMPtr<nsIRunnable> event(aEvent);
return PutEvent(event.forget(), aTarget);
}
nsresult
nsThread::PutEvent(already_AddRefed<nsIRunnable>&& aEvent, nsNestedEventTarget* aTarget)
{
nsCOMPtr<nsIThreadObserver> obs;
@ -509,9 +516,11 @@ nsThread::PutEvent(nsIRunnable* aEvent, nsNestedEventTarget* aTarget)
nsChainedEventQueue* queue = aTarget ? aTarget->mQueue : &mEventsRoot;
if (!queue || (queue == &mEventsRoot && mEventsAreDoomed)) {
NS_WARNING("An event was posted to a thread that will never run it (rejected)");
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIRunnable> temp(aEvent);
nsIRunnable* temp2 = temp.forget().take(); // can't use unused << aEvent here due to Windows (boo)
return temp2 ? NS_ERROR_UNEXPECTED : NS_ERROR_UNEXPECTED; // to make compiler not bletch on us
}
queue->PutEvent(aEvent);
queue->PutEvent(Move(aEvent));
// Make sure to grab the observer before dropping the lock, otherwise the
// event that we just placed into the queue could run and eventually delete
@ -528,10 +537,11 @@ nsThread::PutEvent(nsIRunnable* aEvent, nsNestedEventTarget* aTarget)
}
nsresult
nsThread::DispatchInternal(nsIRunnable* aEvent, uint32_t aFlags,
nsThread::DispatchInternal(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags,
nsNestedEventTarget* aTarget)
{
if (NS_WARN_IF(!aEvent)) {
nsCOMPtr<nsIRunnable> event(aEvent);
if (NS_WARN_IF(!event)) {
return NS_ERROR_INVALID_ARG;
}
@ -540,9 +550,9 @@ nsThread::DispatchInternal(nsIRunnable* aEvent, uint32_t aFlags,
}
#ifdef MOZ_TASK_TRACER
nsCOMPtr<nsIRunnable> tracedRunnable = CreateTracedRunnable(aEvent);
nsCOMPtr<nsIRunnable> tracedRunnable = CreateTracedRunnable(event); // adds a ref
(static_cast<TracedRunnable*>(tracedRunnable.get()))->DispatchTask();
aEvent = tracedRunnable;
event = tracedRunnable.forget();
#endif
if (aFlags & DISPATCH_SYNC) {
@ -556,8 +566,8 @@ nsThread::DispatchInternal(nsIRunnable* aEvent, uint32_t aFlags,
// that to tell us when the event has been processed.
nsRefPtr<nsThreadSyncDispatch> wrapper =
new nsThreadSyncDispatch(thread, aEvent);
nsresult rv = PutEvent(wrapper, aTarget);
new nsThreadSyncDispatch(thread, event.forget());
nsresult rv = PutEvent(wrapper, aTarget); // hold a ref
// Don't wait for the event to finish if we didn't dispatch it...
if (NS_FAILED(rv)) {
return rv;
@ -571,18 +581,25 @@ nsThread::DispatchInternal(nsIRunnable* aEvent, uint32_t aFlags,
}
NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "unexpected dispatch flags");
return PutEvent(aEvent, aTarget);
return PutEvent(event.forget(), aTarget);
}
//-----------------------------------------------------------------------------
// nsIEventTarget
NS_IMETHODIMP
nsThread::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
nsThread::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
{
LOG(("THRD(%p) Dispatch [%p %x]\n", this, aEvent, aFlags));
nsCOMPtr<nsIRunnable> event(aEvent);
return Dispatch(event.forget(), aFlags);
}
return DispatchInternal(aEvent, aFlags, nullptr);
NS_IMETHODIMP
nsThread::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
{
LOG(("THRD(%p) Dispatch [%p %x]\n", this, /* XXX aEvent */nullptr, aFlags));
return DispatchInternal(Move(aEvent), aFlags, nullptr);
}
NS_IMETHODIMP
@ -635,7 +652,7 @@ nsThread::Shutdown()
// events to process.
nsCOMPtr<nsIRunnable> event = new nsThreadShutdownEvent(this, &context);
// XXXroc What if posting the event fails due to OOM?
PutEvent(event, nullptr);
PutEvent(event.forget(), nullptr);
// We could still end up with other events being added after the shutdown
// task, but that's okay because we process pending events in ThreadFunc
@ -1040,7 +1057,7 @@ nsThread::PopEventQueue(nsIEventTarget* aInnermostTarget)
nsCOMPtr<nsIRunnable> event;
while (queue->GetEvent(false, getter_AddRefs(event))) {
mEvents->PutEvent(event);
mEvents->PutEvent(event.forget());
}
// Don't let the event target post any more events.
@ -1085,12 +1102,19 @@ nsThreadSyncDispatch::Run()
NS_IMPL_ISUPPORTS(nsThread::nsNestedEventTarget, nsIEventTarget)
NS_IMETHODIMP
nsThread::nsNestedEventTarget::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
nsThread::nsNestedEventTarget::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
{
LOG(("THRD(%p) Dispatch [%p %x] to nested loop %p\n", mThread.get(), aEvent,
nsCOMPtr<nsIRunnable> event(aEvent);
return Dispatch(event.forget(), aFlags);
}
NS_IMETHODIMP
nsThread::nsNestedEventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
{
LOG(("THRD(%p) Dispatch [%p %x] to nested loop %p\n", mThread.get(), /*XXX aEvent*/ nullptr,
aFlags, this));
return mThread->DispatchInternal(aEvent, aFlags, this);
return mThread->DispatchInternal(Move(aEvent), aFlags, this);
}
NS_IMETHODIMP

View File

@ -16,6 +16,7 @@
#include "nsTObserverArray.h"
#include "mozilla/Attributes.h"
#include "nsAutoPtr.h"
#include "mozilla/AlreadyAddRefed.h"
// A native thread
class nsThread
@ -28,6 +29,10 @@ public:
NS_DECL_NSITHREAD
NS_DECL_NSITHREADINTERNAL
NS_DECL_NSISUPPORTSPRIORITY
// missing from NS_DECL_NSIEVENTTARGET because MSVC
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
enum MainThreadFlag
{
@ -98,8 +103,9 @@ protected:
return mEvents->GetEvent(aMayWait, aEvent);
}
nsresult PutEvent(nsIRunnable* aEvent, nsNestedEventTarget* aTarget);
nsresult PutEvent(already_AddRefed<nsIRunnable>&& aEvent, nsNestedEventTarget* aTarget);
nsresult DispatchInternal(nsIRunnable* aEvent, uint32_t aFlags,
nsresult DispatchInternal(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags,
nsNestedEventTarget* aTarget);
// Wrapper for nsEventQueue that supports chaining.
@ -121,6 +127,11 @@ protected:
mQueue.PutEvent(aEvent);
}
void PutEvent(already_AddRefed<nsIRunnable>&& aEvent)
{
mQueue.PutEvent(mozilla::Move(aEvent));
}
bool HasPendingEvent()
{
return mQueue.HasPendingEvent();
@ -189,7 +200,7 @@ protected:
class nsThreadSyncDispatch : public nsRunnable
{
public:
nsThreadSyncDispatch(nsIThread* aOrigin, nsIRunnable* aTask)
nsThreadSyncDispatch(nsIThread* aOrigin, already_AddRefed<nsIRunnable>&& aTask)
: mOrigin(aOrigin)
, mSyncTask(aTask)
, mResult(NS_ERROR_NOT_INITIALIZED)

View File

@ -66,6 +66,13 @@ nsThreadPool::~nsThreadPool()
nsresult
nsThreadPool::PutEvent(nsIRunnable* aEvent)
{
nsCOMPtr<nsIRunnable> event(aEvent);
return PutEvent(event.forget());
}
nsresult
nsThreadPool::PutEvent(already_AddRefed<nsIRunnable>&& aEvent)
{
// Avoid spawning a new thread while holding the event queue lock...
@ -89,7 +96,7 @@ nsThreadPool::PutEvent(nsIRunnable* aEvent)
spawnThread = true;
}
mEvents.PutEvent(aEvent);
mEvents.PutEvent(Move(aEvent));
stackSize = mStackSize;
}
@ -235,9 +242,16 @@ nsThreadPool::Run()
}
NS_IMETHODIMP
nsThreadPool::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
nsThreadPool::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
{
LOG(("THRD-P(%p) dispatch [%p %x]\n", this, aEvent, aFlags));
nsCOMPtr<nsIRunnable> event(aEvent);
return Dispatch(event.forget(), aFlags);
}
NS_IMETHODIMP
nsThreadPool::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
{
LOG(("THRD-P(%p) dispatch [%p %x]\n", this, /* XXX aEvent*/ nullptr, aFlags));
if (NS_WARN_IF(mShutdown)) {
return NS_ERROR_NOT_AVAILABLE;
@ -251,7 +265,7 @@ nsThreadPool::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
}
nsRefPtr<nsThreadSyncDispatch> wrapper =
new nsThreadSyncDispatch(thread, aEvent);
new nsThreadSyncDispatch(thread, Move(aEvent));
PutEvent(wrapper);
while (wrapper->IsPending()) {
@ -259,7 +273,7 @@ nsThreadPool::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
}
} else {
NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "unexpected dispatch flags");
PutEvent(aEvent);
PutEvent(Move(aEvent));
}
return NS_OK;
}

View File

@ -15,6 +15,7 @@
#include "nsCOMPtr.h"
#include "nsThreadUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/AlreadyAddRefed.h"
class nsThreadPool final
: public nsIThreadPool
@ -25,6 +26,10 @@ public:
NS_DECL_NSIEVENTTARGET
NS_DECL_NSITHREADPOOL
NS_DECL_NSIRUNNABLE
// missing from NS_DECL_NSIEVENTTARGET because MSVC
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
nsThreadPool();
@ -33,6 +38,7 @@ private:
void ShutdownThread(nsIThread* aThread);
nsresult PutEvent(nsIRunnable* aEvent);
nsresult PutEvent(already_AddRefed<nsIRunnable>&& aEvent);
nsCOMArray<nsIThread> mThreads;
nsEventQueue mEvents;