mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
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:
parent
8be77a6119
commit
cb8f0924d3
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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++
|
||||
|
@ -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
|
||||
{
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user