Bug 568730 - Allow customizing the sleep duration in XPCJSRuntime::WatchdogMain. r=igor/jst/gal

This commit is contained in:
Alon Zakai 2010-08-09 16:39:28 -07:00
parent 71cf6e222a
commit 8ba541a087
4 changed files with 59 additions and 4 deletions

View File

@ -805,6 +805,9 @@ JS_BeginRequest(JSContext *cx)
cx->outstandingRequests++; cx->outstandingRequests++;
cx->thread->requestContext = cx; cx->thread->requestContext = cx;
rt->requestCount++; rt->requestCount++;
if (rt->requestCount == 1)
rt->activityCallback(rt->activityCallbackArg, true);
} }
#endif #endif
} }
@ -853,8 +856,10 @@ StopRequest(JSContext *cx)
/* Give the GC a chance to run if this was the last request running. */ /* Give the GC a chance to run if this was the last request running. */
JS_ASSERT(rt->requestCount > 0); JS_ASSERT(rt->requestCount > 0);
rt->requestCount--; rt->requestCount--;
if (rt->requestCount == 0) if (rt->requestCount == 0) {
JS_NOTIFY_REQUEST_DONE(rt); JS_NOTIFY_REQUEST_DONE(rt);
rt->activityCallback(rt->activityCallbackArg, false);
}
} }
} }
#endif #endif

View File

@ -1218,6 +1218,9 @@ struct JSCompartment {
void sweep(JSContext *cx); void sweep(JSContext *cx);
}; };
typedef void
(* JSActivityCallback)(void *arg, JSBool active);
struct JSRuntime { struct JSRuntime {
/* Default compartment. */ /* Default compartment. */
JSCompartment *defaultCompartment; JSCompartment *defaultCompartment;
@ -1234,6 +1237,20 @@ struct JSRuntime {
/* Compartment create/destroy callback. */ /* Compartment create/destroy callback. */
JSCompartmentCallback compartmentCallback; JSCompartmentCallback compartmentCallback;
/*
* Sets a callback that is run whenever the runtime goes idle - the
* last active request ceases - and begins activity - when it was
* idle and a request begins. Note: The callback is called under the
* GC lock.
*/
void setActivityCallback(JSActivityCallback cb, void *arg) {
activityCallback = cb;
activityCallbackArg = arg;
}
JSActivityCallback activityCallback;
void *activityCallbackArg;
/* /*
* Shape regenerated whenever a prototype implicated by an "add property" * Shape regenerated whenever a prototype implicated by an "add property"
* property cache fill and induced trace guard has a readonly property or a * property cache fill and induced trace guard has a readonly property or a

View File

@ -803,14 +803,22 @@ XPCJSRuntime::WatchdogMain(void *arg)
// Lock lasts until we return // Lock lasts until we return
AutoLockJSGC lock(self->mJSRuntime); AutoLockJSGC lock(self->mJSRuntime);
PRIntervalTime sleepInterval;
while (self->mWatchdogThread) while (self->mWatchdogThread)
{ {
// Sleep only 1 second if recently (or currently) active; otherwise, hibernate
if (self->mLastActiveTime == -1 || PR_Now() - self->mLastActiveTime <= 2*PR_USEC_PER_SEC)
sleepInterval = PR_TicksPerSecond();
else
{
sleepInterval = PR_INTERVAL_NO_TIMEOUT;
self->mWatchdogHibernating = PR_TRUE;
}
#ifdef DEBUG #ifdef DEBUG
PRStatus status = PRStatus status =
#endif #endif
PR_WaitCondVar(self->mWatchdogWakeup, PR_TicksPerSecond()); PR_WaitCondVar(self->mWatchdogWakeup, sleepInterval);
JS_ASSERT(status == PR_SUCCESS); JS_ASSERT(status == PR_SUCCESS);
JSContext* cx = nsnull; JSContext* cx = nsnull;
while((cx = js_NextActiveContext(self->mJSRuntime, cx))) while((cx = js_NextActiveContext(self->mJSRuntime, cx)))
{ {
@ -822,6 +830,23 @@ XPCJSRuntime::WatchdogMain(void *arg)
PR_NotifyCondVar(self->mWatchdogWakeup); PR_NotifyCondVar(self->mWatchdogWakeup);
} }
//static
void
XPCJSRuntime::ActivityCallback(void *arg, PRBool active)
{
XPCJSRuntime* self = static_cast<XPCJSRuntime*>(arg);
if (active) {
self->mLastActiveTime = -1;
if (self->mWatchdogHibernating)
{
self->mWatchdogHibernating = PR_FALSE;
PR_NotifyCondVar(self->mWatchdogWakeup);
}
} else {
self->mLastActiveTime = PR_Now();
}
}
/***************************************************************************/ /***************************************************************************/
@ -1108,7 +1133,9 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
mWrappedJSRoots(nsnull), mWrappedJSRoots(nsnull),
mObjectHolderRoots(nsnull), mObjectHolderRoots(nsnull),
mWatchdogWakeup(nsnull), mWatchdogWakeup(nsnull),
mWatchdogThread(nsnull) mWatchdogThread(nsnull),
mWatchdogHibernating(PR_FALSE),
mLastActiveTime(-1)
{ {
#ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
DEBUG_WrappedNativeHashtable = DEBUG_WrappedNativeHashtable =
@ -1138,6 +1165,8 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
JS_SetExtraGCRoots(mJSRuntime, TraceJS, this); JS_SetExtraGCRoots(mJSRuntime, TraceJS, this);
mWatchdogWakeup = JS_NEW_CONDVAR(mJSRuntime->gcLock); mWatchdogWakeup = JS_NEW_CONDVAR(mJSRuntime->gcLock);
mJSRuntime->setActivityCallback(ActivityCallback, this);
mJSRuntime->setCustomGCChunkAllocator(&gXPCJSChunkAllocator); mJSRuntime->setCustomGCChunkAllocator(&gXPCJSChunkAllocator);
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSRuntimeGCChunks)); NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSRuntimeGCChunks));

View File

@ -720,6 +720,8 @@ public:
void AddGCCallback(JSGCCallback cb); void AddGCCallback(JSGCCallback cb);
void RemoveGCCallback(JSGCCallback cb); void RemoveGCCallback(JSGCCallback cb);
static void ActivityCallback(void *arg, PRBool active);
private: private:
XPCJSRuntime(); // no implementation XPCJSRuntime(); // no implementation
XPCJSRuntime(nsXPConnect* aXPConnect); XPCJSRuntime(nsXPConnect* aXPConnect);
@ -758,6 +760,8 @@ private:
PRCondVar *mWatchdogWakeup; PRCondVar *mWatchdogWakeup;
PRThread *mWatchdogThread; PRThread *mWatchdogThread;
nsTArray<JSGCCallback> extraGCCallbacks; nsTArray<JSGCCallback> extraGCCallbacks;
PRBool mWatchdogHibernating;
PRTime mLastActiveTime; // -1 if active NOW
}; };
/***************************************************************************/ /***************************************************************************/