зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1540080 - Execute the canceling runnable after self.close() even when we have sync event loops, r=asuth
Differential Revision: https://phabricator.services.mozilla.com/D25605 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
f230fa362c
Коммит
01c18856e4
|
@ -2063,8 +2063,8 @@ WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
|
|||
mCreationTimeStamp(TimeStamp::Now()),
|
||||
mCreationTimeHighRes((double)PR_Now() / PR_USEC_PER_MSEC),
|
||||
mWorkerThreadAccessible(aParent),
|
||||
mPostSyncLoopOperations(0),
|
||||
mParentWindowPaused(false),
|
||||
mPendingEventQueueClearing(false),
|
||||
mCancelAllPendingRunnables(false),
|
||||
mWorkerScriptExecutedSuccessfully(false),
|
||||
mFetchHandlerWasAdded(false),
|
||||
|
@ -3160,7 +3160,7 @@ void WorkerPrivate::ScheduleDeletion(WorkerRanOrNot aRanOrNot) {
|
|||
MOZ_ASSERT(data->mChildWorkers.IsEmpty());
|
||||
}
|
||||
MOZ_ASSERT(mSyncLoopStack.IsEmpty());
|
||||
MOZ_ASSERT(!mPendingEventQueueClearing);
|
||||
MOZ_ASSERT(mPostSyncLoopOperations == 0);
|
||||
|
||||
ClearMainEventQueue(aRanOrNot);
|
||||
#ifdef DEBUG
|
||||
|
@ -3679,14 +3679,37 @@ bool WorkerPrivate::DestroySyncLoop(uint32_t aLoopIndex) {
|
|||
static_cast<ThreadEventQueue<EventQueue>*>(mThread->EventQueue());
|
||||
queue->PopEventQueue(nestedEventTarget);
|
||||
|
||||
if (mSyncLoopStack.IsEmpty() && mPendingEventQueueClearing) {
|
||||
mPendingEventQueueClearing = false;
|
||||
ClearMainEventQueue(WorkerRan);
|
||||
if (mSyncLoopStack.IsEmpty()) {
|
||||
if ((mPostSyncLoopOperations & ePendingEventQueueClearing)) {
|
||||
ClearMainEventQueue(WorkerRan);
|
||||
}
|
||||
|
||||
if ((mPostSyncLoopOperations & eDispatchCancelingRunnable)) {
|
||||
DispatchCancelingRunnable();
|
||||
}
|
||||
|
||||
mPostSyncLoopOperations = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void WorkerPrivate::DispatchCancelingRunnable() {
|
||||
// Here we use a normal runnable to know when the current JS chunk of code
|
||||
// is finished. We cannot use a WorkerRunnable because they are not
|
||||
// accepted any more by the worker, and we do not want to use a
|
||||
// WorkerControlRunnable because they are immediately executed.
|
||||
RefPtr<CancelingRunnable> r = new CancelingRunnable();
|
||||
mThread->nsThread::Dispatch(r.forget(), NS_DISPATCH_NORMAL);
|
||||
|
||||
// At the same time, we want to be sure that we interrupt infinite loops.
|
||||
// The following runnable starts a timer that cancel the worker, from the
|
||||
// parent thread, after CANCELING_TIMEOUT millseconds.
|
||||
RefPtr<CancelingWithTimeoutOnParentRunnable> rr =
|
||||
new CancelingWithTimeoutOnParentRunnable(this);
|
||||
rr->Dispatch();
|
||||
}
|
||||
|
||||
void WorkerPrivate::StopSyncLoop(nsIEventTarget* aSyncLoopTarget,
|
||||
bool aResult) {
|
||||
AssertIsOnWorkerThread();
|
||||
|
@ -3971,7 +3994,7 @@ bool WorkerPrivate::NotifyInternal(WorkerStatus aStatus) {
|
|||
// NB: If we're in a sync loop, we can't clear the queue immediately,
|
||||
// because this is the wrong queue. So we have to defer it until later.
|
||||
if (!mSyncLoopStack.IsEmpty()) {
|
||||
mPendingEventQueueClearing = true;
|
||||
mPostSyncLoopOperations |= ePendingEventQueueClearing;
|
||||
} else {
|
||||
ClearMainEventQueue(WorkerRan);
|
||||
}
|
||||
|
@ -3986,20 +4009,10 @@ bool WorkerPrivate::NotifyInternal(WorkerStatus aStatus) {
|
|||
// Don't abort the script now, but we dispatch a runnable to do it when the
|
||||
// current JS frame is executed.
|
||||
if (aStatus == Closing) {
|
||||
if (mSyncLoopStack.IsEmpty()) {
|
||||
// Here we use a normal runnable to know when the current JS chunk of code
|
||||
// is finished. We cannot use a WorkerRunnable because they are not
|
||||
// accepted any more by the worker, and we do not want to use a
|
||||
// WorkerControlRunnable because they are immediately executed.
|
||||
RefPtr<CancelingRunnable> r = new CancelingRunnable();
|
||||
mThread->nsThread::Dispatch(r.forget(), NS_DISPATCH_NORMAL);
|
||||
|
||||
// At the same time, we want to be sure that we interrupt infinite loops.
|
||||
// The following runnable starts a timer that cancel the worker, from the
|
||||
// parent thread, after CANCELING_TIMEOUT millseconds.
|
||||
RefPtr<CancelingWithTimeoutOnParentRunnable> rr =
|
||||
new CancelingWithTimeoutOnParentRunnable(this);
|
||||
rr->Dispatch();
|
||||
if (!mSyncLoopStack.IsEmpty()) {
|
||||
mPostSyncLoopOperations |= eDispatchCancelingRunnable;
|
||||
} else {
|
||||
DispatchCancelingRunnable();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -925,6 +925,13 @@ class WorkerPrivate : public RelativeTimeline {
|
|||
nsIEventTarget* aSyncLoopTarget,
|
||||
const MutexAutoLock& aProofOfLock);
|
||||
|
||||
// This method dispatches a simple runnable that starts the shutdown procedure
|
||||
// after a self.close(). This method is called after a ClearMainEventQueue()
|
||||
// to be sure that the canceling runnable is the only one in the queue. We
|
||||
// need this async operation to be sure that all the current JS code is
|
||||
// executed.
|
||||
void DispatchCancelingRunnable();
|
||||
|
||||
class EventTarget;
|
||||
friend class EventTarget;
|
||||
friend class mozilla::dom::WorkerHolder;
|
||||
|
@ -1073,9 +1080,16 @@ class WorkerPrivate : public RelativeTimeline {
|
|||
};
|
||||
ThreadBound<WorkerThreadAccessible> mWorkerThreadAccessible;
|
||||
|
||||
uint32_t mPostSyncLoopOperations;
|
||||
|
||||
// List of operations to do at the end of the last sync event loop.
|
||||
enum {
|
||||
ePendingEventQueueClearing = 0x01,
|
||||
eDispatchCancelingRunnable = 0x02,
|
||||
};
|
||||
|
||||
bool mParentWindowPaused;
|
||||
|
||||
bool mPendingEventQueueClearing;
|
||||
bool mCancelAllPendingRunnables;
|
||||
bool mWorkerScriptExecutedSuccessfully;
|
||||
bool mFetchHandlerWasAdded;
|
||||
|
|
Загрузка…
Ссылка в новой задаче