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:
jband%netscape.com 2000-03-12 05:09:46 +00:00
parent ec58a955b0
commit 8b051df564
3 changed files with 22 additions and 10 deletions

View File

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

View File

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

View File

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