bug 477021 - make sure that js_(New|Destroy)Context() do not race against the GC. r=brendan

This commit is contained in:
Igor Bukanov 2009-02-07 12:39:57 +01:00
Родитель 6ee38d80d3
Коммит befa19923d
1 изменённых файлов: 31 добавлений и 32 удалений

Просмотреть файл

@ -237,33 +237,47 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
return NULL;
#endif
cx = (JSContext *) malloc(sizeof *cx);
/*
* We need to initialize the new context fully before adding it to the
* runtime list. After that it can be accessed from another thread via
* js_ContextIterator.
*/
cx = (JSContext *) calloc(1, sizeof *cx);
if (!cx)
return NULL;
memset(cx, 0, sizeof *cx);
cx->runtime = rt;
js_InitOperationLimit(cx);
cx->debugHooks = &rt->globalDebugHooks;
#if JS_STACK_GROWTH_DIRECTION > 0
cx->stackLimit = (jsuword)-1;
cx->stackLimit = (jsuword) -1;
#endif
cx->scriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA;
#ifdef JS_THREADSAFE
cx->gcLocalFreeLists = (JSGCFreeListSet *) &js_GCEmptyFreeListSet;
/*
* At this point cx is not on rt->contextList. Thus we do not need to
* prevent a race against the GC when adding cx to JSThread.contextList.
*/
js_InitContextThread(cx, thread);
#endif
JS_STATIC_ASSERT(JSVERSION_DEFAULT == 0);
JS_ASSERT(cx->version == JSVERSION_DEFAULT);
VOUCH_DOES_NOT_REQUIRE_STACK();
JS_INIT_ARENA_POOL(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval),
&cx->scriptStackQuota);
JS_INIT_ARENA_POOL(&cx->tempPool, "temp",
1024, /* FIXME: bug 421435 */
sizeof(jsdouble), &cx->scriptStackQuota);
js_InitRegExpStatics(cx);
JS_ASSERT(cx->resolveFlags == 0);
JS_LOCK_GC(rt);
for (;;) {
first = (rt->contextList.next == &rt->contextList);
if (rt->state == JSRTS_UP) {
JS_ASSERT(!first);
/* Ensure that it is safe to update rt->contextList below. */
js_WaitForGC(rt);
break;
}
if (rt->state == JSRTS_DOWN) {
@ -276,26 +290,6 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
JS_APPEND_LINK(&cx->link, &rt->contextList);
JS_UNLOCK_GC(rt);
/*
* First we do the infallible, every-time per-context initializations.
* Should a later, fallible initialization (js_InitRegExpStatics, e.g.,
* or the stuff under 'if (first)' below) fail, at least the version
* and arena-pools will be valid and safe to use (say, from the last GC
* done by js_DestroyContext).
*/
cx->version = JSVERSION_DEFAULT;
VOUCH_DOES_NOT_REQUIRE_STACK();
JS_INIT_ARENA_POOL(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval),
&cx->scriptStackQuota);
JS_INIT_ARENA_POOL(&cx->tempPool, "temp",
1024, /* FIXME: bug 421435 */
sizeof(jsdouble), &cx->scriptStackQuota);
js_InitRegExpStatics(cx);
cx->resolveFlags = 0;
/*
* If cx is the first context on this runtime, initialize well-known atoms,
* keywords, numbers, and strings. If one of these steps should fail, the
@ -437,16 +431,21 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
}
}
/* Remove cx from context list first. */
JS_LOCK_GC(rt);
JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING);
#ifdef JS_THREADSAFE
/*
* Typically we are called outside a request, so ensure that the GC is not
* running before removing the context from rt->contextList, see bug 477021.
*/
if (cx->requestDepth == 0)
js_WaitForGC(rt);
js_RevokeGCLocalFreeLists(cx);
#endif
JS_REMOVE_LINK(&cx->link);
last = (rt->contextList.next == &rt->contextList);
if (last)
rt->state = JSRTS_LANDING;
#ifdef JS_THREADSAFE
js_RevokeGCLocalFreeLists(cx);
#endif
JS_UNLOCK_GC(rt);
if (last) {