Bug 900681 - Properly clean up leaked off thread parses in the JS shell, r=billm.

This commit is contained in:
Brian Hackett 2013-08-21 18:43:18 -06:00
parent 3acaa1a1ec
commit 8e0be4fb38
6 changed files with 43 additions and 15 deletions

View File

@ -262,6 +262,11 @@ js::DestroyContext(JSContext *cx, DestroyContextMode mode)
CancelOffThreadIonCompile(c, NULL);
WaitForOffThreadParsingToFinish(rt);
#ifdef JS_WORKER_THREADS
if (rt->workerThreadState)
rt->workerThreadState->cleanup(rt);
#endif
/* Unpin all common names before final GC. */
FinishCommonNames(rt);

View File

@ -10,6 +10,7 @@
#include "jscntxt.h"
#include "jsiter.h"
#include "jsworkers.h"
#include "builtin/Object.h"
#include "jit/IonFrames.h"

View File

@ -359,18 +359,33 @@ WorkerThreadState::init(JSRuntime *rt)
return true;
}
WorkerThreadState::~WorkerThreadState()
void
WorkerThreadState::cleanup(JSRuntime *rt)
{
/*
* Join created threads first, which needs locks and condition variables
* to be intact.
*/
// Do preparatory work for shutdown before the final GC has destroyed most
// of the GC heap.
// Join created threads, to ensure there is no in progress work.
if (threads) {
for (size_t i = 0; i < numThreads; i++)
threads[i].destroy();
js_free(threads);
threads = NULL;
numThreads = 0;
}
// Clean up any parse tasks which haven't been finished yet.
while (!parseFinishedList.empty()) {
JSScript *script = parseFinishedList[0]->script;
finishParseTaskForScript(rt, script);
}
}
WorkerThreadState::~WorkerThreadState()
{
JS_ASSERT(!threads);
JS_ASSERT(parseFinishedList.empty());
if (workerLock)
PR_DestroyLock(workerLock);

View File

@ -30,8 +30,7 @@ namespace ion {
class IonBuilder;
}
#if defined(JS_THREADSAFE) && defined(JS_ION)
# define JS_WORKER_THREADS
#ifdef JS_WORKER_THREADS
/* Per-runtime state for off thread work items. */
class WorkerThreadState
@ -75,6 +74,7 @@ class WorkerThreadState
~WorkerThreadState();
bool init(JSRuntime *rt);
void cleanup(JSRuntime *rt);
void lock();
void unlock();
@ -236,27 +236,31 @@ WaitForOffThreadParsingToFinish(JSRuntime *rt);
class AutoLockWorkerThreadState
{
WorkerThreadState &state;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
#ifdef JS_WORKER_THREADS
WorkerThreadState &state;
public:
AutoLockWorkerThreadState(WorkerThreadState &state
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: state(state)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
#ifdef JS_WORKER_THREADS
state.lock();
#else
(void)state;
#endif
}
~AutoLockWorkerThreadState() {
#ifdef JS_WORKER_THREADS
state.unlock();
#endif
}
#else
public:
AutoLockWorkerThreadState(WorkerThreadState &state
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
#endif
};
class AutoUnlockWorkerThreadState

View File

@ -74,7 +74,7 @@ ThreadDataIter::ThreadDataIter(JSRuntime *rt)
#ifdef JS_WORKER_THREADS
// Only allow iteration over a runtime's threads when those threads are
// paused, to avoid racing when reading data from the PerThreadData.
JS_ASSERT_IF(rt->workerThreadState, rt->workerThreadState->shouldPause);
JS_ASSERT(rt->exclusiveThreadsPaused);
#endif
iter = rt->threadList.getFirst();
}

View File

@ -663,6 +663,7 @@ typedef Vector<JS::Zone *, 1, SystemAllocPolicy> ZoneVector;
class AutoLockForExclusiveAccess;
class AutoPauseWorkersForGC;
class ThreadDataIter;
} // namespace js
@ -772,6 +773,7 @@ struct JSRuntime : public JS::shadow::Runtime,
friend class js::AutoLockForExclusiveAccess;
friend class js::AutoPauseWorkersForGC;
friend class js::ThreadDataIter;
public:
void setUsedByExclusiveThread(JS::Zone *zone);
@ -1317,6 +1319,7 @@ struct JSRuntime : public JS::shadow::Runtime,
#ifdef JS_THREADSAFE
# ifdef JS_ION
js::WorkerThreadState *workerThreadState;
# define JS_WORKER_THREADS
# endif
js::SourceCompressorThread sourceCompressorThread;