Bug 1432429 Tell the JS Runtime/Workers whether or not Fuzzyfox is enabled 13/14
MozReview-Commit-ID: 6F9sVpOxZUV
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -126,16 +126,17 @@ static_assert(MAX_WORKERS_PER_DOMAIN >=
#define PREF_MAX_SCRIPT_RUN_TIME_CONTENT "dom.max_script_run_time"
#define PREF_MAX_SCRIPT_RUN_TIME_CHROME "dom.max_chrome_script_run_time"
#define GC_REQUEST_OBSERVER_TOPIC "child-gc-request"
#define CC_REQUEST_OBSERVER_TOPIC "child-cc-request"
#define MEMORY_PRESSURE_OBSERVER_TOPIC "memory-pressure"
#define FUZZYFOX_UPDATECLOCK_OBSERVER_TOPIC "fuzzyfox-update-clocks"
+#define FUZZYFOX_UPDATEENABLEDSTATUS_OBSERVER_TOPIC "fuzzyfox-update-status"
#define BROADCAST_ALL_WORKERS(_func, ...) \
PR_BEGIN_MACRO \
AssertIsOnMainThread(); \
\
AutoTArray<WorkerPrivate*, 100> workers; \
{ \
MutexAutoLock lock(mMutex); \
@@ -2557,16 +2558,33 @@ RuntimeService::SendFuzzyFoxClockToAllWo
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
BROADCAST_ALL_WORKERS(UpdateFuzzyFoxClock, newTime);
}
void
+RuntimeService::SendFuzzyFoxEnabledStatusToAllWorkers(nsISupports* aData)
+{
+ nsCOMPtr<nsISupportsPRBool> wrapper = do_QueryInterface(aData);
+ if (NS_WARN_IF(!wrapper)) {
+ return;
+ }
+
+ bool newStatus;
+ nsresult rv = wrapper->GetData(&newStatus);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return;
+ }
+
+ BROADCAST_ALL_WORKERS(UpdateFuzzyFoxEnabledStatus, newStatus);
+}
+
+void
RuntimeService::MemoryPressureAllWorkers()
{
BROADCAST_ALL_WORKERS(MemoryPressure, /* dummy = */ false);
}
uint32_t
RuntimeService::ClampedHardwareConcurrency() const
{
@@ -2632,16 +2650,20 @@ RuntimeService::Observe(nsISupports* aSu
SendOfflineStatusChangeEventToAllWorkers(NS_IsOffline());
return NS_OK;
}
if (!strcmp(aTopic, FUZZYFOX_UPDATECLOCK_OBSERVER_TOPIC)) {
SendFuzzyFoxClockToAllWorkers(aSubject);
return NS_OK;
}
+ if (!strcmp(aTopic, FUZZYFOX_UPDATEENABLEDSTATUS_OBSERVER_TOPIC)) {
+ SendFuzzyFoxEnabledStatusToAllWorkers(aSubject);
+ return NS_OK;
+ }
NS_NOTREACHED("Unknown observer topic!");
return NS_OK;
}
bool
LogViolationDetailsRunnable::MainThreadRun()
{
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -230,16 +230,19 @@ public:
void
SendOfflineStatusChangeEventToAllWorkers(bool aIsOffline);
void
SendFuzzyFoxClockToAllWorkers(nsISupports* aData);
void
+ SendFuzzyFoxEnabledStatusToAllWorkers(nsISupports* aData);
+
+ void
MemoryPressureAllWorkers();
uint32_t ClampedHardwareConcurrency() const;
void CrashIfHanging();
private:
RuntimeService();
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -774,16 +774,35 @@ public:
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
JS_UpdateLockedClock(aCx, mNewTime);
return true;
}
};
+class UpdateFuzzyFoxEnabledStatusRunnable final : public WorkerRunnable
+{
+ bool mNewStatus;
+
+public:
+ UpdateFuzzyFoxEnabledStatusRunnable(WorkerPrivate* aWorkerPrivate,
+ bool aNewStatus)
+ : WorkerRunnable(aWorkerPrivate)
+ , mNewStatus(aNewStatus)
+ {}
+
+ virtual bool
+ WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
+ {
+ JS_UpdateLockedClockEnabledStatus(aCx, mNewStatus);
+ return true;
+ }
+};
+
class UpdateLanguagesRunnable final : public WorkerRunnable
{
nsTArray<nsString> mLanguages;
public:
UpdateLanguagesRunnable(WorkerPrivate* aWorkerPrivate,
const nsTArray<nsString>& aLanguages)
: WorkerRunnable(aWorkerPrivate),
@@ -2219,16 +2238,28 @@ WorkerPrivate::UpdateFuzzyFoxClock(int64
RefPtr<UpdateFuzzyFoxClockRunnable> runnable =
new UpdateFuzzyFoxClockRunnable(this, aNewTime);
if (!runnable->Dispatch()) {
NS_WARNING("Failed to dispatch fuzzy fox clock update event!");
}
}
void
+WorkerPrivate::UpdateFuzzyFoxEnabledStatus(bool aNewStatus)
+{
+ AssertIsOnParentThread();
+
+ RefPtr<UpdateFuzzyFoxEnabledStatusRunnable> runnable =
+ new UpdateFuzzyFoxEnabledStatusRunnable(this, aNewStatus);
+ if (!runnable->Dispatch()) {
+ NS_WARNING("Failed to dispatch fuzzy fox enabled status update event!");
+ }
+}
+
+void
WorkerPrivate::MemoryPressure(bool aDummy)
{
AssertIsOnParentThread();
RefPtr<MemoryPressureRunnable> runnable = new MemoryPressureRunnable(this);
Unused << NS_WARN_IF(!runnable->Dispatch());
}
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -1156,16 +1156,19 @@ public:
#endif
void
OfflineStatusChangeEvent(bool aIsOffline);
void
UpdateFuzzyFoxClock(int64_t aNewTime);
+ void
+ UpdateFuzzyFoxEnabledStatus(bool aNewStatus);
+
nsresult
Dispatch(already_AddRefed<WorkerRunnable> aRunnable,
nsIEventTarget* aSyncLoopTarget = nullptr);
nsresult
DispatchControlRunnable(already_AddRefed<WorkerControlRunnable> aWorkerControlRunnable);
nsresult
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5707,16 +5707,22 @@ JS_RequestInterruptCallbackCanWait(JSCon
}
JS_PUBLIC_API(void)
JS_UpdateLockedClock(JSContext* cx, int64_t update)
{
cx->runtime()->updateLockedClock(update);
}
+JS_PUBLIC_API(void)
+JS_UpdateLockedClockEnabledStatus(JSContext* cx, bool update)
+{
+ cx->runtime()->updateLockedClockEnabledStatus(update);
+}
+
JS::AutoSetAsyncStackForNewCalls::AutoSetAsyncStackForNewCalls(
JSContext* cx, HandleObject stack, const char* asyncCause,
JS::AutoSetAsyncStackForNewCalls::AsyncCallKind kind)
: cx(cx),
oldAsyncStack(cx, cx->asyncStackForNewActivations()),
oldAsyncCause(cx->asyncCauseForNewActivations),
oldAsyncCallIsExplicit(cx->asyncCallIsExplicit)
{
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5486,16 +5486,19 @@ extern JS_PUBLIC_API(void)
JS_SetPendingException(JSContext* cx, JS::HandleValue v);
extern JS_PUBLIC_API(void)
JS_ClearPendingException(JSContext* cx);
extern JS_PUBLIC_API(void)
JS_UpdateLockedClock(JSContext* cx, int64_t update);
+extern JS_PUBLIC_API(void)
+JS_UpdateLockedClockEnabledStatus(JSContext* cx, bool update);
+
namespace JS {
/**
* Save and later restore the current exception state of a given JSContext.
* This is useful for implementing behavior in C++ that's like try/catch
* or try/finally in JS.
*
* Typical usage:
--- a/js/src/vm/FuzzyfoxClock.h
+++ b/js/src/vm/FuzzyfoxClock.h
@@ -23,21 +23,40 @@ class FuzzyfoxClock
}
bool
isClockStarted() const
{
return currentClock;
}
+ bool
+ getEnabled() const
+ {
+ return enabled;
+ }
+
+ void
+ setEnabled(bool update)
+ {
+ enabled = update;
+ }
+
void
updateFuzzyfoxClock(int64_t update)
{
+ // We assume that if we send out a fuzzyfox update on a new object
+ // that FuzzyFox is enabled, and this is how we enabled it to begin with
+ if (!isClockStarted()) {
+ setEnabled(true);
+ }
+
currentClock = update;
}
private:
+ bool enabled;
int64_t currentClock;
};
} // js namespace
#endif /* FuzzyfoxClock_h*/
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -812,22 +812,34 @@ JSRuntime::setUsedByHelperThread(Zone* z
}
void
JSRuntime::updateLockedClock(int64_t update)
{
fuzzyfoxClock.updateFuzzyfoxClock(update);
}
+void
+JSRuntime::updateLockedClockEnabledStatus(bool update)
+{
+ fuzzyfoxClock.setEnabled(update);
+}
+
bool
JSRuntime::hasValidFuzzyfoxClock() const
{
return fuzzyfoxClock.isClockStarted();
}
+bool
+JSRuntime::getFuzzyfoxEnabled() const
+{
+ return fuzzyfoxClock.getEnabled();
+}
+
int64_t
JSRuntime::getFuzzyfoxClock() const
{
return fuzzyfoxClock.getFuzzyfoxClock();
}
void
JSRuntime::clearUsedByHelperThread(Zone* zone)
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -965,16 +965,18 @@ struct JSRuntime : public js::MallocProv
// in this runtime will trigger the call to `interceptor`
JSErrorInterceptor* interceptor;
};
ErrorInterceptionSupport errorInterception;
#endif // defined(NIGHTLY_BUILD)
public:
void updateLockedClock(int64_t update);
+ void updateLockedClockEnabledStatus(bool update);
+ bool getFuzzyfoxEnabled() const;
bool hasValidFuzzyfoxClock() const;
int64_t getFuzzyfoxClock() const;
private:
js::FuzzyfoxClock fuzzyfoxClock;
};
namespace js {
--- a/js/src/vm/Time.cpp
+++ b/js/src/vm/Time.cpp
@@ -45,28 +45,32 @@ extern int gettimeofday(struct timeval*
using mozilla::DebugOnly;
#if defined(XP_UNIX)
int64_t
PRMJ_Now()
{
JSContext* cx = js::TlsContext.get();
- if (cx && cx->runtime()->hasValidFuzzyfoxClock())
+ if (cx && cx->runtime() && cx->runtime()->getFuzzyfoxEnabled() && cx->runtime()->hasValidFuzzyfoxClock())
return cx->runtime()->getFuzzyfoxClock();
struct timeval tv;
#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
gettimeofday(&tv);
#else
gettimeofday(&tv, 0);
#endif /* _SVID_GETTOD */
- return int64_t(tv.tv_sec) * PRMJ_USEC_PER_SEC + int64_t(tv.tv_usec);
+ int64_t now = int64_t(tv.tv_sec) * PRMJ_USEC_PER_SEC + int64_t(tv.tv_usec);
+
+ if (cx && cx->runtime() && cx->runtime()->hasValidFuzzyfoxClock())
+ return cx->runtime()->getFuzzyfoxClock() > now ? cx->runtime()->getFuzzyfoxClock() : now;
+ return now;
}
#else
// Returns the number of microseconds since the Unix epoch.
static double
FileTimeToUnixMicroseconds(const FILETIME& ft)
{
@@ -155,24 +159,27 @@ PRMJ_NowShutdown()
#define MUTEX_UNLOCK(m) LeaveCriticalSection(m)
#define MUTEX_SETSPINCOUNT(m, c) SetCriticalSectionSpinCount((m),(c))
// Please see bug 363258 for why the win32 timing code is so complex.
int64_t
PRMJ_Now()
{
JSContext* cx = js::TlsContext.get();
- if (cx && cx->runtime()->hasValidFuzzyfoxClock())
+ if (cx && cx->runtime() && cx->runtime()->getFuzzyfoxEnabled() && cx->runtime()->hasValidFuzzyfoxClock())
return cx->runtime()->getFuzzyfoxClock();
if (pGetSystemTimePreciseAsFileTime) {
// Windows 8 has a new API function that does all the work.
FILETIME ft;
pGetSystemTimePreciseAsFileTime(&ft);
- return int64_t(FileTimeToUnixMicroseconds(ft));
+ int64_t now = int64_t(FileTimeToUnixMicroseconds(ft));
+ if (cx && cx->runtime() && cx->runtime()->hasValidFuzzyfoxClock())
+ return cx->runtime()->getFuzzyfoxClock() > now ? cx->runtime()->getFuzzyfoxClock() : now;
+ return now;
}
bool calibrated = false;
bool needsCalibration = !calibration.calibrated;
double cachedOffset = 0.0;
while (true) {
if (needsCalibration) {
MUTEX_LOCK(&calibration.data_lock);
@@ -222,30 +229,36 @@ PRMJ_Now()
// For some reason that I have not determined, the skew can be
// up to twice a kernel tick. This does not seem to happen by
// itself, but I have only seen it triggered by another program
// doing some kind of file I/O. The symptoms are a negative diff
// followed by an equally large positive diff.
if (mozilla::Abs(diff) <= 2 * KernelTickInMicroseconds) {
// No detectable clock skew.
- return int64_t(highresTime);
+ int64_t now = int64_t(highresTime);
+ if (cx && cx->runtime() && cx->runtime()->hasValidFuzzyfoxClock())
+ return cx->runtime()->getFuzzyfoxClock() > now ? cx->runtime()->getFuzzyfoxClock() : now;
+ return now;
}
if (calibrated) {
// If we already calibrated once this instance, and the
// clock is still skewed, then either the processor(s) are
// wildly changing clockspeed or the system is so busy that
// we get switched out for long periods of time. In either
// case, it would be infeasible to make use of high
// resolution results for anything, so let's resort to old
// behavior for this call. It's possible that in the
// future, the user will want the high resolution timer, so
// we don't disable it entirely.
- return int64_t(lowresTime);
+ int64_t now = int64_t(lowresTime);
+ if (cx && cx->runtime() && cx->runtime()->hasValidFuzzyfoxClock())
+ return cx->runtime()->getFuzzyfoxClock() > now ? cx->runtime()->getFuzzyfoxClock() : now;
+ return now;
}
// It is possible that when we recalibrate, we will return a
// value less than what we have returned before; this is
// unavoidable. We cannot tell the different between a
// faulty QueryPerformanceCounter implementation and user
// changes to the operating system time. Since we must
// respect user changes to the operating system time, we
--- a/js/xpconnect/src/FuzzyfoxClockUpdater.cpp
+++ b/js/xpconnect/src/FuzzyfoxClockUpdater.cpp
@@ -59,38 +59,54 @@ FuzzyfoxClockUpdater::Initialize()
}
NS_IMETHODIMP
FuzzyfoxClockUpdater::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{
MOZ_ASSERT(NS_IsMainThread());
- if (!strcmp(aTopic, "fuzzyfox-update-clocks")) {
- nsCOMPtr<nsISupportsPRInt64> wrapper = do_QueryInterface(aSubject);
- if (NS_WARN_IF(!wrapper)) {
- return NS_OK;
- }
-
- int64_t newTime = 0;
- nsresult rv = wrapper->GetData(&newTime);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return NS_OK;
- }
-
+ if (!strcmp(aTopic, "fuzzyfox-update-clocks") || !strcmp(aTopic, "fuzzyfox-update-status")) {
CycleCollectedJSContext* ccjscx = CycleCollectedJSContext::Get();
if (!ccjscx) {
return NS_OK;
}
JSContext* cx = ccjscx->Context();
MOZ_ASSERT(cx);
- JS_UpdateLockedClock(cx, newTime);
- return NS_OK;
+ if (!strcmp(aTopic, "fuzzyfox-update-clocks")) {
+ nsCOMPtr<nsISupportsPRInt64> wrapper = do_QueryInterface(aSubject);
+ if (NS_WARN_IF(!wrapper)) {
+ return NS_OK;
+ }
+
+ int64_t newTime = 0;
+ nsresult rv = wrapper->GetData(&newTime);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return NS_OK;
+ }
+
+ JS_UpdateLockedClock(cx, newTime);
+ return NS_OK;
+ } else {
+ nsCOMPtr<nsISupportsPRBool> wrapper = do_QueryInterface(aSubject);
+ if (NS_WARN_IF(!wrapper)) {
+ return NS_OK;
+ }
+
+ bool newStatus = false;
+ nsresult rv = wrapper->GetData(&newStatus);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return NS_OK;
+ }
+
+ JS_UpdateLockedClockEnabledStatus(cx, newStatus);
+ return NS_OK;
+ }
}
MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
Shutdown();
return NS_OK;
}
void
--- a/toolkit/components/fuzzyfox/Fuzzyfox.cpp
+++ b/toolkit/components/fuzzyfox/Fuzzyfox.cpp
@@ -119,16 +119,22 @@ Fuzzyfox::Fuzzyfox()
FUZZYFOX_DURATION_PREF,
FUZZYFOX_DURATION_PREF_DEFAULT);
LOG(Info, ("PT(%p) Created Fuzzyfox, sFuzzyfoxEnabled is now %s \n",
this, (sFuzzyfoxEnabledPrefMapped ? "enabled" : "disabled")));
TimeStamp::SetFuzzyfoxEnabled(sFuzzyfoxEnabledPrefMapped);
+ nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+ nsCOMPtr<nsISupportsPRBool> wrapper =
+ do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
+ wrapper->SetData(sFuzzyfoxEnabledPrefMapped);
+ os->NotifyObservers(wrapper, "fuzzyfox-update-status", nullptr);
+
// Should I see if these fail? And do what?
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
prefs->AddObserver(FUZZYFOX_ENABLED_PREF, this, false);
prefs->AddObserver(FUZZYFOX_CLOCKGRAIN_PREF, this, false);
prefs->AddObserver(FUZZYFOX_DURATION_PREF, this, false);
}
Fuzzyfox::~Fuzzyfox() = default;
@@ -143,16 +149,29 @@ Fuzzyfox::Observe(nsISupports* aObject,
if (pref.EqualsLiteral(FUZZYFOX_ENABLED_PREF)) {
LOG(Info, ("PT(%p) Observed a pref change, sFuzzyfoxEnabled is now %s \n",
this, (sFuzzyfoxEnabledPrefMapped ? "enabled" : "disabled")));
TimeStamp::SetFuzzyfoxEnabled(sFuzzyfoxEnabledPrefMapped);
+ nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+ if (NS_WARN_IF(!os)) {
+ return NS_OK; // [[what do i return if this stuff fails?]]
+ }
+ nsCOMPtr<nsISupportsPRBool> wrapper =
+ do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
+ if (NS_WARN_IF(!wrapper)) {
+ return NS_OK; // [[what do i return if this stuff fails?]]
+ }
+ wrapper->SetData(sFuzzyfoxEnabledPrefMapped);
+ os->NotifyObservers(wrapper, "fuzzyfox-update-status", nullptr);
+
+
if (TimeStamp::GetFuzzyfoxEnabled()) {
// Queue a runnable
nsCOMPtr<nsIRunnable> r = this;
SystemGroup::Dispatch(TaskCategory::Other, r.forget());
} else {
mStartTime = 0;
mTickType = eUptick;
mSanityCheck = false;