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:
igor%mir2.org
2009-04-18 09:07:05 +00:00
parent 91ee98114c
commit 85940179ec
5 changed files with 98 additions and 141 deletions

View File

@@ -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;

View File

@@ -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. */

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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);