mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1203427 (part 5) - Add logging of timer firings. r=froydnj.
This commit is contained in:
parent
c65f0f318a
commit
09b4a9e997
@ -53,6 +53,7 @@
|
||||
#include "ScriptSettings.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/Snprintf.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
// Other Classes
|
||||
@ -545,8 +546,9 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTimeout, Release)
|
||||
nsresult
|
||||
nsTimeout::InitTimer(uint32_t aDelay)
|
||||
{
|
||||
return mTimer->InitWithFuncCallback(nsGlobalWindow::TimerCallback, this,
|
||||
aDelay, nsITimer::TYPE_ONE_SHOT);
|
||||
return mTimer->InitWithNameableFuncCallback(
|
||||
nsGlobalWindow::TimerCallback, this, aDelay,
|
||||
nsITimer::TYPE_ONE_SHOT, nsGlobalWindow::TimerNameCallback);
|
||||
}
|
||||
|
||||
// Return true if this timeout has a refcount of 1. This is used to check
|
||||
@ -13161,6 +13163,19 @@ nsGlobalWindow::TimerCallback(nsITimer *aTimer, void *aClosure)
|
||||
timeout->mWindow->RunTimeout(timeout);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
nsGlobalWindow::TimerNameCallback(nsITimer* aTimer, void* aClosure, char* aBuf,
|
||||
size_t aLen)
|
||||
{
|
||||
nsRefPtr<nsTimeout> timeout = (nsTimeout*)aClosure;
|
||||
|
||||
const char* filename;
|
||||
uint32_t lineNum, column;
|
||||
timeout->mScriptHandler->GetLocation(&filename, &lineNum, &column);
|
||||
snprintf(aBuf, aLen, "[content] %s:%u:%u", filename, lineNum, column);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsGlobalWindow: Helper Functions
|
||||
//*****************************************************************************
|
||||
|
@ -1424,6 +1424,8 @@ public:
|
||||
// fire after it, but no earlier than mTimeoutInsertionPoint, if any.
|
||||
void InsertTimeoutIntoList(nsTimeout *aTimeout);
|
||||
static void TimerCallback(nsITimer *aTimer, void *aClosure);
|
||||
static void TimerNameCallback(nsITimer* aTimer, void* aClosure, char* aBuf,
|
||||
size_t aLen);
|
||||
|
||||
// Helper Functions
|
||||
already_AddRefed<nsIDocShellTreeOwner> GetTreeOwner();
|
||||
|
@ -1636,10 +1636,10 @@ nsJSContext::BeginCycleCollectionCallback()
|
||||
// an incremental collection, and we want to be sure to finish it.
|
||||
CallCreateInstance("@mozilla.org/timer;1", &sICCTimer);
|
||||
if (sICCTimer) {
|
||||
sICCTimer->InitWithFuncCallback(ICCTimerFired,
|
||||
nullptr,
|
||||
kICCIntersliceDelay,
|
||||
nsITimer::TYPE_REPEATING_SLACK);
|
||||
sICCTimer->InitWithNamedFuncCallback(ICCTimerFired, nullptr,
|
||||
kICCIntersliceDelay,
|
||||
nsITimer::TYPE_REPEATING_SLACK,
|
||||
"ICCTimerFired");
|
||||
}
|
||||
}
|
||||
|
||||
@ -2036,14 +2036,15 @@ nsJSContext::PokeGC(JS::gcreason::Reason aReason, int aDelay)
|
||||
|
||||
static bool first = true;
|
||||
|
||||
sGCTimer->InitWithFuncCallback(GCTimerFired, reinterpret_cast<void *>(aReason),
|
||||
aDelay
|
||||
? aDelay
|
||||
: (first
|
||||
? NS_FIRST_GC_DELAY
|
||||
: NS_GC_DELAY),
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
|
||||
sGCTimer->InitWithNamedFuncCallback(GCTimerFired,
|
||||
reinterpret_cast<void *>(aReason),
|
||||
aDelay
|
||||
? aDelay
|
||||
: (first
|
||||
? NS_FIRST_GC_DELAY
|
||||
: NS_GC_DELAY),
|
||||
nsITimer::TYPE_ONE_SHOT,
|
||||
"GCTimerFired");
|
||||
first = false;
|
||||
}
|
||||
|
||||
@ -2062,9 +2063,11 @@ nsJSContext::PokeShrinkGCBuffers()
|
||||
return;
|
||||
}
|
||||
|
||||
sShrinkGCBuffersTimer->InitWithFuncCallback(ShrinkGCBuffersTimerFired, nullptr,
|
||||
NS_SHRINK_GC_BUFFERS_DELAY,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
sShrinkGCBuffersTimer->InitWithNamedFuncCallback(ShrinkGCBuffersTimerFired,
|
||||
nullptr,
|
||||
NS_SHRINK_GC_BUFFERS_DELAY,
|
||||
nsITimer::TYPE_ONE_SHOT,
|
||||
"ShrinkGCBuffersTimerFired");
|
||||
}
|
||||
|
||||
// static
|
||||
@ -2082,9 +2085,10 @@ nsJSContext::PokeShrinkingGC()
|
||||
return;
|
||||
}
|
||||
|
||||
sShrinkingGCTimer->InitWithFuncCallback(ShrinkingGCTimerFired, nullptr,
|
||||
sCompactOnUserInactiveDelay,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
sShrinkingGCTimer->InitWithNamedFuncCallback(ShrinkingGCTimerFired, nullptr,
|
||||
sCompactOnUserInactiveDelay,
|
||||
nsITimer::TYPE_ONE_SHOT,
|
||||
"ShrinkingGCTimerFired");
|
||||
}
|
||||
|
||||
// static
|
||||
@ -2104,9 +2108,10 @@ nsJSContext::MaybePokeCC()
|
||||
// We can kill some objects before running forgetSkippable.
|
||||
nsCycleCollector_dispatchDeferredDeletion();
|
||||
|
||||
sCCTimer->InitWithFuncCallback(CCTimerFired, nullptr,
|
||||
NS_CC_SKIPPABLE_DELAY,
|
||||
nsITimer::TYPE_REPEATING_SLACK);
|
||||
sCCTimer->InitWithNamedFuncCallback(CCTimerFired, nullptr,
|
||||
NS_CC_SKIPPABLE_DELAY,
|
||||
nsITimer::TYPE_REPEATING_SLACK,
|
||||
"CCTimerFired");
|
||||
}
|
||||
}
|
||||
|
||||
@ -2263,10 +2268,11 @@ DOMGCSliceCallback(JSRuntime *aRt, JS::GCProgress aProgress, const JS::GCDescrip
|
||||
if (aDesc.isCompartment_) {
|
||||
if (!sFullGCTimer && !sShuttingDown) {
|
||||
CallCreateInstance("@mozilla.org/timer;1", &sFullGCTimer);
|
||||
sFullGCTimer->InitWithFuncCallback(FullGCTimerFired,
|
||||
nullptr,
|
||||
NS_FULL_GC_DELAY,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
sFullGCTimer->InitWithNamedFuncCallback(FullGCTimerFired,
|
||||
nullptr,
|
||||
NS_FULL_GC_DELAY,
|
||||
nsITimer::TYPE_ONE_SHOT,
|
||||
"FullGCTimerFired");
|
||||
}
|
||||
} else {
|
||||
nsJSContext::KillFullGCTimer();
|
||||
@ -2295,10 +2301,11 @@ DOMGCSliceCallback(JSRuntime *aRt, JS::GCProgress aProgress, const JS::GCDescrip
|
||||
nsJSContext::KillInterSliceGCTimer();
|
||||
if (!sShuttingDown) {
|
||||
CallCreateInstance("@mozilla.org/timer;1", &sInterSliceGCTimer);
|
||||
sInterSliceGCTimer->InitWithFuncCallback(InterSliceGCTimerFired,
|
||||
nullptr,
|
||||
NS_INTERSLICE_GC_DELAY,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
sInterSliceGCTimer->InitWithNamedFuncCallback(InterSliceGCTimerFired,
|
||||
nullptr,
|
||||
NS_INTERSLICE_GC_DELAY,
|
||||
nsITimer::TYPE_ONE_SHOT,
|
||||
"InterSliceGCTimerFired");
|
||||
}
|
||||
|
||||
if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
|
||||
|
@ -3522,10 +3522,9 @@ void HTMLMediaElement::StartProgressTimer()
|
||||
NS_ASSERTION(!mProgressTimer, "Already started progress timer.");
|
||||
|
||||
mProgressTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
mProgressTimer->InitWithFuncCallback(ProgressTimerCallback,
|
||||
this,
|
||||
PROGRESS_MS,
|
||||
nsITimer::TYPE_REPEATING_SLACK);
|
||||
mProgressTimer->InitWithNamedFuncCallback(
|
||||
ProgressTimerCallback, this, PROGRESS_MS, nsITimer::TYPE_REPEATING_SLACK,
|
||||
"HTMLMediaElement::ProgressTimerCallback");
|
||||
}
|
||||
|
||||
void HTMLMediaElement::StartProgress()
|
||||
|
@ -174,7 +174,9 @@ MediaTimer::ArmTimer(const TimeStamp& aTarget, const TimeStamp& aNow)
|
||||
unsigned long delay = std::ceil((aTarget - aNow).ToMilliseconds());
|
||||
TIMER_LOG("MediaTimer::ArmTimer delay=%lu", delay);
|
||||
mCurrentTimerTarget = aTarget;
|
||||
nsresult rv = mTimer->InitWithFuncCallback(&TimerCallback, this, delay, nsITimer::TYPE_ONE_SHOT);
|
||||
nsresult rv = mTimer->InitWithNamedFuncCallback(&TimerCallback, this, delay,
|
||||
nsITimer::TYPE_ONE_SHOT,
|
||||
"MediaTimer::TimerCallback");
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
(void) rv;
|
||||
}
|
||||
|
@ -1188,8 +1188,9 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_FAILED(timer->InitWithFuncCallback(DummyCallback, nullptr, aDelayMS,
|
||||
nsITimer::TYPE_ONE_SHOT))) {
|
||||
if (NS_FAILED(timer->InitWithNamedFuncCallback(
|
||||
DummyCallback, nullptr, aDelayMS, nsITimer::TYPE_ONE_SHOT,
|
||||
"dom::workers::DummyCallback(1)"))) {
|
||||
JS_ReportError(aCx, "Failed to start timer!");
|
||||
return false;
|
||||
}
|
||||
@ -4536,9 +4537,9 @@ WorkerPrivate::SetGCTimerMode(GCTimerMode aMode)
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mGCTimer->SetTarget(target)));
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mGCTimer->InitWithFuncCallback(DummyCallback,
|
||||
nullptr, delay,
|
||||
type)));
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
mGCTimer->InitWithNamedFuncCallback(DummyCallback, nullptr, delay, type,
|
||||
"dom::workers::DummyCallback(2)")));
|
||||
|
||||
if (aMode == PeriodicTimer) {
|
||||
LOG(("Worker %p scheduled periodic GC timer\n", this));
|
||||
@ -5945,8 +5946,9 @@ WorkerPrivate::RescheduleTimeoutTimer(JSContext* aCx)
|
||||
(mTimeouts[0]->mTargetTime - TimeStamp::Now()).ToMilliseconds();
|
||||
uint32_t delay = delta > 0 ? std::min(delta, double(UINT32_MAX)) : 0;
|
||||
|
||||
nsresult rv = mTimer->InitWithFuncCallback(DummyCallback, nullptr, delay,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
nsresult rv = mTimer->InitWithNamedFuncCallback(
|
||||
DummyCallback, nullptr, delay, nsITimer::TYPE_ONE_SHOT,
|
||||
"dom::workers::DummyCallback(3)");
|
||||
if (NS_FAILED(rv)) {
|
||||
JS_ReportError(aCx, "Failed to start timer!");
|
||||
return false;
|
||||
|
@ -1748,9 +1748,9 @@ PresShell::Initialize(nscoord aWidth, nscoord aHeight)
|
||||
Preferences::GetInt("nglayout.initialpaint.delay",
|
||||
PAINTLOCK_EVENT_DELAY);
|
||||
|
||||
mPaintSuppressionTimer->InitWithFuncCallback(sPaintSuppressionCallback,
|
||||
this, delay,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
mPaintSuppressionTimer->InitWithNamedFuncCallback(
|
||||
sPaintSuppressionCallback, this, delay, nsITimer::TYPE_ONE_SHOT,
|
||||
"PresShell::sPaintSuppressionCallback");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -426,9 +426,9 @@ ScrollbarActivity::StartFadeBeginTimer()
|
||||
if (!mFadeBeginTimer) {
|
||||
mFadeBeginTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
}
|
||||
mFadeBeginTimer->InitWithFuncCallback(FadeBeginTimerFired, this,
|
||||
mScrollbarFadeBeginDelay,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
mFadeBeginTimer->InitWithNamedFuncCallback(
|
||||
FadeBeginTimerFired, this, mScrollbarFadeBeginDelay,
|
||||
nsITimer::TYPE_ONE_SHOT, "ScrollbarActivity::FadeBeginTimerFired");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -275,8 +275,9 @@ nsHtml5TreeOpExecutor::ContinueInterruptedParsingAsync()
|
||||
// The timer value 50 should not hopefully slow down background pages too
|
||||
// much, yet lets event loop to process enough between ticks.
|
||||
// See bug 734015.
|
||||
gFlushTimer->InitWithFuncCallback(FlushTimerCallback, nullptr,
|
||||
50, nsITimer::TYPE_REPEATING_SLACK);
|
||||
gFlushTimer->InitWithNamedFuncCallback(FlushTimerCallback, nullptr,
|
||||
50, nsITimer::TYPE_REPEATING_SLACK,
|
||||
"FlushTimerCallback");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -355,8 +355,9 @@ nsBrowserStatusFilter::StartDelayTimer()
|
||||
if (!mTimer)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return mTimer->InitWithFuncCallback(TimeoutHandler, this, 160,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
return mTimer->InitWithNamedFuncCallback(
|
||||
TimeoutHandler, this, 160, nsITimer::TYPE_ONE_SHOT,
|
||||
"nsBrowserStatusFilter::TimeoutHandler");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -360,8 +360,8 @@ private:
|
||||
if (!mTimer) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
mTimer->InitWithFuncCallback(TimerCallback, this, mTimerPeriod,
|
||||
nsITimer::TYPE_REPEATING_SLACK);
|
||||
mTimer->InitWithNamedFuncCallback(TimerCallback, this, mTimerPeriod,
|
||||
nsITimer::TYPE_REPEATING_SLACK, mName);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
@ -21,9 +21,24 @@ interface nsIEventTarget;
|
||||
*/
|
||||
class nsITimer;
|
||||
typedef void (*nsTimerCallbackFunc) (nsITimer *aTimer, void *aClosure);
|
||||
|
||||
/**
|
||||
* The signature of the timer name callback function passed to
|
||||
* initWithNameableFuncCallback.
|
||||
* This is the function that will get called when timer profiling is enabled
|
||||
* via the "TimerFirings" log module.
|
||||
*
|
||||
* @param aTimer the timer which has expired
|
||||
* @param aClosure opaque parameter passed to initWithFuncCallback
|
||||
* @param aBuf a buffer in which to put the name
|
||||
* @param aLen the length of the buffer
|
||||
*/
|
||||
typedef void (*nsTimerNameCallbackFunc) (nsITimer *aTimer, void *aClosure,
|
||||
char *aBuf, size_t aLen);
|
||||
%}
|
||||
|
||||
native nsTimerCallbackFunc(nsTimerCallbackFunc);
|
||||
native nsTimerNameCallbackFunc(nsTimerNameCallbackFunc);
|
||||
|
||||
/**
|
||||
* The callback interface for timers.
|
||||
@ -57,7 +72,7 @@ interface nsITimerCallback : nsISupports
|
||||
* target thread, or races may occur with bad results like timers firing after
|
||||
* they've been canceled, and/or not firing after re-initiatization.
|
||||
*/
|
||||
[scriptable, uuid(c569e813-333f-4b78-8691-13ca5839e10a)]
|
||||
[scriptable, uuid(3de4b105-363c-482c-a409-baac83a01bfc)]
|
||||
interface nsITimer : nsISupports
|
||||
{
|
||||
/* Timer types */
|
||||
@ -151,6 +166,40 @@ interface nsITimer : nsISupports
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* Like initWithFuncCallback, but also takes a name for the timer; the name
|
||||
* will be used when timer profiling is enabled via the "TimerFirings" log
|
||||
* module.
|
||||
*
|
||||
* @param aFunc The function to invoke
|
||||
* @param aClosure An opaque pointer to pass to that function
|
||||
* @param aDelay The millisecond interval
|
||||
* @param aType Timer type per TYPE* consts defined above
|
||||
* @param aName The timer's name
|
||||
*/
|
||||
[noscript] void initWithNamedFuncCallback(in nsTimerCallbackFunc aCallback,
|
||||
in voidPtr aClosure,
|
||||
in unsigned long aDelay,
|
||||
in unsigned long aType,
|
||||
in string aName);
|
||||
|
||||
/**
|
||||
* Like initWithNamedFuncCallback, but instead of a timer name it takes a
|
||||
* callback that will provide a name when the timer fires.
|
||||
*
|
||||
* @param aFunc The function to invoke
|
||||
* @param aClosure An opaque pointer to pass to that function
|
||||
* @param aDelay The millisecond interval
|
||||
* @param aType Timer type per TYPE* consts defined above
|
||||
* @param aNameCallback The callback function
|
||||
*/
|
||||
[noscript] void initWithNameableFuncCallback(
|
||||
in nsTimerCallbackFunc aCallback,
|
||||
in voidPtr aClosure,
|
||||
in unsigned long aDelay,
|
||||
in unsigned long aType,
|
||||
in nsTimerNameCallbackFunc aNameCallback);
|
||||
|
||||
/**
|
||||
* The millisecond delay of the timeout.
|
||||
*
|
||||
|
@ -21,6 +21,15 @@
|
||||
using namespace mozilla::tasktracer;
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <process.h>
|
||||
#ifndef getpid
|
||||
#define getpid _getpid
|
||||
#endif
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
using mozilla::Atomic;
|
||||
using mozilla::LogLevel;
|
||||
using mozilla::TimeDuration;
|
||||
@ -29,6 +38,7 @@ using mozilla::TimeStamp;
|
||||
static Atomic<int32_t> gGenerator;
|
||||
static TimerThread* gThread = nullptr;
|
||||
|
||||
// This module prints info about the precision of timers.
|
||||
PRLogModuleInfo*
|
||||
GetTimerLog()
|
||||
{
|
||||
@ -39,6 +49,44 @@ GetTimerLog()
|
||||
return sLog;
|
||||
}
|
||||
|
||||
// This module prints info about which timers are firing, which is useful for
|
||||
// wakeups for the purposes of power profiling. Set the following environment
|
||||
// variable before starting the browser.
|
||||
//
|
||||
// NSPR_LOG_MODULES=TimerFirings:4
|
||||
//
|
||||
// Then a line will be printed for every timer that fires. The name used for a
|
||||
// |CallbackType::Function| timer depends on the circumstances.
|
||||
//
|
||||
// - If it was explicitly named (e.g. it was initialized with
|
||||
// InitWithNamedFuncCallback()) then that explicit name will be shown.
|
||||
//
|
||||
// - Otherwise, if we are on a platform that supports function name lookup
|
||||
// (currently only Mac) then the looked-up name will be shown with a
|
||||
// "[from dladdr]" annotation.
|
||||
//
|
||||
// - Otherwise, no name will be printed. If many timers hit this case then
|
||||
// you'll need to re-run the workload on a Mac to find out which timers they
|
||||
// are, and then give them explicit names.
|
||||
//
|
||||
// If you redirect this output to a file called "out", you can then
|
||||
// post-process it with a command something like the following.
|
||||
//
|
||||
// cat out | grep timer | sort | uniq -c | sort -r -n
|
||||
//
|
||||
// This will show how often each unique line appears, with the most common ones
|
||||
// first.
|
||||
//
|
||||
PRLogModuleInfo*
|
||||
GetTimerFiringsLog()
|
||||
{
|
||||
static PRLogModuleInfo* sLog;
|
||||
if (!sLog) {
|
||||
sLog = PR_NewLogModule("TimerFirings");
|
||||
}
|
||||
return sLog;
|
||||
}
|
||||
|
||||
#include <math.h>
|
||||
|
||||
double nsTimerImpl::sDeltaSumSquared = 0;
|
||||
@ -128,6 +176,7 @@ nsTimerImpl::Release(void)
|
||||
|
||||
nsTimerImpl::nsTimerImpl() :
|
||||
mClosure(nullptr),
|
||||
mName(nsTimerImpl::Nothing),
|
||||
mCallbackType(CallbackType::Unknown),
|
||||
mFiring(false),
|
||||
mArmed(false),
|
||||
@ -216,11 +265,12 @@ nsTimerImpl::InitCommon(uint32_t aDelay, uint32_t aType)
|
||||
return gThread->AddTimer(this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc,
|
||||
void* aClosure,
|
||||
uint32_t aDelay,
|
||||
uint32_t aType)
|
||||
nsresult
|
||||
nsTimerImpl::InitWithFuncCallbackCommon(nsTimerCallbackFunc aFunc,
|
||||
void* aClosure,
|
||||
uint32_t aDelay,
|
||||
uint32_t aType,
|
||||
Name aName)
|
||||
{
|
||||
if (NS_WARN_IF(!aFunc)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
@ -230,10 +280,43 @@ nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc,
|
||||
mCallbackType = CallbackType::Function;
|
||||
mCallback.c = aFunc;
|
||||
mClosure = aClosure;
|
||||
mName = aName;
|
||||
|
||||
return InitCommon(aDelay, aType);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc,
|
||||
void* aClosure,
|
||||
uint32_t aDelay,
|
||||
uint32_t aType)
|
||||
{
|
||||
Name name(nsTimerImpl::Nothing);
|
||||
return InitWithFuncCallbackCommon(aFunc, aClosure, aDelay, aType, name);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::InitWithNamedFuncCallback(nsTimerCallbackFunc aFunc,
|
||||
void* aClosure,
|
||||
uint32_t aDelay,
|
||||
uint32_t aType,
|
||||
const char* aNameString)
|
||||
{
|
||||
Name name(aNameString);
|
||||
return InitWithFuncCallbackCommon(aFunc, aClosure, aDelay, aType, name);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::InitWithNameableFuncCallback(nsTimerCallbackFunc aFunc,
|
||||
void* aClosure,
|
||||
uint32_t aDelay,
|
||||
uint32_t aType,
|
||||
nsTimerNameCallbackFunc aNameFunc)
|
||||
{
|
||||
Name name(aNameFunc);
|
||||
return InitWithFuncCallbackCommon(aFunc, aClosure, aDelay, aType, name);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::InitWithCallback(nsITimerCallback* aCallback,
|
||||
uint32_t aDelay,
|
||||
@ -432,6 +515,10 @@ nsTimerImpl::Fire()
|
||||
}
|
||||
ReleaseCallback();
|
||||
|
||||
if (MOZ_LOG_TEST(GetTimerFiringsLog(), LogLevel::Debug)) {
|
||||
LogFiring(callbackType, callback);
|
||||
}
|
||||
|
||||
switch (callbackType) {
|
||||
case CallbackType::Function:
|
||||
callback.c(this, mClosure);
|
||||
@ -484,6 +571,108 @@ nsTimerImpl::Fire()
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#include <cxxabi.h>
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
// See the big comment above GetTimerFiringsLog() to understand this code.
|
||||
void
|
||||
nsTimerImpl::LogFiring(CallbackType aCallbackType, CallbackUnion aCallback)
|
||||
{
|
||||
const char* typeStr;
|
||||
switch (mType) {
|
||||
case TYPE_ONE_SHOT: typeStr = "ONE_SHOT"; break;
|
||||
case TYPE_REPEATING_SLACK: typeStr = "SLACK "; break;
|
||||
case TYPE_REPEATING_PRECISE: /* fall through */
|
||||
case TYPE_REPEATING_PRECISE_CAN_SKIP: typeStr = "PRECISE "; break;
|
||||
default: MOZ_CRASH("bad type");
|
||||
}
|
||||
|
||||
switch (aCallbackType) {
|
||||
case CallbackType::Function: {
|
||||
bool needToFreeName = false;
|
||||
const char* annotation = "";
|
||||
const char* name;
|
||||
static const size_t buflen = 1024;
|
||||
char buf[buflen];
|
||||
|
||||
if (mName.is<NameString>()) {
|
||||
name = mName.as<NameString>();
|
||||
|
||||
} else if (mName.is<NameFunc>()) {
|
||||
mName.as<NameFunc>()(this, mClosure, buf, buflen);
|
||||
name = buf;
|
||||
|
||||
} else {
|
||||
MOZ_ASSERT(mName.is<NameNothing>());
|
||||
#if defined(XP_MACOSX)
|
||||
annotation = "[from dladdr] ";
|
||||
|
||||
Dl_info info;
|
||||
if (dladdr(reinterpret_cast<void*>(aCallback.c), &info) == 0) {
|
||||
name = "???[dladdr: failed]";
|
||||
} else if (!info.dli_sname) {
|
||||
name = "???[dladdr: no matching symbol]";
|
||||
|
||||
} else {
|
||||
int status;
|
||||
name = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
|
||||
if (status == 0) {
|
||||
// Success. Because we didn't pass in a buffer to __cxa_demangle it
|
||||
// allocates its own one with malloc() which we must free() later.
|
||||
MOZ_ASSERT(name);
|
||||
needToFreeName = true;
|
||||
} else if (status == -1) {
|
||||
name = "???[__cxa_demangle: OOM]";
|
||||
} else if (status == -2) {
|
||||
name = "???[__cxa_demangle: invalid mangled name]";
|
||||
} else if (status == -3) {
|
||||
name = "???[__cxa_demangle: invalid argument]";
|
||||
} else {
|
||||
name = "???[__cxa_demangle: unexpected status value]";
|
||||
}
|
||||
}
|
||||
#else
|
||||
name = "???[dladdr: unavailable/doesn't work on this platform]";
|
||||
#endif
|
||||
}
|
||||
|
||||
MOZ_LOG(GetTimerFiringsLog(), LogLevel::Debug,
|
||||
("[%d] fn timer (%s %5d ms): %s%s\n",
|
||||
getpid(), typeStr, mDelay, annotation, name));
|
||||
|
||||
if (needToFreeName) {
|
||||
free(const_cast<char*>(name));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CallbackType::Interface: {
|
||||
MOZ_LOG(GetTimerFiringsLog(), LogLevel::Debug,
|
||||
("[%d] iface timer (%s %5d ms): %p\n",
|
||||
getpid(), typeStr, mDelay, aCallback.i));
|
||||
break;
|
||||
}
|
||||
|
||||
case CallbackType::Observer: {
|
||||
MOZ_LOG(GetTimerFiringsLog(), LogLevel::Debug,
|
||||
("[%d] obs timer (%s %5d ms): %p\n",
|
||||
getpid(), typeStr, mDelay, aCallback.o));
|
||||
break;
|
||||
}
|
||||
|
||||
case CallbackType::Unknown:
|
||||
default: {
|
||||
MOZ_LOG(GetTimerFiringsLog(), LogLevel::Debug,
|
||||
("[%d] ??? timer (%s, %5d ms)\n",
|
||||
getpid(), typeStr, mDelay));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsTimerImpl::SetDelayInternal(uint32_t aDelay)
|
||||
{
|
||||
@ -511,6 +700,8 @@ nsTimerImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
return aMallocSizeOf(this);
|
||||
}
|
||||
|
||||
/* static */ const nsTimerImpl::NameNothing nsTimerImpl::Nothing = 0;
|
||||
|
||||
#ifdef MOZ_TASK_TRACER
|
||||
void
|
||||
nsTimerImpl::GetTLSTraceInfo()
|
||||
|
@ -13,9 +13,10 @@
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Variant.h"
|
||||
|
||||
#ifdef MOZ_TASK_TRACER
|
||||
#include "TracedTaskCommon.h"
|
||||
@ -122,6 +123,28 @@ private:
|
||||
nsIObserver* MOZ_OWNING_REF o;
|
||||
} mCallback;
|
||||
|
||||
void LogFiring(CallbackType aCallbackType, CallbackUnion aCallbackUnion);
|
||||
|
||||
// |Name| is a tagged union type representing one of (a) nothing, (b) a
|
||||
// string, or (c) a function. mozilla::Variant doesn't naturally handle the
|
||||
// "nothing" case, so we define a dummy type and value (which is unused and
|
||||
// so the exact value doesn't matter) for it.
|
||||
typedef const int NameNothing;
|
||||
typedef const char* NameString;
|
||||
typedef nsTimerNameCallbackFunc NameFunc;
|
||||
typedef mozilla::Variant<NameNothing, NameString, NameFunc> Name;
|
||||
static const NameNothing Nothing;
|
||||
|
||||
nsresult InitWithFuncCallbackCommon(nsTimerCallbackFunc aFunc,
|
||||
void* aClosure,
|
||||
uint32_t aDelay,
|
||||
uint32_t aType,
|
||||
Name aName);
|
||||
|
||||
// This is set by Init. It records the name (if there is one) for the timer,
|
||||
// for use when logging timer firings.
|
||||
Name mName;
|
||||
|
||||
// Some callers expect to be able to access the callback while the
|
||||
// timer is firing.
|
||||
nsCOMPtr<nsITimerCallback> mTimerCallbackWhileFiring;
|
||||
|
Loading…
Reference in New Issue
Block a user