Fix protection against gc reentry on same thread but on different JSContexts. Also fix potential deadlock in gc when destroying a JSContext while some other thread is blocked in gc waiting for the EndRequest of the first thread. The reentrance fix is needed to fix bug 28570. r=brendan@mozilla.org
git-svn-id: svn://10.0.0.236/trunk@62685 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
ec58a955b0
commit
8b051df564
@ -174,7 +174,11 @@ js_DestroyContext(JSContext *cx, JSGCMode gcmode)
|
||||
js_FreeRegExpStatics(cx, &cx->regExpStatics);
|
||||
#endif
|
||||
|
||||
/* XXXbe this deadlocks with a GC waiting for this request to end */
|
||||
/* Used to avoid deadlock with a GC waiting for this request to end. */
|
||||
#ifdef JS_THREADSAFE
|
||||
cx->destroying = JS_TRUE;
|
||||
#endif
|
||||
|
||||
if (gcmode == JS_FORCE_GC)
|
||||
js_ForceGC(cx);
|
||||
else if (gcmode == JS_MAYBE_GC)
|
||||
|
||||
@ -139,6 +139,7 @@ struct JSRuntime {
|
||||
PRCondVar *gcDone;
|
||||
PRCondVar *requestDone;
|
||||
uint32 requestCount;
|
||||
jsword gcThread;
|
||||
|
||||
/* Lock and owning thread pointer for JS_LOCK_RUNTIME. */
|
||||
PRLock *rtLock;
|
||||
@ -224,10 +225,10 @@ struct JSContext {
|
||||
#ifdef JS_THREADSAFE
|
||||
jsword thread;
|
||||
jsrefcount requestDepth;
|
||||
JSPackedBool gcActive;
|
||||
JSPackedBool destroying;
|
||||
#endif
|
||||
|
||||
/* Exception state (NB: throwing is packed with gcActive above). */
|
||||
/* Exception state (NB: throwing is packed with destroying above). */
|
||||
JSPackedBool throwing; /* is there a pending exception? */
|
||||
jsval exception; /* most-recently-thrown exceptin */
|
||||
|
||||
|
||||
@ -693,6 +693,9 @@ js_GC(JSContext *cx)
|
||||
JSGCThing *thing, *final, **flp, **oflp;
|
||||
GCFinalizeOp finalizer;
|
||||
JSBool a_all_clear, f_all_clear;
|
||||
#ifdef JS_THREADSAFE
|
||||
jsword currentThread;
|
||||
#endif
|
||||
|
||||
rt = cx->runtime;
|
||||
if (rt->gcDisabled)
|
||||
@ -720,8 +723,9 @@ js_GC(JSContext *cx)
|
||||
METER(rt->gcStats.poke++);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
/* Bump gcLevel and return rather than nest on this context. */
|
||||
if (cx->gcActive) {
|
||||
/* Bump gcLevel and return rather than nest on this thread. */
|
||||
currentThread = js_CurrentThreadId();
|
||||
if (rt->gcThread == currentThread) {
|
||||
rt->gcLevel++;
|
||||
METER(if (rt->gcLevel > rt->gcStats.maxlevel)
|
||||
rt->gcStats.maxlevel = rt->gcLevel);
|
||||
@ -739,8 +743,11 @@ js_GC(JSContext *cx)
|
||||
|
||||
/* If another thread is already in GC, don't attempt GC; wait instead. */
|
||||
if (rt->gcLevel > 0) {
|
||||
while (rt->gcLevel > 0)
|
||||
JS_AWAIT_GC_DONE(rt);
|
||||
/* If we are destroying this context return early to avoid deadlock. */
|
||||
if (!cx->destroying) {
|
||||
while (rt->gcLevel > 0)
|
||||
JS_AWAIT_GC_DONE(rt);
|
||||
}
|
||||
if (cx->requestDepth)
|
||||
rt->requestCount++;
|
||||
JS_UNLOCK_GC(rt);
|
||||
@ -750,8 +757,8 @@ js_GC(JSContext *cx)
|
||||
/* No other thread is in GC, so indicate that we're now in GC. */
|
||||
rt->gcLevel = 1;
|
||||
|
||||
/* Also indicate that GC is active on this context. */
|
||||
cx->gcActive = JS_TRUE;
|
||||
/* Also indicate that GC is active on this thread. */
|
||||
rt->gcThread = currentThread;
|
||||
|
||||
/* Wait for all other requests to finish. */
|
||||
while (rt->requestCount > 0)
|
||||
@ -972,7 +979,7 @@ out:
|
||||
/* If we were invoked during a request, undo the temporary decrement. */
|
||||
if (cx->requestDepth)
|
||||
rt->requestCount++;
|
||||
cx->gcActive = JS_FALSE;
|
||||
rt->gcThread = 0;
|
||||
JS_NOTIFY_GC_DONE(rt);
|
||||
JS_UNLOCK_GC(rt);
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user