bug 718600 - remove JSRuntime::(rtLock, state). r=luke

This commit is contained in:
Igor Bukanov 2012-01-17 23:14:49 +01:00
parent 4a57071627
commit 2942303dc8
9 changed files with 20 additions and 182 deletions

View File

@ -216,7 +216,7 @@ JS_GetEmptyStringValue(JSContext *cx)
JS_PUBLIC_API(JSString *)
JS_GetEmptyString(JSRuntime *rt)
{
JS_ASSERT(rt->state == JSRTS_UP);
JS_ASSERT(rt->hasContexts());
return rt->emptyString;
}
@ -680,7 +680,6 @@ static JSBool js_NewRuntimeWasCalled = JS_FALSE;
JSRuntime::JSRuntime()
: atomsCompartment(NULL),
state(),
cxCallback(NULL),
compartmentCallback(NULL),
activityCallback(NULL),
@ -739,11 +738,6 @@ JSRuntime::JSRuntime()
requestCount(0),
gcThread(NULL),
gcHelperThread(thisFromCtor()),
rtLock(NULL),
# ifdef DEBUG
rtLockOwner(0),
# endif
stateChange(NULL),
#endif
debuggerMutations(0),
securityCallbacks(NULL),
@ -811,12 +805,6 @@ JSRuntime::init(uint32_t maxbytes)
/* this is asymmetric with JS_ShutDown: */
if (!js_SetupLocks(8, 16))
return false;
rtLock = JS_NEW_LOCK();
if (!rtLock)
return false;
stateChange = JS_NEW_CONDVAR(gcLock);
if (!stateChange)
return false;
#endif
debugMode = false;
@ -859,10 +847,6 @@ JSRuntime::~JSRuntime()
JS_DESTROY_CONDVAR(gcDone);
if (requestDone)
JS_DESTROY_CONDVAR(requestDone);
if (rtLock)
JS_DESTROY_LOCK(rtLock);
if (stateChange)
JS_DESTROY_CONDVAR(stateChange);
#endif
}
@ -1137,18 +1121,6 @@ JS_IsInRequest(JSContext *cx)
#endif
}
JS_PUBLIC_API(void)
JS_Lock(JSRuntime *rt)
{
JS_LOCK_RUNTIME(rt);
}
JS_PUBLIC_API(void)
JS_Unlock(JSRuntime *rt)
{
JS_UNLOCK_RUNTIME(rt);
}
JS_PUBLIC_API(JSContextCallback)
JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
{
@ -1927,8 +1899,7 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
*resolved = JS_FALSE;
rt = cx->runtime;
JS_ASSERT(rt->state != JSRTS_DOWN);
if (rt->state == JSRTS_LANDING || !JSID_IS_ATOM(id))
if (!rt->hasContexts() || !JSID_IS_ATOM(id))
return JS_TRUE;
idstr = JSID_TO_STRING(id);

View File

@ -2449,12 +2449,6 @@ class JSAutoCheckRequest {
JS_BEGIN_EXTERN_C
#endif
extern JS_PUBLIC_API(void)
JS_Lock(JSRuntime *rt);
extern JS_PUBLIC_API(void)
JS_Unlock(JSRuntime *rt);
extern JS_PUBLIC_API(JSContextCallback)
JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback);

View File

@ -455,30 +455,7 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
* Here the GC lock is still held after js_InitContextThreadAndLockGC took it and
* the GC is not running on another thread.
*/
bool first;
for (;;) {
if (rt->state == JSRTS_UP) {
JS_ASSERT(!JS_CLIST_IS_EMPTY(&rt->contextList));
first = false;
break;
}
if (rt->state == JSRTS_DOWN) {
JS_ASSERT(JS_CLIST_IS_EMPTY(&rt->contextList));
first = true;
rt->state = JSRTS_LAUNCHING;
break;
}
JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT);
/*
* During the above wait after we are notified about the state change
* but before we wake up, another thread could enter the GC from
* js_DestroyContext, bug 478336. So we must wait here to ensure that
* when we exit the loop with the first flag set to true, that GC is
* finished.
*/
js_WaitForGC(rt);
}
bool first = JS_CLIST_IS_EMPTY(&rt->contextList);
JS_APPEND_LINK(&cx->link, &rt->contextList);
JS_UNLOCK_GC(rt);
@ -507,10 +484,6 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
js_DestroyContext(cx, JSDCM_NEW_FAILED);
return NULL;
}
AutoLockGC lock(rt);
rt->state = JSRTS_UP;
JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
}
JSContextCallback cxCallback = rt->cxCallback;
@ -529,7 +502,6 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
JS_AbortIfWrongThread(rt);
JSContextCallback cxCallback;
JSBool last;
JS_ASSERT(!cx->enumerators);
@ -565,7 +537,6 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
}
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
@ -575,9 +546,7 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
js_WaitForGC(rt);
#endif
JS_REMOVE_LINK(&cx->link);
last = (rt->contextList.next == &rt->contextList);
if (last)
rt->state = JSRTS_LANDING;
bool last = !rt->hasContexts();
if (last || mode == JSDCM_FORCE_GC || mode == JSDCM_MAYBE_GC
#ifdef JS_THREADSAFE
|| cx->outstandingRequests != 0
@ -595,12 +564,7 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
/*
* If this thread 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 request here if necessary, we end all
* thread's requests before forcing a final GC. This lets any
* not-last context destruction racing in another thread try to
* force or maybe run the GC, but by that point, rt->state will
* not be JSRTS_UP, and that GC attempt will return early.
* finish, before we plow ahead and unpin atoms.
*/
if (cx->thread()->data.requestDepth == 0)
JS_BeginRequest(cx);
@ -626,24 +590,16 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
}
#ifdef JS_THREADSAFE
/*
* Destroying a context implicitly calls JS_EndRequest(). Also, we must
* end our request here in case we are "last" -- in that event, another
* 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.
*/
/* Destroying a context implicitly calls JS_EndRequest(). */
while (cx->outstandingRequests != 0)
JS_EndRequest(cx);
#endif
if (last) {
js_GC(cx, NULL, GC_LAST_CONTEXT, gcstats::LASTCONTEXT);
js_GC(cx, NULL, GC_NORMAL, gcstats::LASTCONTEXT);
/* Take the runtime down, now that it has no contexts or atoms. */
JS_LOCK_GC(rt);
rt->state = JSRTS_DOWN;
JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
} else {
if (mode == JSDCM_FORCE_GC)
js_GC(cx, NULL, GC_NORMAL, gcstats::DESTROYCONTEXT);

View File

@ -325,13 +325,6 @@ typedef enum JSDestroyContextMode {
JSDCM_NEW_FAILED
} JSDestroyContextMode;
typedef enum JSRuntimeState {
JSRTS_DOWN,
JSRTS_LAUNCHING,
JSRTS_UP,
JSRTS_LANDING
} JSRuntimeState;
typedef struct JSPropertyTreeEntry {
JSDHashEntryHdr hdr;
js::Shape *child;
@ -351,9 +344,6 @@ struct JSRuntime
/* List of compartments (protected by the GC lock). */
js::CompartmentVector compartments;
/* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */
JSRuntimeState state;
/* See comment for JS_AbortIfWrongThread in jsapi.h. */
#ifdef JS_THREADSAFE
public:
@ -532,6 +522,10 @@ struct JSRuntime
/* List of active contexts sharing this runtime; protected by gcLock. */
JSCList contextList;
bool hasContexts() const {
return !JS_CLIST_IS_EMPTY(&contextList);
}
/* Per runtime debug hooks -- see jsprvtd.h and jsdbgapi.h. */
JSDebugHooks globalDebugHooks;
@ -563,15 +557,6 @@ struct JSRuntime
js::GCHelperThread gcHelperThread;
/* Lock and owning thread pointer for JS_LOCK_RUNTIME. */
PRLock *rtLock;
#ifdef DEBUG
void * rtLockOwner;
#endif
/* Used to synchronize down/up state change; protected by gcLock. */
PRCondVar *stateChange;
/*
* Mapping from NSPR thread identifiers to JSThreads.
*

View File

@ -60,7 +60,7 @@ JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
JS_FRIEND_API(JSString *)
JS_GetAnonymousString(JSRuntime *rt)
{
JS_ASSERT(rt->state == JSRTS_UP);
JS_ASSERT(rt->hasContexts());
return rt->atomState.anonymousAtom;
}

View File

@ -2103,7 +2103,7 @@ MarkRuntime(JSTracer *trc)
{
JSRuntime *rt = trc->runtime;
if (rt->state != JSRTS_LANDING)
if (rt->hasContexts())
MarkConservativeStackRoots(trc);
for (RootRange r = rt->gcRootsHash.all(); !r.empty(); r.popFront())
@ -2659,7 +2659,7 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
JSCompartment *compartment = *read++;
if (!compartment->hold &&
(compartment->arenas.arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT))
(compartment->arenas.arenaListsAreEmpty() || !rt->hasContexts()))
{
compartment->arenas.checkEmptyFreeLists();
if (callback)
@ -3050,7 +3050,6 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
{
JSRuntime *rt = cx->runtime;
JS_ASSERT_IF(comp, gckind != GC_LAST_CONTEXT);
JS_ASSERT_IF(comp, comp != rt->atomsCompartment);
JS_ASSERT_IF(comp, rt->gcMode == JSGC_MODE_COMPARTMENT);
@ -3077,10 +3076,8 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
* is either the current thread or waits for the GC to complete on this
* thread.
*/
if (rt->inOOMReport) {
JS_ASSERT(gckind != GC_LAST_CONTEXT);
if (rt->inOOMReport)
return;
}
/*
* We should not be depending on cx->compartment in the GC, so set it to
@ -3102,10 +3099,8 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
*/
JS_ASSERT(!cx->gcBackgroundFree);
rt->gcHelperThread.waitBackgroundSweepOrAllocEnd();
if (gckind != GC_LAST_CONTEXT && rt->state != JSRTS_LANDING) {
if (rt->gcHelperThread.prepareForBackgroundSweep())
cx->gcBackgroundFree = &rt->gcHelperThread;
}
if (rt->hasContexts() && rt->gcHelperThread.prepareForBackgroundSweep())
cx->gcBackgroundFree = &rt->gcHelperThread;
#endif
MarkAndSweep(cx, gckind);
@ -3135,15 +3130,6 @@ js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, gcstats::Re
JSRuntime *rt = cx->runtime;
JS_AbortIfWrongThread(rt);
/*
* Don't collect garbage if the runtime isn't up, and cx is not the last
* context in the runtime. The last context must force a GC, and nothing
* should suppress that final collection or there may be shutdown leaks,
* or runtime bloat until the next context is created.
*/
if (rt->state != JSRTS_UP && gckind != GC_LAST_CONTEXT)
return;
#ifdef JS_GC_ZEAL
struct AutoVerifyBarriers {
JSContext *cx;
@ -3167,7 +3153,7 @@ js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, gcstats::Re
* on another thread.
*/
if (JSGCCallback callback = rt->gcCallback) {
if (!callback(cx, JSGC_BEGIN) && gckind != GC_LAST_CONTEXT)
if (!callback(cx, JSGC_BEGIN) && rt->hasContexts())
return;
}
@ -3186,7 +3172,7 @@ js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, gcstats::Re
* On shutdown, iterate until finalizers or the JSGC_END callback
* stop creating garbage.
*/
} while (gckind == GC_LAST_CONTEXT && rt->gcPoke);
} while (!rt->hasContexts() && rt->gcPoke);
rt->gcNextFullGCTime = PRMJ_Now() + GC_IDLE_FULL_SPAN;

View File

@ -1408,14 +1408,8 @@ typedef enum JSGCInvocationKind {
/* Normal invocation. */
GC_NORMAL = 0,
/*
* Called from js_DestroyContext for last JSContext in a JSRuntime, when
* it is imperative that rt->gcPoke gets cleared early in js_GC.
*/
GC_LAST_CONTEXT = 1,
/* Minimize GC triggers and release empty GC chunks right away. */
GC_SHRINK = 2
GC_SHRINK = 1
} JSGCInvocationKind;
/* Pass NULL for |comp| to get a full GC. */

View File

@ -740,30 +740,4 @@ js_Unlock(JSContext *cx, JSThinLock *tl)
ThinUnlock(tl, CX_THINLOCK_ID(cx));
}
void
js_LockRuntime(JSRuntime *rt)
{
PR_Lock(rt->rtLock);
#ifdef DEBUG
rt->rtLockOwner = js_CurrentThreadId();
#endif
}
void
js_UnlockRuntime(JSRuntime *rt)
{
#ifdef DEBUG
rt->rtLockOwner = NULL;
#endif
PR_Unlock(rt->rtLock);
}
#ifdef DEBUG
JSBool
js_IsRuntimeLocked(JSRuntime *rt)
{
return js_CurrentThreadId() == rt->rtLockOwner;
}
#endif /* DEBUG */
#endif /* JS_THREADSAFE */

View File

@ -113,30 +113,13 @@ typedef PRLock JSLock;
#define JS_LOCK(cx, tl) js_Lock(cx, tl)
#define JS_UNLOCK(cx, tl) js_Unlock(cx, tl)
#define JS_LOCK_RUNTIME(rt) js_LockRuntime(rt)
#define JS_UNLOCK_RUNTIME(rt) js_UnlockRuntime(rt)
extern void js_Lock(JSContext *cx, JSThinLock *tl);
extern void js_Unlock(JSContext *cx, JSThinLock *tl);
extern void js_LockRuntime(JSRuntime *rt);
extern void js_UnlockRuntime(JSRuntime *rt);
extern int js_SetupLocks(int,int);
extern void js_CleanupLocks();
extern void js_InitLock(JSThinLock *);
extern void js_FinishLock(JSThinLock *);
#ifdef DEBUG
#define JS_IS_RUNTIME_LOCKED(rt) js_IsRuntimeLocked(rt)
extern JSBool js_IsRuntimeLocked(JSRuntime *rt);
#else
#define JS_IS_RUNTIME_LOCKED(rt) 0
#endif /* DEBUG */
#else /* !JS_THREADSAFE */
#define JS_ATOMIC_INCREMENT(p) (++*(p))
@ -158,11 +141,6 @@ extern JSBool js_IsRuntimeLocked(JSRuntime *rt);
#define JS_NOTIFY_CONDVAR(cv) ((void)0)
#define JS_NOTIFY_ALL_CONDVAR(cv) ((void)0)
#define JS_LOCK_RUNTIME(rt) ((void)0)
#define JS_UNLOCK_RUNTIME(rt) ((void)0)
#define JS_IS_RUNTIME_LOCKED(rt) 1
#endif /* !JS_THREADSAFE */
#define JS_LOCK_GC(rt) JS_ACQUIRE_LOCK((rt)->gcLock)