backing out for bug 478336, bug 477021 and bug 476934 due to compilation failure on Windows in bug 476934
git-svn-id: svn://10.0.0.236/trunk@256968 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -5794,56 +5794,21 @@ JS_PUBLIC_API(jsword)
|
||||
JS_SetContextThread(JSContext *cx)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(cx->requestDepth == 0);
|
||||
if (cx->thread) {
|
||||
JS_ASSERT(cx->thread->id == js_CurrentThreadId());
|
||||
return cx->thread->id;
|
||||
}
|
||||
|
||||
JSRuntime *rt = cx->runtime;
|
||||
JSThread *thread = js_GetCurrentThread(rt);
|
||||
if (!thread) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
jsword old = JS_THREAD_ID(cx);
|
||||
if (!js_SetContextThread(cx))
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We must not race with a GC that accesses cx->thread for all threads,
|
||||
* see bug 476934.
|
||||
*/
|
||||
JS_LOCK_GC(rt);
|
||||
js_WaitForGC(rt);
|
||||
js_InitContextThread(cx, thread);
|
||||
JS_UNLOCK_GC(rt);
|
||||
#endif
|
||||
return old;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(jsword)
|
||||
JS_ClearContextThread(JSContext *cx)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
/*
|
||||
* This must be called outside a request and, if cx is associated with a
|
||||
* thread, this must be called only from that thread. If not, this is a
|
||||
* harmless no-op.
|
||||
*/
|
||||
JS_ASSERT(cx->requestDepth == 0);
|
||||
if (!cx->thread)
|
||||
return 0;
|
||||
jsword old = cx->thread->id;
|
||||
JS_ASSERT(old == js_CurrentThreadId());
|
||||
|
||||
/*
|
||||
* We must not race with a GC that accesses cx->thread for all threads,
|
||||
* see bug 476934.
|
||||
*/
|
||||
JSRuntime *rt = cx->runtime;
|
||||
JS_LOCK_GC(rt);
|
||||
js_WaitForGC(rt);
|
||||
JS_REMOVE_AND_INIT_LINK(&cx->threadLinks);
|
||||
cx->thread = NULL;
|
||||
JS_UNLOCK_GC(cx->runtime);
|
||||
jsword old = JS_THREAD_ID(cx);
|
||||
js_ClearContextThread(cx);
|
||||
return old;
|
||||
#else
|
||||
return 0;
|
||||
|
||||
@@ -146,7 +146,7 @@ js_GetCurrentThread(JSRuntime *rt)
|
||||
thread->gcMallocBytes = 0;
|
||||
|
||||
/*
|
||||
* js_InitContextThread initializes the remaining fields as necessary.
|
||||
* js_SetContextThread initializes the remaining fields as necessary.
|
||||
*/
|
||||
}
|
||||
return thread;
|
||||
@@ -154,14 +154,18 @@ js_GetCurrentThread(JSRuntime *rt)
|
||||
|
||||
/*
|
||||
* Sets current thread as owning thread of a context by assigning the
|
||||
* thread-private info to the context.
|
||||
* thread-private info to the context. If the current thread doesn't have
|
||||
* private JSThread info, create one.
|
||||
*/
|
||||
void
|
||||
js_InitContextThread(JSContext *cx, JSThread *thread)
|
||||
JSBool
|
||||
js_SetContextThread(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(CURRENT_THREAD_IS_ME(thread));
|
||||
JS_ASSERT(!cx->thread);
|
||||
JS_ASSERT(cx->requestDepth == 0);
|
||||
JSThread *thread = js_GetCurrentThread(cx->runtime);
|
||||
|
||||
if (!thread) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear gcFreeLists and caches on each transition from 0 to 1 context
|
||||
@@ -173,8 +177,31 @@ js_InitContextThread(JSContext *cx, JSThread *thread)
|
||||
memset(&thread->propertyCache, 0, sizeof(thread->propertyCache));
|
||||
}
|
||||
|
||||
JS_APPEND_LINK(&cx->threadLinks, &thread->contextList);
|
||||
/* Assert that the previous cx->thread called JS_ClearContextThread(). */
|
||||
JS_ASSERT(!cx->thread || cx->thread == thread);
|
||||
if (!cx->thread)
|
||||
JS_APPEND_LINK(&cx->threadLinks, &thread->contextList);
|
||||
cx->thread = thread;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Remove the owning thread info of a context. */
|
||||
void
|
||||
js_ClearContextThread(JSContext *cx)
|
||||
{
|
||||
/*
|
||||
* If cx is associated with a thread, this must be called only from that
|
||||
* thread. If not, this is a harmless no-op.
|
||||
*/
|
||||
JS_ASSERT(cx->thread == js_GetCurrentThread(cx->runtime) || !cx->thread);
|
||||
JS_REMOVE_AND_INIT_LINK(&cx->threadLinks);
|
||||
#ifdef DEBUG
|
||||
if (JS_CLIST_IS_EMPTY(&cx->thread->contextList)) {
|
||||
memset(cx->thread->gcFreeLists, JS_FREE_PATTERN,
|
||||
sizeof(cx->thread->gcFreeLists));
|
||||
}
|
||||
#endif
|
||||
cx->thread = NULL;
|
||||
}
|
||||
|
||||
#endif /* JS_THREADSAFE */
|
||||
@@ -202,55 +229,33 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
|
||||
JSContext *cx;
|
||||
JSBool ok, first;
|
||||
JSContextCallback cxCallback;
|
||||
#ifdef JS_THREADSAFE
|
||||
JSThread *thread = js_GetCurrentThread(rt);
|
||||
|
||||
if (!thread)
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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);
|
||||
cx = (JSContext *) malloc(sizeof *cx);
|
||||
if (!cx)
|
||||
return NULL;
|
||||
memset(cx, 0, sizeof *cx);
|
||||
|
||||
cx->runtime = rt;
|
||||
JS_ClearOperationCallback(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
|
||||
js_InitContextThread(cx, thread);
|
||||
JS_INIT_CLIST(&cx->threadLinks);
|
||||
js_SetContextThread(cx);
|
||||
#endif
|
||||
JS_STATIC_ASSERT(JSVERSION_DEFAULT == 0);
|
||||
JS_ASSERT(cx->version == JSVERSION_DEFAULT);
|
||||
JS_INIT_ARENA_POOL(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval),
|
||||
&cx->scriptStackQuota);
|
||||
JS_INIT_ARENA_POOL(&cx->tempPool, "temp", 1024, sizeof(jsdouble),
|
||||
&cx->scriptStackQuota);
|
||||
|
||||
js_InitRegExpStatics(cx);
|
||||
|
||||
JS_LOCK_GC(rt);
|
||||
for (;;) {
|
||||
/*
|
||||
* Ensure that we don't race with the GC on other threads, bug 478336.
|
||||
*/
|
||||
js_WaitForGC(rt);
|
||||
first = (rt->contextList.next == &rt->contextList);
|
||||
if (rt->state == JSRTS_UP) {
|
||||
JS_ASSERT(!JS_CLIST_IS_EMPTY(&rt->contextList));
|
||||
first = JS_FALSE;
|
||||
JS_ASSERT(!first);
|
||||
break;
|
||||
}
|
||||
if (rt->state == JSRTS_DOWN) {
|
||||
JS_ASSERT(JS_CLIST_IS_EMPTY(&rt->contextList));
|
||||
first = JS_TRUE;
|
||||
JS_ASSERT(first);
|
||||
rt->state = JSRTS_LAUNCHING;
|
||||
break;
|
||||
}
|
||||
@@ -259,6 +264,21 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
|
||||
JS_APPEND_LINK(&cx->links, &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;
|
||||
JS_INIT_ARENA_POOL(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval),
|
||||
&cx->scriptStackQuota);
|
||||
JS_INIT_ARENA_POOL(&cx->tempPool, "temp", 1024, sizeof(jsdouble),
|
||||
&cx->scriptStackQuota);
|
||||
|
||||
js_InitRegExpStatics(cx);
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -316,9 +336,6 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||
JSLocalRootStack *lrs;
|
||||
JSLocalRootChunk *lrc;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
|
||||
#endif
|
||||
rt = cx->runtime;
|
||||
|
||||
if (mode != JSDCM_NEW_FAILED) {
|
||||
@@ -336,16 +353,9 @@ 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);
|
||||
#endif
|
||||
JS_REMOVE_LINK(&cx->links);
|
||||
last = (rt->contextList.next == &rt->contextList);
|
||||
if (last)
|
||||
@@ -354,7 +364,7 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||
|
||||
if (last) {
|
||||
#ifdef JS_THREADSAFE
|
||||
/*`<
|
||||
/*
|
||||
* If cx is not in a request already, begin one now so that we wait
|
||||
* for any racing GC started on a not-last context to finish, before
|
||||
* we plow ahead and unpin atoms. Note that even though we begin a
|
||||
@@ -390,6 +400,10 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||
* js_DestroyContext that was not last might be waiting in the GC for our
|
||||
* request to end. We'll let it run below, just before we do the truly
|
||||
* final GC and then free atom state.
|
||||
*
|
||||
* At this point, cx must be inaccessible to other threads. It's off the
|
||||
* rt->contextList, and it should not be reachable via any object private
|
||||
* data structure.
|
||||
*/
|
||||
while (cx->requestDepth != 0)
|
||||
JS_EndRequest(cx);
|
||||
@@ -449,13 +463,7 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
/*
|
||||
* Since cx is not on rt->contextList, it cannot be accessed by the GC
|
||||
* running on another thread. Thus, compared with JS_ClearContextThread,
|
||||
* we can safely unlink cx from from JSThread.contextList without taking
|
||||
* the GC lock.
|
||||
*/
|
||||
JS_REMOVE_LINK(&cx->threadLinks);
|
||||
js_ClearContextThread(cx);
|
||||
#endif
|
||||
|
||||
/* Finally, free cx itself. */
|
||||
|
||||
@@ -134,8 +134,11 @@ struct JSThread {
|
||||
extern void JS_DLL_CALLBACK
|
||||
js_ThreadDestructorCB(void *ptr);
|
||||
|
||||
extern JSBool
|
||||
js_SetContextThread(JSContext *cx);
|
||||
|
||||
extern void
|
||||
js_InitContextThread(JSContext *cx, JSThread *thread);
|
||||
js_ClearContextThread(JSContext *cx);
|
||||
|
||||
extern JSThread *
|
||||
js_GetCurrentThread(JSRuntime *rt);
|
||||
|
||||
@@ -1454,9 +1454,22 @@ js_AddRootRT(JSRuntime *rt, void *rp, const char *name)
|
||||
* properly with a racing GC, without calling JS_AddRoot from a request.
|
||||
* We have to preserve API compatibility here, now that we avoid holding
|
||||
* rt->gcLock across the mark phase (including the root hashtable mark).
|
||||
*
|
||||
* If the GC is running and we're called on another thread, wait for this
|
||||
* GC activation to finish. We can safely wait here (in the case where we
|
||||
* are called within a request on another thread's context) without fear
|
||||
* of deadlock because the GC doesn't set rt->gcRunning until after it has
|
||||
* waited for all active requests to end.
|
||||
*/
|
||||
JS_LOCK_GC(rt);
|
||||
js_WaitForGC(rt);
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(!rt->gcRunning || rt->gcLevel > 0);
|
||||
if (rt->gcRunning && rt->gcThread->id != js_CurrentThreadId()) {
|
||||
do {
|
||||
JS_AWAIT_GC_DONE(rt);
|
||||
} while (rt->gcLevel > 0);
|
||||
}
|
||||
#endif
|
||||
rhe = (JSGCRootHashEntry *)
|
||||
JS_DHashTableOperate(&rt->gcRootsHash, rp, JS_DHASH_ADD);
|
||||
if (rhe) {
|
||||
@@ -1478,7 +1491,14 @@ js_RemoveRoot(JSRuntime *rt, void *rp)
|
||||
* Same synchronization drill as above in js_AddRoot.
|
||||
*/
|
||||
JS_LOCK_GC(rt);
|
||||
js_WaitForGC(rt);
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(!rt->gcRunning || rt->gcLevel > 0);
|
||||
if (rt->gcRunning && rt->gcThread->id != js_CurrentThreadId()) {
|
||||
do {
|
||||
JS_AWAIT_GC_DONE(rt);
|
||||
} while (rt->gcLevel > 0);
|
||||
}
|
||||
#endif
|
||||
(void) JS_DHashTableOperate(&rt->gcRootsHash, rp, JS_DHASH_REMOVE);
|
||||
rt->gcPoke = JS_TRUE;
|
||||
JS_UNLOCK_GC(rt);
|
||||
@@ -3529,31 +3549,6 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
||||
/*
|
||||
* If the GC is running and we're called on another thread, wait for this GC
|
||||
* activation to finish. We can safely wait here without fear of deadlock (in
|
||||
* the case where we are called within a request on another thread's context)
|
||||
* because the GC doesn't set rt->gcRunning until after it has waited for all
|
||||
* active requests to end.
|
||||
*
|
||||
* We call here js_CurrentThreadId() after checking for rt->gcRunning to avoid
|
||||
* expensive calls when the GC is not running.
|
||||
*/
|
||||
void
|
||||
js_WaitForGC(JSRuntime *rt)
|
||||
{
|
||||
JS_ASSERT_IF(rt->gcRunning, rt->gcLevel > 0);
|
||||
if (rt->gcRunning && rt->gcThread->id != js_CurrentThreadId()) {
|
||||
do {
|
||||
JS_AWAIT_GC_DONE(rt);
|
||||
} while (rt->gcRunning);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
js_UpdateMallocCounter(JSContext *cx, size_t nbytes)
|
||||
{
|
||||
|
||||
@@ -296,20 +296,6 @@ typedef enum JSGCInvocationKind {
|
||||
extern void
|
||||
js_GC(JSContext *cx, JSGCInvocationKind gckind);
|
||||
|
||||
|
||||
/*
|
||||
* This function must be called with the GC lock held. It is a helper for code
|
||||
* that can potentially run outside JS request to ensure that the GC is not
|
||||
* running when the function returns.
|
||||
*/
|
||||
#ifdef JS_THREADSAFE
|
||||
extern void
|
||||
js_WaitForGC(JSRuntime *rt);
|
||||
#else
|
||||
# define js_WaitForGC(rt) ((void) 0)
|
||||
#endif
|
||||
|
||||
|
||||
/* Call this after succesful malloc of memory for GC-related things. */
|
||||
extern void
|
||||
js_UpdateMallocCounter(JSContext *cx, size_t nbytes);
|
||||
|
||||
Reference in New Issue
Block a user