mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-04 13:07:52 +00:00
Bug 995730 - Convert xpcom/threads/ to Gecko style. r=froydnj
--HG-- extra : rebase_source : 1f6f179f44db87f55ebfe5d855192adfad7d1b74
This commit is contained in:
parent
9c80e3cef5
commit
67dad11bae
@ -38,7 +38,7 @@ private:
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (IsNuwaProcess()) {
|
||||
NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
|
||||
NS_ASSERTION(NuwaMarkCurrentThread,
|
||||
"NuwaMarkCurrentThread is undefined!");
|
||||
NuwaMarkCurrentThread(nullptr, nullptr);
|
||||
}
|
||||
@ -117,9 +117,8 @@ public:
|
||||
|
||||
static void Startup()
|
||||
{
|
||||
/* We can tolerate init() failing.
|
||||
The if block turns off warn_unused_result. */
|
||||
if (!sTlsKey.init()) {}
|
||||
/* We can tolerate init() failing. */
|
||||
(void)!sTlsKey.init();
|
||||
}
|
||||
|
||||
// Hang timeout in ticks
|
||||
@ -176,18 +175,14 @@ BackgroundHangManager::BackgroundHangManager()
|
||||
PR_USER_THREAD, MonitorThread, this,
|
||||
PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
|
||||
|
||||
MOZ_ASSERT(mHangMonitorThread,
|
||||
"Failed to create monitor thread");
|
||||
MOZ_ASSERT(mHangMonitorThread, "Failed to create monitor thread");
|
||||
}
|
||||
|
||||
BackgroundHangManager::~BackgroundHangManager()
|
||||
{
|
||||
MOZ_ASSERT(mShutdown,
|
||||
"Destruction without Shutdown call");
|
||||
MOZ_ASSERT(mHangThreads.isEmpty(),
|
||||
"Destruction with outstanding monitors");
|
||||
MOZ_ASSERT(mHangMonitorThread,
|
||||
"No monitor thread");
|
||||
MOZ_ASSERT(mShutdown, "Destruction without Shutdown call");
|
||||
MOZ_ASSERT(mHangThreads.isEmpty(), "Destruction with outstanding monitors");
|
||||
MOZ_ASSERT(mHangMonitorThread, "No monitor thread");
|
||||
|
||||
// PR_CreateThread could have failed above due to resource limitation
|
||||
if (mHangMonitorThread) {
|
||||
|
@ -26,7 +26,8 @@
|
||||
#define REPORT_CHROME_HANGS
|
||||
#endif
|
||||
|
||||
namespace mozilla { namespace HangMonitor {
|
||||
namespace mozilla {
|
||||
namespace HangMonitor {
|
||||
|
||||
/**
|
||||
* A flag which may be set from within a debugger to disable the hang
|
||||
@ -112,21 +113,22 @@ Crash()
|
||||
|
||||
#ifdef REPORT_CHROME_HANGS
|
||||
static void
|
||||
ChromeStackWalker(void *aPC, void *aSP, void *aClosure)
|
||||
ChromeStackWalker(void* aPC, void* aSP, void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aClosure);
|
||||
std::vector<uintptr_t> *stack =
|
||||
std::vector<uintptr_t>* stack =
|
||||
static_cast<std::vector<uintptr_t>*>(aClosure);
|
||||
if (stack->size() == MAX_CALL_STACK_PCS)
|
||||
if (stack->size() == MAX_CALL_STACK_PCS) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(stack->size() < MAX_CALL_STACK_PCS);
|
||||
stack->push_back(reinterpret_cast<uintptr_t>(aPC));
|
||||
}
|
||||
|
||||
static void
|
||||
GetChromeHangReport(Telemetry::ProcessedStack &aStack,
|
||||
int32_t &aSystemUptime,
|
||||
int32_t &aFirefoxUptime)
|
||||
GetChromeHangReport(Telemetry::ProcessedStack& aStack,
|
||||
int32_t& aSystemUptime,
|
||||
int32_t& aFirefoxUptime)
|
||||
{
|
||||
MOZ_ASSERT(winMainThreadHandle);
|
||||
|
||||
@ -135,14 +137,16 @@ GetChromeHangReport(Telemetry::ProcessedStack &aStack,
|
||||
std::vector<uintptr_t> rawStack;
|
||||
rawStack.reserve(MAX_CALL_STACK_PCS);
|
||||
DWORD ret = ::SuspendThread(winMainThreadHandle);
|
||||
if (ret == -1)
|
||||
if (ret == -1) {
|
||||
return;
|
||||
}
|
||||
NS_StackWalk(ChromeStackWalker, /* skipFrames */ 0, /* maxFrames */ 0,
|
||||
reinterpret_cast<void*>(&rawStack),
|
||||
reinterpret_cast<uintptr_t>(winMainThreadHandle), nullptr);
|
||||
ret = ::ResumeThread(winMainThreadHandle);
|
||||
if (ret == -1)
|
||||
if (ret == -1) {
|
||||
return;
|
||||
}
|
||||
aStack = Telemetry::GetStackAndModules(rawStack);
|
||||
|
||||
// Record system uptime (in minutes) at the time of the hang
|
||||
@ -217,8 +221,7 @@ ThreadMain(void*)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
#ifdef REPORT_CHROME_HANGS
|
||||
if (waitCount >= 2) {
|
||||
uint32_t hangDuration = PR_IntervalToSeconds(now - lastTimestamp);
|
||||
@ -234,8 +237,7 @@ ThreadMain(void*)
|
||||
PRIntervalTime timeout;
|
||||
if (gTimeout <= 0) {
|
||||
timeout = PR_INTERVAL_NO_TIMEOUT;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
timeout = PR_MillisecondsToInterval(gTimeout * 500);
|
||||
}
|
||||
lock.Wait(timeout);
|
||||
@ -248,8 +250,9 @@ Startup()
|
||||
// The hang detector only runs in chrome processes. If you change this,
|
||||
// you must also deal with the threadsafety of AnnotateCrashReport in
|
||||
// non-chrome processes!
|
||||
if (GeckoProcessType_Default != XRE_GetProcessType())
|
||||
if (GeckoProcessType_Default != XRE_GetProcessType()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!gMonitor, "Hang monitor already initialized");
|
||||
gMonitor = new Monitor("HangMonitor");
|
||||
@ -261,8 +264,9 @@ Startup()
|
||||
Preferences::RegisterCallback(PrefChanged, kTelemetryPrefName, nullptr);
|
||||
winMainThreadHandle =
|
||||
OpenThread(THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId());
|
||||
if (!winMainThreadHandle)
|
||||
if (!winMainThreadHandle) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Don't actually start measuring hangs until we hit the main event loop.
|
||||
@ -280,12 +284,14 @@ Startup()
|
||||
void
|
||||
Shutdown()
|
||||
{
|
||||
if (GeckoProcessType_Default != XRE_GetProcessType())
|
||||
if (GeckoProcessType_Default != XRE_GetProcessType()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(gMonitor, "Hang monitor not started");
|
||||
|
||||
{ // Scope the lock we're going to delete later
|
||||
{
|
||||
// Scope the lock we're going to delete later
|
||||
MonitorAutoLock lock(*gMonitor);
|
||||
gShutdown = true;
|
||||
lock.Notify();
|
||||
@ -307,11 +313,11 @@ IsUIMessageWaiting()
|
||||
#ifndef XP_WIN
|
||||
return false;
|
||||
#else
|
||||
#define NS_WM_IMEFIRST WM_IME_SETCONTEXT
|
||||
#define NS_WM_IMELAST WM_IME_KEYUP
|
||||
#define NS_WM_IMEFIRST WM_IME_SETCONTEXT
|
||||
#define NS_WM_IMELAST WM_IME_KEYUP
|
||||
BOOL haveUIMessageWaiting = FALSE;
|
||||
MSG msg;
|
||||
haveUIMessageWaiting |= ::PeekMessageW(&msg, nullptr, WM_KEYFIRST,
|
||||
haveUIMessageWaiting |= ::PeekMessageW(&msg, nullptr, WM_KEYFIRST,
|
||||
WM_IME_KEYLAST, PM_NOREMOVE);
|
||||
haveUIMessageWaiting |= ::PeekMessageW(&msg, nullptr, NS_WM_IMEFIRST,
|
||||
NS_WM_IMELAST, PM_NOREMOVE);
|
||||
@ -322,32 +328,32 @@ IsUIMessageWaiting()
|
||||
}
|
||||
|
||||
void
|
||||
NotifyActivity(ActivityType activityType)
|
||||
NotifyActivity(ActivityType aActivityType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(),
|
||||
"HangMonitor::Notify called from off the main thread.");
|
||||
|
||||
// Determine the activity type more specifically
|
||||
if (activityType == kGeneralActivity) {
|
||||
activityType = IsUIMessageWaiting() ? kActivityUIAVail :
|
||||
kActivityNoUIAVail;
|
||||
if (aActivityType == kGeneralActivity) {
|
||||
aActivityType = IsUIMessageWaiting() ? kActivityUIAVail :
|
||||
kActivityNoUIAVail;
|
||||
}
|
||||
|
||||
// Calculate the cumulative amount of lag time since the last UI message
|
||||
static uint32_t cumulativeUILagMS = 0;
|
||||
switch(activityType) {
|
||||
case kActivityNoUIAVail:
|
||||
cumulativeUILagMS = 0;
|
||||
break;
|
||||
case kActivityUIAVail:
|
||||
case kUIActivity:
|
||||
if (gTimestamp != PR_INTERVAL_NO_WAIT) {
|
||||
cumulativeUILagMS += PR_IntervalToMilliseconds(PR_IntervalNow() -
|
||||
gTimestamp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
switch (aActivityType) {
|
||||
case kActivityNoUIAVail:
|
||||
cumulativeUILagMS = 0;
|
||||
break;
|
||||
case kActivityUIAVail:
|
||||
case kUIActivity:
|
||||
if (gTimestamp != PR_INTERVAL_NO_WAIT) {
|
||||
cumulativeUILagMS += PR_IntervalToMilliseconds(PR_IntervalNow() -
|
||||
gTimestamp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// This is not a locked activity because PRTimeStamp is a 32-bit quantity
|
||||
@ -357,7 +363,7 @@ NotifyActivity(ActivityType activityType)
|
||||
|
||||
// If we have UI activity we should reset the timer and report it if it is
|
||||
// significant enough.
|
||||
if (activityType == kUIActivity) {
|
||||
if (aActivityType == kUIActivity) {
|
||||
// The minimum amount of lag time that we should report for telemetry data.
|
||||
// Mozilla's UI responsiveness goal is 50ms
|
||||
static const uint32_t kUIResponsivenessThresholdMS = 50;
|
||||
@ -387,4 +393,5 @@ Suspend()
|
||||
}
|
||||
}
|
||||
|
||||
} } // namespace mozilla::HangMonitor
|
||||
} // namespace HangMonitor
|
||||
} // namespace mozilla
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
@ -6,12 +7,14 @@
|
||||
#ifndef mozilla_HangMonitor_h
|
||||
#define mozilla_HangMonitor_h
|
||||
|
||||
namespace mozilla { namespace HangMonitor {
|
||||
namespace mozilla {
|
||||
namespace HangMonitor {
|
||||
|
||||
/**
|
||||
* Signifies the type of activity in question
|
||||
*/
|
||||
enum ActivityType {
|
||||
enum ActivityType
|
||||
{
|
||||
/* There is activity and it is known to be UI related activity. */
|
||||
kUIActivity,
|
||||
|
||||
@ -49,6 +52,7 @@ void NotifyActivity(ActivityType activityType = kGeneralActivity);
|
||||
*/
|
||||
void Suspend();
|
||||
|
||||
} } // namespace mozilla::HangMonitor
|
||||
} // namespace HangMonitor
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_HangMonitor_h
|
||||
|
@ -34,18 +34,18 @@ LazyIdleThread::LazyIdleThread(uint32_t aIdleTimeoutMS,
|
||||
const nsCSubstring& aName,
|
||||
ShutdownMethod aShutdownMethod,
|
||||
nsIObserver* aIdleObserver)
|
||||
: mMutex("LazyIdleThread::mMutex"),
|
||||
mOwningThread(NS_GetCurrentThread()),
|
||||
mIdleObserver(aIdleObserver),
|
||||
mQueuedRunnables(nullptr),
|
||||
mIdleTimeoutMS(aIdleTimeoutMS),
|
||||
mPendingEventCount(0),
|
||||
mIdleNotificationCount(0),
|
||||
mShutdownMethod(aShutdownMethod),
|
||||
mShutdown(false),
|
||||
mThreadIsShuttingDown(false),
|
||||
mIdleTimeoutEnabled(true),
|
||||
mName(aName)
|
||||
: mMutex("LazyIdleThread::mMutex")
|
||||
, mOwningThread(NS_GetCurrentThread())
|
||||
, mIdleObserver(aIdleObserver)
|
||||
, mQueuedRunnables(nullptr)
|
||||
, mIdleTimeoutMS(aIdleTimeoutMS)
|
||||
, mPendingEventCount(0)
|
||||
, mIdleNotificationCount(0)
|
||||
, mShutdownMethod(aShutdownMethod)
|
||||
, mShutdown(false)
|
||||
, mThreadIsShuttingDown(false)
|
||||
, mIdleTimeoutEnabled(true)
|
||||
, mName(aName)
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread, "Need owning thread!");
|
||||
}
|
||||
@ -147,26 +147,31 @@ LazyIdleThread::EnsureThread()
|
||||
if (mShutdownMethod == AutomaticShutdown && NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIObserverService> obs =
|
||||
do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = obs->AddObserver(this, "xpcom-shutdown-threads", false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
mIdleTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(!mIdleTimer))
|
||||
if (NS_WARN_IF(!mIdleTimer)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &LazyIdleThread::InitThread);
|
||||
if (NS_WARN_IF(!runnable))
|
||||
if (NS_WARN_IF(!runnable)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
rv = NS_NewThread(getter_AddRefs(mThread), runnable);
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -273,14 +278,16 @@ LazyIdleThread::ShutdownThread()
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &LazyIdleThread::CleanupThread);
|
||||
if (NS_WARN_IF(!runnable))
|
||||
if (NS_WARN_IF(!runnable)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
PreDispatch();
|
||||
|
||||
rv = mThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Put the temporary queue in place before calling Shutdown().
|
||||
mQueuedRunnables = &queuedRunnables;
|
||||
@ -306,8 +313,9 @@ LazyIdleThread::ShutdownThread()
|
||||
|
||||
if (mIdleTimer) {
|
||||
rv = mIdleTimer->Cancel();
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mIdleTimer = nullptr;
|
||||
}
|
||||
@ -384,8 +392,9 @@ LazyIdleThread::Dispatch(nsIRunnable* aEvent,
|
||||
ASSERT_OWNING_THREAD();
|
||||
|
||||
// LazyIdleThread can't always support synchronous dispatch currently.
|
||||
if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL))
|
||||
if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// If our thread is shutting down then we can't actually dispatch right now.
|
||||
// Queue this runnable for later.
|
||||
@ -395,8 +404,9 @@ LazyIdleThread::Dispatch(nsIRunnable* aEvent,
|
||||
}
|
||||
|
||||
nsresult rv = EnsureThread();
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
PreDispatch();
|
||||
|
||||
@ -437,8 +447,9 @@ LazyIdleThread::Shutdown()
|
||||
|
||||
mIdleObserver = nullptr;
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -478,8 +489,9 @@ LazyIdleThread::Notify(nsITimer* aTimer)
|
||||
}
|
||||
|
||||
nsresult rv = ShutdownThread();
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -528,12 +540,14 @@ LazyIdleThread::AfterProcessNextEvent(nsIThreadInternal* /* aThread */,
|
||||
if (shouldNotifyIdle) {
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &LazyIdleThread::ScheduleTimer);
|
||||
if (NS_WARN_IF(!runnable))
|
||||
if (NS_WARN_IF(!runnable)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsresult rv = mOwningThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -32,10 +32,11 @@ namespace mozilla {
|
||||
* is created on the main thread then it will automatically join its thread on
|
||||
* XPCOM shutdown using the Observer Service.
|
||||
*/
|
||||
class LazyIdleThread MOZ_FINAL : public nsIThread,
|
||||
public nsITimerCallback,
|
||||
public nsIThreadObserver,
|
||||
public nsIObserver
|
||||
class LazyIdleThread MOZ_FINAL
|
||||
: public nsIThread
|
||||
, public nsITimerCallback
|
||||
, public nsIThreadObserver
|
||||
, public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
@ -45,7 +46,8 @@ public:
|
||||
NS_DECL_NSITHREADOBSERVER
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
enum ShutdownMethod {
|
||||
enum ShutdownMethod
|
||||
{
|
||||
AutomaticShutdown = 0,
|
||||
ManualShutdown
|
||||
};
|
||||
@ -128,7 +130,8 @@ private:
|
||||
* Returns true if events should be queued rather than immediately dispatched
|
||||
* to mThread. Currently only happens when the thread is shutting down.
|
||||
*/
|
||||
bool UseRunnableQueue() {
|
||||
bool UseRunnableQueue()
|
||||
{
|
||||
return !!mQueuedRunnables;
|
||||
}
|
||||
|
||||
@ -165,7 +168,7 @@ private:
|
||||
* Temporary storage for events that happen to be dispatched while we're in
|
||||
* the process of shutting down our real thread.
|
||||
*/
|
||||
nsTArray<nsCOMPtr<nsIRunnable> >* mQueuedRunnables;
|
||||
nsTArray<nsCOMPtr<nsIRunnable>>* mQueuedRunnables;
|
||||
|
||||
/**
|
||||
* The number of milliseconds a thread should be idle before dying.
|
||||
|
@ -30,20 +30,20 @@ namespace mozilla {
|
||||
class SyncRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
SyncRunnable(nsIRunnable* r)
|
||||
: mRunnable(r)
|
||||
SyncRunnable(nsIRunnable* aRunnable)
|
||||
: mRunnable(aRunnable)
|
||||
, mMonitor("SyncRunnable")
|
||||
, mDone(false)
|
||||
{ }
|
||||
{
|
||||
}
|
||||
|
||||
void DispatchToThread(nsIEventTarget* thread,
|
||||
bool forceDispatch = false)
|
||||
void DispatchToThread(nsIEventTarget* aThread, bool aForceDispatch = false)
|
||||
{
|
||||
nsresult rv;
|
||||
bool on;
|
||||
|
||||
if (!forceDispatch) {
|
||||
rv = thread->IsOnCurrentThread(&on);
|
||||
if (!aForceDispatch) {
|
||||
rv = aThread->IsOnCurrentThread(&on);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (NS_SUCCEEDED(rv) && on) {
|
||||
mRunnable->Run();
|
||||
@ -51,7 +51,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
rv = thread->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
rv = aThread->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mozilla::MonitorAutoLock lock(mMonitor);
|
||||
while (!mDone) {
|
||||
@ -60,12 +60,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
static void DispatchToThread(nsIEventTarget* thread,
|
||||
nsIRunnable* r,
|
||||
bool forceDispatch = false)
|
||||
static void DispatchToThread(nsIEventTarget* aThread,
|
||||
nsIRunnable* aRunnable,
|
||||
bool aForceDispatch = false)
|
||||
{
|
||||
nsRefPtr<SyncRunnable> s(new SyncRunnable(r));
|
||||
s->DispatchToThread(thread, forceDispatch);
|
||||
nsRefPtr<SyncRunnable> s(new SyncRunnable(aRunnable));
|
||||
s->DispatchToThread(aThread, aForceDispatch);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -184,7 +184,8 @@ ThreadStackHelper::SigAction(int aSignal, siginfo_t* aInfo, void* aContext)
|
||||
#endif // XP_LINUX
|
||||
|
||||
bool
|
||||
ThreadStackHelper::PrepareStackBuffer(Stack& aStack) {
|
||||
ThreadStackHelper::PrepareStackBuffer(Stack& aStack)
|
||||
{
|
||||
// Return false to skip getting the stack and return an empty stack
|
||||
aStack.clear();
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
@ -208,7 +209,8 @@ ThreadStackHelper::PrepareStackBuffer(Stack& aStack) {
|
||||
}
|
||||
|
||||
void
|
||||
ThreadStackHelper::FillStackBuffer() {
|
||||
ThreadStackHelper::FillStackBuffer()
|
||||
{
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
size_t reservedSize = mMaxStackSize;
|
||||
|
||||
|
@ -50,9 +50,10 @@ namespace {
|
||||
class TimerObserverRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
TimerObserverRunnable(nsIObserver* observer)
|
||||
: mObserver(observer)
|
||||
{ }
|
||||
TimerObserverRunnable(nsIObserver* aObserver)
|
||||
: mObserver(aObserver)
|
||||
{
|
||||
}
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
@ -76,13 +77,16 @@ TimerObserverRunnable::Run()
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
nsresult TimerThread::Init()
|
||||
nsresult
|
||||
TimerThread::Init()
|
||||
{
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("TimerThread::Init [%d]\n", mInitialized));
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG,
|
||||
("TimerThread::Init [%d]\n", mInitialized));
|
||||
|
||||
if (mInitialized) {
|
||||
if (!mThread)
|
||||
if (!mThread) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -92,13 +96,11 @@ nsresult TimerThread::Init()
|
||||
nsresult rv = NS_NewThread(getter_AddRefs(mThread), this);
|
||||
if (NS_FAILED(rv)) {
|
||||
mThread = nullptr;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
nsRefPtr<TimerObserverRunnable> r = new TimerObserverRunnable(this);
|
||||
if (NS_IsMainThread()) {
|
||||
r->Run();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
}
|
||||
@ -108,29 +110,32 @@ nsresult TimerThread::Init()
|
||||
mInitialized = true;
|
||||
mMonitor.NotifyAll();
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
while (!mInitialized) {
|
||||
mMonitor.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
if (!mThread)
|
||||
if (!mThread) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult TimerThread::Shutdown()
|
||||
nsresult
|
||||
TimerThread::Shutdown()
|
||||
{
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("TimerThread::Shutdown begin\n"));
|
||||
|
||||
if (!mThread)
|
||||
if (!mThread) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
nsTArray<nsTimerImpl*> timers;
|
||||
{ // lock scope
|
||||
{
|
||||
// lock scope
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
mShutdown = true;
|
||||
@ -153,7 +158,7 @@ nsresult TimerThread::Shutdown()
|
||||
|
||||
uint32_t timersCount = timers.Length();
|
||||
for (uint32_t i = 0; i < timersCount; i++) {
|
||||
nsTimerImpl *timer = timers[i];
|
||||
nsTimerImpl* timer = timers[i];
|
||||
timer->ReleaseCallback();
|
||||
ReleaseTimerInternal(timer);
|
||||
}
|
||||
@ -169,13 +174,14 @@ nsresult TimerThread::Shutdown()
|
||||
#endif
|
||||
|
||||
/* void Run(); */
|
||||
NS_IMETHODIMP TimerThread::Run()
|
||||
NS_IMETHODIMP
|
||||
TimerThread::Run()
|
||||
{
|
||||
PR_SetCurrentThreadName("Timer");
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (IsNuwaProcess()) {
|
||||
NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
|
||||
NS_ASSERTION(NuwaMarkCurrentThread,
|
||||
"NuwaMarkCurrentThread is undefined!");
|
||||
NuwaMarkCurrentThread(nullptr, nullptr);
|
||||
}
|
||||
@ -187,18 +193,20 @@ NS_IMETHODIMP TimerThread::Run()
|
||||
// is platform-dependent, we calculate it at runtime now.
|
||||
// First we find a value such that PR_MicrosecondsToInterval(high) = 1
|
||||
int32_t low = 0, high = 1;
|
||||
while (PR_MicrosecondsToInterval(high) == 0)
|
||||
while (PR_MicrosecondsToInterval(high) == 0) {
|
||||
high <<= 1;
|
||||
}
|
||||
// We now have
|
||||
// PR_MicrosecondsToInterval(low) = 0
|
||||
// PR_MicrosecondsToInterval(high) = 1
|
||||
// and we can proceed to find the critical value using binary search
|
||||
while (high-low > 1) {
|
||||
int32_t mid = (high+low) >> 1;
|
||||
if (PR_MicrosecondsToInterval(mid) == 0)
|
||||
while (high - low > 1) {
|
||||
int32_t mid = (high + low) >> 1;
|
||||
if (PR_MicrosecondsToInterval(mid) == 0) {
|
||||
low = mid;
|
||||
else
|
||||
} else {
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
|
||||
// Half of the amount of microseconds needed to get positive PRIntervalTime.
|
||||
@ -222,7 +230,7 @@ NS_IMETHODIMP TimerThread::Run()
|
||||
} else {
|
||||
waitFor = PR_INTERVAL_NO_TIMEOUT;
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
nsTimerImpl *timer = nullptr;
|
||||
nsTimerImpl* timer = nullptr;
|
||||
|
||||
if (!mTimers.IsEmpty()) {
|
||||
timer = mTimers[0];
|
||||
@ -273,8 +281,9 @@ NS_IMETHODIMP TimerThread::Run()
|
||||
timer = nullptr;
|
||||
}
|
||||
|
||||
if (mShutdown)
|
||||
if (mShutdown) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Update now, as PostTimerEvent plus the locking may have taken a
|
||||
// tick or two, and we may goto next below.
|
||||
@ -294,7 +303,7 @@ NS_IMETHODIMP TimerThread::Run()
|
||||
// resolution. We use halfMicrosecondsIntervalResolution, calculated
|
||||
// before, to do the optimal rounding (i.e., of how to decide what
|
||||
// interval is so small we should not wait at all).
|
||||
double microseconds = (timeout - now).ToMilliseconds()*1000;
|
||||
double microseconds = (timeout - now).ToMilliseconds() * 1000;
|
||||
|
||||
if (ChaosMode::isActive()) {
|
||||
// The mean value of sFractions must be 1 to ensure that
|
||||
@ -303,7 +312,8 @@ NS_IMETHODIMP TimerThread::Run()
|
||||
static const float sFractions[] = {
|
||||
0.0f, 0.25f, 0.5f, 0.75f, 1.0f, 1.75f, 2.75f
|
||||
};
|
||||
microseconds *= sFractions[ChaosMode::randomUint32LessThan(ArrayLength(sFractions))];
|
||||
microseconds *=
|
||||
sFractions[ChaosMode::randomUint32LessThan(ArrayLength(sFractions))];
|
||||
forceRunNextTimer = true;
|
||||
}
|
||||
|
||||
@ -311,9 +321,11 @@ NS_IMETHODIMP TimerThread::Run()
|
||||
forceRunNextTimer = false;
|
||||
goto next; // round down; execute event now
|
||||
}
|
||||
waitFor = PR_MicrosecondsToInterval(static_cast<uint32_t>(microseconds)); // Floor is accurate enough.
|
||||
if (waitFor == 0)
|
||||
waitFor = 1; // round up, wait the minimum time we can wait
|
||||
waitFor = PR_MicrosecondsToInterval(
|
||||
static_cast<uint32_t>(microseconds)); // Floor is accurate enough.
|
||||
if (waitFor == 0) {
|
||||
waitFor = 1; // round up, wait the minimum time we can wait
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TIMERS
|
||||
@ -340,14 +352,16 @@ NS_IMETHODIMP TimerThread::Run()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult TimerThread::AddTimer(nsTimerImpl *aTimer)
|
||||
nsresult
|
||||
TimerThread::AddTimer(nsTimerImpl* aTimer)
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
// Add the timer to our list.
|
||||
int32_t i = AddTimerInternal(aTimer);
|
||||
if (i < 0)
|
||||
if (i < 0) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Awaken the timer thread.
|
||||
if (mWaiting && i == 0) {
|
||||
@ -358,7 +372,8 @@ nsresult TimerThread::AddTimer(nsTimerImpl *aTimer)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult TimerThread::TimerDelayChanged(nsTimerImpl *aTimer)
|
||||
nsresult
|
||||
TimerThread::TimerDelayChanged(nsTimerImpl* aTimer)
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
@ -367,8 +382,9 @@ nsresult TimerThread::TimerDelayChanged(nsTimerImpl *aTimer)
|
||||
RemoveTimerInternal(aTimer);
|
||||
|
||||
int32_t i = AddTimerInternal(aTimer);
|
||||
if (i < 0)
|
||||
if (i < 0) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Awaken the timer thread.
|
||||
if (mWaiting && i == 0) {
|
||||
@ -379,7 +395,8 @@ nsresult TimerThread::TimerDelayChanged(nsTimerImpl *aTimer)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult TimerThread::RemoveTimer(nsTimerImpl *aTimer)
|
||||
nsresult
|
||||
TimerThread::RemoveTimer(nsTimerImpl* aTimer)
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
@ -390,8 +407,9 @@ nsresult TimerThread::RemoveTimer(nsTimerImpl *aTimer)
|
||||
// TimerThread::Run, must wait for the mMonitor auto-lock here, and during the
|
||||
// wait Run drops the only remaining ref to aTimer via RemoveTimerInternal.
|
||||
|
||||
if (!RemoveTimerInternal(aTimer))
|
||||
if (!RemoveTimerInternal(aTimer)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Awaken the timer thread.
|
||||
if (mWaiting) {
|
||||
@ -403,18 +421,21 @@ nsresult TimerThread::RemoveTimer(nsTimerImpl *aTimer)
|
||||
}
|
||||
|
||||
// This function must be called from within a lock
|
||||
int32_t TimerThread::AddTimerInternal(nsTimerImpl *aTimer)
|
||||
int32_t
|
||||
TimerThread::AddTimerInternal(nsTimerImpl* aTimer)
|
||||
{
|
||||
if (mShutdown)
|
||||
if (mShutdown) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
|
||||
TimerAdditionComparator c(now, aTimer);
|
||||
nsTimerImpl** insertSlot = mTimers.InsertElementSorted(aTimer, c);
|
||||
|
||||
if (!insertSlot)
|
||||
if (!insertSlot) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
aTimer->mArmed = true;
|
||||
NS_ADDREF(aTimer);
|
||||
@ -426,32 +447,37 @@ int32_t TimerThread::AddTimerInternal(nsTimerImpl *aTimer)
|
||||
return insertSlot - mTimers.Elements();
|
||||
}
|
||||
|
||||
bool TimerThread::RemoveTimerInternal(nsTimerImpl *aTimer)
|
||||
bool
|
||||
TimerThread::RemoveTimerInternal(nsTimerImpl* aTimer)
|
||||
{
|
||||
if (!mTimers.RemoveElement(aTimer))
|
||||
if (!mTimers.RemoveElement(aTimer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ReleaseTimerInternal(aTimer);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TimerThread::ReleaseTimerInternal(nsTimerImpl *aTimer)
|
||||
void
|
||||
TimerThread::ReleaseTimerInternal(nsTimerImpl* aTimer)
|
||||
{
|
||||
// Order is crucial here -- see nsTimerImpl::Release.
|
||||
aTimer->mArmed = false;
|
||||
NS_RELEASE(aTimer);
|
||||
}
|
||||
|
||||
void TimerThread::DoBeforeSleep()
|
||||
void
|
||||
TimerThread::DoBeforeSleep()
|
||||
{
|
||||
mSleeping = true;
|
||||
}
|
||||
|
||||
void TimerThread::DoAfterSleep()
|
||||
void
|
||||
TimerThread::DoAfterSleep()
|
||||
{
|
||||
mSleeping = true; // wake may be notified without preceding sleep notification
|
||||
for (uint32_t i = 0; i < mTimers.Length(); i ++) {
|
||||
nsTimerImpl *timer = mTimers[i];
|
||||
nsTimerImpl* timer = mTimers[i];
|
||||
// get and set the delay to cause its timeout to be recomputed
|
||||
uint32_t delay;
|
||||
timer->GetDelay(&delay);
|
||||
@ -464,14 +490,16 @@ void TimerThread::DoAfterSleep()
|
||||
|
||||
/* void observe (in nsISupports aSubject, in string aTopic, in wstring aData); */
|
||||
NS_IMETHODIMP
|
||||
TimerThread::Observe(nsISupports* /* aSubject */, const char *aTopic, const char16_t* /* aData */)
|
||||
TimerThread::Observe(nsISupports* /* aSubject */, const char* aTopic,
|
||||
const char16_t* /* aData */)
|
||||
{
|
||||
if (strcmp(aTopic, "sleep_notification") == 0 ||
|
||||
strcmp(aTopic, "suspend_process_notification") == 0)
|
||||
strcmp(aTopic, "suspend_process_notification") == 0) {
|
||||
DoBeforeSleep();
|
||||
else if (strcmp(aTopic, "wake_notification") == 0 ||
|
||||
strcmp(aTopic, "resume_process_notification") == 0)
|
||||
} else if (strcmp(aTopic, "wake_notification") == 0 ||
|
||||
strcmp(aTopic, "resume_process_notification") == 0) {
|
||||
DoAfterSleep();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -23,8 +23,9 @@ namespace mozilla {
|
||||
class TimeStamp;
|
||||
}
|
||||
|
||||
class TimerThread MOZ_FINAL : public nsIRunnable,
|
||||
public nsIObserver
|
||||
class TimerThread MOZ_FINAL
|
||||
: public nsIRunnable
|
||||
, public nsIObserver
|
||||
{
|
||||
public:
|
||||
typedef mozilla::Monitor Monitor;
|
||||
@ -41,9 +42,9 @@ public:
|
||||
NS_HIDDEN_(nsresult) Init();
|
||||
NS_HIDDEN_(nsresult) Shutdown();
|
||||
|
||||
nsresult AddTimer(nsTimerImpl *aTimer);
|
||||
nsresult TimerDelayChanged(nsTimerImpl *aTimer);
|
||||
nsresult RemoveTimer(nsTimerImpl *aTimer);
|
||||
nsresult AddTimer(nsTimerImpl* aTimer);
|
||||
nsresult TimerDelayChanged(nsTimerImpl* aTimer);
|
||||
nsresult RemoveTimer(nsTimerImpl* aTimer);
|
||||
|
||||
void DoBeforeSleep();
|
||||
void DoAfterSleep();
|
||||
@ -62,9 +63,9 @@ private:
|
||||
// These two internal helper methods must be called while mLock is held.
|
||||
// AddTimerInternal returns the position where the timer was added in the
|
||||
// list, or -1 if it failed.
|
||||
int32_t AddTimerInternal(nsTimerImpl *aTimer);
|
||||
bool RemoveTimerInternal(nsTimerImpl *aTimer);
|
||||
void ReleaseTimerInternal(nsTimerImpl *aTimer);
|
||||
int32_t AddTimerInternal(nsTimerImpl* aTimer);
|
||||
bool RemoveTimerInternal(nsTimerImpl* aTimer);
|
||||
void ReleaseTimerInternal(nsTimerImpl* aTimer);
|
||||
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
Monitor mMonitor;
|
||||
@ -77,31 +78,35 @@ private:
|
||||
nsTArray<nsTimerImpl*> mTimers;
|
||||
};
|
||||
|
||||
struct TimerAdditionComparator {
|
||||
TimerAdditionComparator(const mozilla::TimeStamp &aNow,
|
||||
nsTimerImpl *aTimerToInsert) :
|
||||
struct TimerAdditionComparator
|
||||
{
|
||||
TimerAdditionComparator(const mozilla::TimeStamp& aNow,
|
||||
nsTimerImpl* aTimerToInsert) :
|
||||
now(aNow)
|
||||
#ifdef DEBUG
|
||||
, timerToInsert(aTimerToInsert)
|
||||
#endif
|
||||
{}
|
||||
|
||||
bool LessThan(nsTimerImpl *fromArray, nsTimerImpl *newTimer) const {
|
||||
NS_ABORT_IF_FALSE(newTimer == timerToInsert, "Unexpected timer ordering");
|
||||
|
||||
// Skip any overdue timers.
|
||||
return fromArray->mTimeout <= now ||
|
||||
fromArray->mTimeout <= newTimer->mTimeout;
|
||||
{
|
||||
}
|
||||
|
||||
bool Equals(nsTimerImpl* fromArray, nsTimerImpl* newTimer) const {
|
||||
bool LessThan(nsTimerImpl* aFromArray, nsTimerImpl* aNewTimer) const
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aNewTimer == timerToInsert, "Unexpected timer ordering");
|
||||
|
||||
// Skip any overdue timers.
|
||||
return aFromArray->mTimeout <= now ||
|
||||
aFromArray->mTimeout <= aNewTimer->mTimeout;
|
||||
}
|
||||
|
||||
bool Equals(nsTimerImpl* aFromArray, nsTimerImpl* aNewTimer) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
const mozilla::TimeStamp &now;
|
||||
const mozilla::TimeStamp& now;
|
||||
#ifdef DEBUG
|
||||
const nsTimerImpl * const timerToInsert;
|
||||
const nsTimerImpl* const timerToInsert;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
@ -17,26 +18,25 @@ using namespace mozilla;
|
||||
NS_IMPL_ISUPPORTS(nsEnvironment, nsIEnvironment)
|
||||
|
||||
nsresult
|
||||
nsEnvironment::Create(nsISupports *aOuter, REFNSIID aIID,
|
||||
void **aResult)
|
||||
nsEnvironment::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
*aResult = nullptr;
|
||||
nsresult rv;
|
||||
*aResult = nullptr;
|
||||
|
||||
if (aOuter != nullptr) {
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
if (aOuter) {
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
|
||||
nsEnvironment* obj = new nsEnvironment();
|
||||
if (!obj) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
nsEnvironment* obj = new nsEnvironment();
|
||||
if (!obj) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
rv = obj->QueryInterface(aIID, aResult);
|
||||
if (NS_FAILED(rv)) {
|
||||
delete obj;
|
||||
}
|
||||
return rv;
|
||||
rv = obj->QueryInterface(aIID, aResult);
|
||||
if (NS_FAILED(rv)) {
|
||||
delete obj;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsEnvironment::~nsEnvironment()
|
||||
@ -44,117 +44,123 @@ nsEnvironment::~nsEnvironment()
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEnvironment::Exists(const nsAString& aName, bool *aOutValue)
|
||||
nsEnvironment::Exists(const nsAString& aName, bool* aOutValue)
|
||||
{
|
||||
nsAutoCString nativeName;
|
||||
nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
return rv;
|
||||
nsAutoCString nativeName;
|
||||
nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoCString nativeVal;
|
||||
nsAutoCString nativeVal;
|
||||
#if defined(XP_UNIX)
|
||||
/* For Unix/Linux platforms we follow the Unix definition:
|
||||
* An environment variable exists when |getenv()| returns a non-nullptr
|
||||
* value. An environment variable does not exist when |getenv()| returns
|
||||
* nullptr.
|
||||
*/
|
||||
const char *value = PR_GetEnv(nativeName.get());
|
||||
*aOutValue = value && *value;
|
||||
/* For Unix/Linux platforms we follow the Unix definition:
|
||||
* An environment variable exists when |getenv()| returns a non-nullptr
|
||||
* value. An environment variable does not exist when |getenv()| returns
|
||||
* nullptr.
|
||||
*/
|
||||
const char* value = PR_GetEnv(nativeName.get());
|
||||
*aOutValue = value && *value;
|
||||
#else
|
||||
/* For non-Unix/Linux platforms we have to fall back to a
|
||||
* "portable" definition (which is incorrect for Unix/Linux!!!!)
|
||||
* which simply checks whether the string returned by |Get()| is empty
|
||||
* or not.
|
||||
*/
|
||||
nsAutoString value;
|
||||
Get(aName, value);
|
||||
*aOutValue = !value.IsEmpty();
|
||||
/* For non-Unix/Linux platforms we have to fall back to a
|
||||
* "portable" definition (which is incorrect for Unix/Linux!!!!)
|
||||
* which simply checks whether the string returned by |Get()| is empty
|
||||
* or not.
|
||||
*/
|
||||
nsAutoString value;
|
||||
Get(aName, value);
|
||||
*aOutValue = !value.IsEmpty();
|
||||
#endif /* XP_UNIX */
|
||||
|
||||
return NS_OK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEnvironment::Get(const nsAString& aName, nsAString& aOutValue)
|
||||
{
|
||||
nsAutoCString nativeName;
|
||||
nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
return rv;
|
||||
|
||||
nsAutoCString nativeVal;
|
||||
const char *value = PR_GetEnv(nativeName.get());
|
||||
if (value && *value) {
|
||||
rv = NS_CopyNativeToUnicode(nsDependentCString(value), aOutValue);
|
||||
} else {
|
||||
aOutValue.Truncate();
|
||||
rv = NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString nativeName;
|
||||
nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoCString nativeVal;
|
||||
const char* value = PR_GetEnv(nativeName.get());
|
||||
if (value && *value) {
|
||||
rv = NS_CopyNativeToUnicode(nsDependentCString(value), aOutValue);
|
||||
} else {
|
||||
aOutValue.Truncate();
|
||||
rv = NS_OK;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Environment strings must have static duration; We're gonna leak all of this
|
||||
* at shutdown: this is by design, caused how Unix/Linux implement environment
|
||||
* vars.
|
||||
* vars.
|
||||
*/
|
||||
|
||||
typedef nsBaseHashtableET<nsCharPtrHashKey,char*> EnvEntryType;
|
||||
typedef nsBaseHashtableET<nsCharPtrHashKey, char*> EnvEntryType;
|
||||
typedef nsTHashtable<EnvEntryType> EnvHashType;
|
||||
|
||||
static EnvHashType *gEnvHash = nullptr;
|
||||
static EnvHashType* gEnvHash = nullptr;
|
||||
|
||||
static bool
|
||||
EnsureEnvHash()
|
||||
{
|
||||
if (gEnvHash)
|
||||
return true;
|
||||
|
||||
gEnvHash = new EnvHashType;
|
||||
if (!gEnvHash)
|
||||
return false;
|
||||
|
||||
if (gEnvHash) {
|
||||
return true;
|
||||
}
|
||||
|
||||
gEnvHash = new EnvHashType;
|
||||
if (!gEnvHash) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEnvironment::Set(const nsAString& aName, const nsAString& aValue)
|
||||
{
|
||||
nsAutoCString nativeName;
|
||||
nsAutoCString nativeVal;
|
||||
nsAutoCString nativeName;
|
||||
nsAutoCString nativeVal;
|
||||
|
||||
nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
return rv;
|
||||
nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = NS_CopyUnicodeToNative(aValue, nativeVal);
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
return rv;
|
||||
rv = NS_CopyUnicodeToNative(aValue, nativeVal);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mLock);
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
if (!EnsureEnvHash()){
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
if (!EnsureEnvHash()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
EnvEntryType* entry = gEnvHash->PutEntry(nativeName.get());
|
||||
if (!entry) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
char* newData = PR_smprintf("%s=%s",
|
||||
nativeName.get(),
|
||||
nativeVal.get());
|
||||
if (!newData) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
PR_SetEnv(newData);
|
||||
if (entry->mData) {
|
||||
PR_smprintf_free(entry->mData);
|
||||
}
|
||||
entry->mData = newData;
|
||||
return NS_OK;
|
||||
EnvEntryType* entry = gEnvHash->PutEntry(nativeName.get());
|
||||
if (!entry) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
char* newData = PR_smprintf("%s=%s",
|
||||
nativeName.get(),
|
||||
nativeVal.get());
|
||||
if (!newData) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
PR_SetEnv(newData);
|
||||
if (entry->mData) {
|
||||
PR_smprintf_free(entry->mData);
|
||||
}
|
||||
entry->mData = newData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
@ -18,17 +19,18 @@
|
||||
class nsEnvironment MOZ_FINAL : public nsIEnvironment
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIENVIRONMENT
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIENVIRONMENT
|
||||
|
||||
static nsresult Create(nsISupports *aOuter, REFNSIID aIID,
|
||||
void **aResult);
|
||||
static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
||||
|
||||
private:
|
||||
nsEnvironment() : mLock("nsEnvironment.mLock") { }
|
||||
~nsEnvironment();
|
||||
nsEnvironment() : mLock("nsEnvironment.mLock")
|
||||
{
|
||||
}
|
||||
~nsEnvironment();
|
||||
|
||||
mozilla::Mutex mLock;
|
||||
mozilla::Mutex mLock;
|
||||
};
|
||||
|
||||
#endif /* !nsEnvironment_h__ */
|
||||
|
@ -14,12 +14,13 @@
|
||||
using namespace mozilla;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
static PRLogModuleInfo *
|
||||
static PRLogModuleInfo*
|
||||
GetLog()
|
||||
{
|
||||
static PRLogModuleInfo *sLog;
|
||||
if (!sLog)
|
||||
static PRLogModuleInfo* sLog;
|
||||
if (!sLog) {
|
||||
sLog = PR_NewLogModule("nsEventQueue");
|
||||
}
|
||||
return sLog;
|
||||
}
|
||||
#endif
|
||||
@ -41,35 +42,38 @@ nsEventQueue::~nsEventQueue()
|
||||
{
|
||||
// It'd be nice to be able to assert that no one else is holding the monitor,
|
||||
// but NSPR doesn't really expose APIs for it.
|
||||
NS_ASSERTION(IsEmpty(), "Non-empty event queue being destroyed; events being leaked.");
|
||||
NS_ASSERTION(IsEmpty(),
|
||||
"Non-empty event queue being destroyed; events being leaked.");
|
||||
|
||||
if (mHead)
|
||||
if (mHead) {
|
||||
FreePage(mHead);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsEventQueue::GetEvent(bool mayWait, nsIRunnable **result)
|
||||
nsEventQueue::GetEvent(bool aMayWait, nsIRunnable** aResult)
|
||||
{
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
|
||||
while (IsEmpty()) {
|
||||
if (!mayWait) {
|
||||
if (result)
|
||||
*result = nullptr;
|
||||
if (!aMayWait) {
|
||||
if (aResult) {
|
||||
*aResult = nullptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
LOG(("EVENTQ(%p): wait begin\n", this));
|
||||
LOG(("EVENTQ(%p): wait begin\n", this));
|
||||
mon.Wait();
|
||||
LOG(("EVENTQ(%p): wait end\n", this));
|
||||
LOG(("EVENTQ(%p): wait end\n", this));
|
||||
}
|
||||
|
||||
if (result) {
|
||||
*result = mHead->mEvents[mOffsetHead++];
|
||||
|
||||
|
||||
if (aResult) {
|
||||
*aResult = mHead->mEvents[mOffsetHead++];
|
||||
|
||||
// Check if mHead points to empty Page
|
||||
if (mOffsetHead == EVENTS_PER_PAGE) {
|
||||
Page *dead = mHead;
|
||||
Page* dead = mHead;
|
||||
mHead = mHead->mNext;
|
||||
FreePage(dead);
|
||||
mOffsetHead = 0;
|
||||
|
@ -23,7 +23,7 @@ public:
|
||||
// This method adds a new event to the pending event queue. The queue holds
|
||||
// a strong reference to the event after this method returns. This method
|
||||
// cannot fail.
|
||||
void PutEvent(nsIRunnable *event);
|
||||
void PutEvent(nsIRunnable* aEvent);
|
||||
|
||||
// This method gets an event from the event queue. If mayWait is true, then
|
||||
// the method will block the calling thread until an event is available. If
|
||||
@ -31,53 +31,63 @@ public:
|
||||
// or not an event is pending. When the resulting event is non-null, the
|
||||
// caller is responsible for releasing the event object. This method does
|
||||
// not alter the reference count of the resulting event.
|
||||
bool GetEvent(bool mayWait, nsIRunnable **event);
|
||||
bool GetEvent(bool aMayWait, nsIRunnable** aEvent);
|
||||
|
||||
// This method returns true if there is a pending event.
|
||||
bool HasPendingEvent() {
|
||||
bool HasPendingEvent()
|
||||
{
|
||||
return GetEvent(false, nullptr);
|
||||
}
|
||||
|
||||
// This method returns the next pending event or null.
|
||||
bool GetPendingEvent(nsIRunnable **runnable) {
|
||||
bool GetPendingEvent(nsIRunnable** runnable)
|
||||
{
|
||||
return GetEvent(false, runnable);
|
||||
}
|
||||
|
||||
// Expose the event queue's monitor for "power users"
|
||||
ReentrantMonitor& GetReentrantMonitor() {
|
||||
ReentrantMonitor& GetReentrantMonitor()
|
||||
{
|
||||
return mReentrantMonitor;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool IsEmpty() {
|
||||
bool IsEmpty()
|
||||
{
|
||||
return !mHead || (mHead == mTail && mOffsetHead == mOffsetTail);
|
||||
}
|
||||
|
||||
enum { EVENTS_PER_PAGE = 255 };
|
||||
enum
|
||||
{
|
||||
EVENTS_PER_PAGE = 255
|
||||
};
|
||||
|
||||
// Page objects are linked together to form a simple deque.
|
||||
|
||||
struct Page {
|
||||
struct Page *mNext;
|
||||
nsIRunnable *mEvents[EVENTS_PER_PAGE];
|
||||
struct Page
|
||||
{
|
||||
struct Page* mNext;
|
||||
nsIRunnable* mEvents[EVENTS_PER_PAGE];
|
||||
};
|
||||
|
||||
static_assert((sizeof(Page) & (sizeof(Page) - 1)) == 0,
|
||||
"sizeof(Page) should be a power of two to avoid heap slop.");
|
||||
|
||||
static Page *NewPage() {
|
||||
return static_cast<Page *>(moz_xcalloc(1, sizeof(Page)));
|
||||
static Page* NewPage()
|
||||
{
|
||||
return static_cast<Page*>(moz_xcalloc(1, sizeof(Page)));
|
||||
}
|
||||
|
||||
static void FreePage(Page *p) {
|
||||
free(p);
|
||||
static void FreePage(Page* aPage)
|
||||
{
|
||||
free(aPage);
|
||||
}
|
||||
|
||||
ReentrantMonitor mReentrantMonitor;
|
||||
|
||||
Page *mHead;
|
||||
Page *mTail;
|
||||
Page* mHead;
|
||||
Page* mTail;
|
||||
|
||||
uint16_t mOffsetHead; // offset into mHead where next item is removed
|
||||
uint16_t mOffsetTail; // offset into mTail where next item is added
|
||||
|
@ -24,14 +24,14 @@ NS_GetPendingMemoryPressure()
|
||||
}
|
||||
|
||||
void
|
||||
NS_DispatchEventualMemoryPressure(MemoryPressureState state)
|
||||
NS_DispatchEventualMemoryPressure(MemoryPressureState aState)
|
||||
{
|
||||
/*
|
||||
* A new memory pressure event erases an ongoing memory pressure, but an
|
||||
* existing "new" memory pressure event takes precedence over a new "ongoing"
|
||||
* memory pressure event.
|
||||
*/
|
||||
switch (state) {
|
||||
switch (aState) {
|
||||
case MemPressure_None:
|
||||
sMemoryPressurePending = MemPressure_None;
|
||||
break;
|
||||
@ -39,15 +39,16 @@ NS_DispatchEventualMemoryPressure(MemoryPressureState state)
|
||||
sMemoryPressurePending = MemPressure_New;
|
||||
break;
|
||||
case MemPressure_Ongoing:
|
||||
sMemoryPressurePending.compareExchange(MemPressure_None, MemPressure_Ongoing);
|
||||
sMemoryPressurePending.compareExchange(MemPressure_None,
|
||||
MemPressure_Ongoing);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_DispatchMemoryPressure(MemoryPressureState state)
|
||||
NS_DispatchMemoryPressure(MemoryPressureState aState)
|
||||
{
|
||||
NS_DispatchEventualMemoryPressure(state);
|
||||
NS_DispatchEventualMemoryPressure(aState);
|
||||
nsCOMPtr<nsIRunnable> event = new nsRunnable;
|
||||
return NS_DispatchToMainThread(event);
|
||||
}
|
||||
|
@ -9,7 +9,8 @@
|
||||
|
||||
#include "nscore.h"
|
||||
|
||||
enum MemoryPressureState {
|
||||
enum MemoryPressureState
|
||||
{
|
||||
/*
|
||||
* No memory pressure.
|
||||
*/
|
||||
@ -59,7 +60,7 @@ NS_GetPendingMemoryPressure();
|
||||
* You may call this function from any thread.
|
||||
*/
|
||||
void
|
||||
NS_DispatchEventualMemoryPressure(MemoryPressureState state);
|
||||
NS_DispatchEventualMemoryPressure(MemoryPressureState aState);
|
||||
|
||||
/**
|
||||
* This function causes the main thread to fire a memory pressure event
|
||||
@ -71,6 +72,6 @@ NS_DispatchEventualMemoryPressure(MemoryPressureState state);
|
||||
* You may call this function from any thread.
|
||||
*/
|
||||
nsresult
|
||||
NS_DispatchMemoryPressure(MemoryPressureState state);
|
||||
NS_DispatchMemoryPressure(MemoryPressureState aState);
|
||||
|
||||
#endif // nsMemoryPressure_h__
|
||||
|
@ -31,8 +31,9 @@
|
||||
{0x7b4eeb20, 0xd781, 0x11d4, \
|
||||
{0x8A, 0x83, 0x00, 0x10, 0xa4, 0xe0, 0xc9, 0xca}}
|
||||
|
||||
class nsProcess MOZ_FINAL : public nsIProcess,
|
||||
public nsIObserver
|
||||
class nsProcess MOZ_FINAL
|
||||
: public nsIProcess
|
||||
, public nsIObserver
|
||||
{
|
||||
public:
|
||||
|
||||
@ -44,17 +45,17 @@ public:
|
||||
|
||||
private:
|
||||
~nsProcess();
|
||||
static void Monitor(void *arg);
|
||||
static void Monitor(void* aArg);
|
||||
void ProcessComplete();
|
||||
nsresult CopyArgsAndRunProcess(bool blocking, const char** args,
|
||||
uint32_t count, nsIObserver* observer,
|
||||
bool holdWeak);
|
||||
nsresult CopyArgsAndRunProcessw(bool blocking, const char16_t** args,
|
||||
uint32_t count, nsIObserver* observer,
|
||||
bool holdWeak);
|
||||
nsresult CopyArgsAndRunProcess(bool aBlocking, const char** aArgs,
|
||||
uint32_t aCount, nsIObserver* aObserver,
|
||||
bool aHoldWeak);
|
||||
nsresult CopyArgsAndRunProcessw(bool aBlocking, const char16_t** aArgs,
|
||||
uint32_t aCount, nsIObserver* aObserver,
|
||||
bool aHoldWeak);
|
||||
// The 'args' array is null-terminated.
|
||||
nsresult RunProcess(bool blocking, char **args, nsIObserver* observer,
|
||||
bool holdWeak, bool argsUTF8);
|
||||
nsresult RunProcess(bool aBlocking, char** aArgs, nsIObserver* aObserver,
|
||||
bool aHoldWeak, bool aArgsUTF8);
|
||||
|
||||
PRThread* mThread;
|
||||
mozilla::Mutex mLock;
|
||||
@ -73,7 +74,7 @@ private:
|
||||
#if defined(PROCESSMODEL_WINAPI)
|
||||
HANDLE mProcess;
|
||||
#elif !defined(XP_MACOSX)
|
||||
PRProcess *mProcess;
|
||||
PRProcess* mProcess;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -67,12 +67,13 @@ using namespace mozilla::tasktracer;
|
||||
using namespace mozilla;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
static PRLogModuleInfo *
|
||||
static PRLogModuleInfo*
|
||||
GetThreadLog()
|
||||
{
|
||||
static PRLogModuleInfo *sLog;
|
||||
if (!sLog)
|
||||
static PRLogModuleInfo* sLog;
|
||||
if (!sLog) {
|
||||
sLog = PR_NewLogModule("nsThread");
|
||||
}
|
||||
return sLog;
|
||||
}
|
||||
#endif
|
||||
@ -89,68 +90,79 @@ nsIThreadObserver* nsThread::sMainThreadObserver = nullptr;
|
||||
// Because we do not have our own nsIFactory, we have to implement nsIClassInfo
|
||||
// somewhat manually.
|
||||
|
||||
class nsThreadClassInfo : public nsIClassInfo {
|
||||
class nsThreadClassInfo : public nsIClassInfo
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED // no mRefCnt
|
||||
NS_DECL_NSICLASSINFO
|
||||
|
||||
nsThreadClassInfo() {}
|
||||
nsThreadClassInfo()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMETHODIMP_(MozExternalRefCountType) nsThreadClassInfo::AddRef() { return 2; }
|
||||
NS_IMETHODIMP_(MozExternalRefCountType) nsThreadClassInfo::Release() { return 1; }
|
||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||
nsThreadClassInfo::AddRef()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||
nsThreadClassInfo::Release()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
NS_IMPL_QUERY_INTERFACE(nsThreadClassInfo, nsIClassInfo)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetInterfaces(uint32_t *count, nsIID ***array)
|
||||
nsThreadClassInfo::GetInterfaces(uint32_t* aCount, nsIID*** aArray)
|
||||
{
|
||||
return NS_CI_INTERFACE_GETTER_NAME(nsThread)(count, array);
|
||||
return NS_CI_INTERFACE_GETTER_NAME(nsThread)(aCount, aArray);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetHelperForLanguage(uint32_t lang, nsISupports **result)
|
||||
nsThreadClassInfo::GetHelperForLanguage(uint32_t aLang, nsISupports** aResult)
|
||||
{
|
||||
*result = nullptr;
|
||||
*aResult = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetContractID(char **result)
|
||||
nsThreadClassInfo::GetContractID(char** aResult)
|
||||
{
|
||||
*result = nullptr;
|
||||
*aResult = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetClassDescription(char **result)
|
||||
nsThreadClassInfo::GetClassDescription(char** aResult)
|
||||
{
|
||||
*result = nullptr;
|
||||
*aResult = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetClassID(nsCID **result)
|
||||
nsThreadClassInfo::GetClassID(nsCID** aResult)
|
||||
{
|
||||
*result = nullptr;
|
||||
*aResult = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetImplementationLanguage(uint32_t *result)
|
||||
nsThreadClassInfo::GetImplementationLanguage(uint32_t* aResult)
|
||||
{
|
||||
*result = nsIProgrammingLanguage::CPLUSPLUS;
|
||||
*aResult = nsIProgrammingLanguage::CPLUSPLUS;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetFlags(uint32_t *result)
|
||||
nsThreadClassInfo::GetFlags(uint32_t* aResult)
|
||||
{
|
||||
*result = THREADSAFE;
|
||||
*aResult = THREADSAFE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetClassIDNoAlloc(nsCID *result)
|
||||
nsThreadClassInfo::GetClassIDNoAlloc(nsCID* aResult)
|
||||
{
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
@ -175,30 +187,39 @@ NS_IMPL_CI_INTERFACE_GETTER(nsThread, nsIThread, nsIThreadInternal,
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsThreadStartupEvent : public nsRunnable {
|
||||
class nsThreadStartupEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsThreadStartupEvent()
|
||||
: mMon("nsThreadStartupEvent.mMon")
|
||||
, mInitialized(false) {
|
||||
, mInitialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
// This method does not return until the thread startup object is in the
|
||||
// completion state.
|
||||
void Wait() {
|
||||
if (mInitialized) // Maybe avoid locking...
|
||||
void Wait()
|
||||
{
|
||||
if (mInitialized) {
|
||||
// Maybe avoid locking...
|
||||
return;
|
||||
}
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mMon);
|
||||
while (!mInitialized)
|
||||
while (!mInitialized) {
|
||||
mon.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
// This method needs to be public to support older compilers (xlC_r on AIX).
|
||||
// It should be called directly as this class type is reference counted.
|
||||
virtual ~nsThreadStartupEvent() {
|
||||
virtual ~nsThreadStartupEvent()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
NS_IMETHOD Run() {
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMon);
|
||||
mInitialized = true;
|
||||
mon.Notify();
|
||||
@ -206,45 +227,53 @@ private:
|
||||
}
|
||||
|
||||
ReentrantMonitor mMon;
|
||||
bool mInitialized;
|
||||
bool mInitialized;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct nsThreadShutdownContext {
|
||||
nsThread *joiningThread;
|
||||
struct nsThreadShutdownContext
|
||||
{
|
||||
nsThread* joiningThread;
|
||||
bool shutdownAck;
|
||||
};
|
||||
|
||||
// This event is responsible for notifying nsThread::Shutdown that it is time
|
||||
// to call PR_JoinThread.
|
||||
class nsThreadShutdownAckEvent : public nsRunnable {
|
||||
class nsThreadShutdownAckEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsThreadShutdownAckEvent(nsThreadShutdownContext *ctx)
|
||||
: mShutdownContext(ctx) {
|
||||
nsThreadShutdownAckEvent(nsThreadShutdownContext* aCtx)
|
||||
: mShutdownContext(aCtx)
|
||||
{
|
||||
}
|
||||
NS_IMETHOD Run() {
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mShutdownContext->shutdownAck = true;
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsThreadShutdownContext *mShutdownContext;
|
||||
nsThreadShutdownContext* mShutdownContext;
|
||||
};
|
||||
|
||||
// This event is responsible for setting mShutdownContext
|
||||
class nsThreadShutdownEvent : public nsRunnable {
|
||||
class nsThreadShutdownEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsThreadShutdownEvent(nsThread *thr, nsThreadShutdownContext *ctx)
|
||||
: mThread(thr), mShutdownContext(ctx) {
|
||||
}
|
||||
NS_IMETHOD Run() {
|
||||
nsThreadShutdownEvent(nsThread* aThr, nsThreadShutdownContext* aCtx)
|
||||
: mThread(aThr)
|
||||
, mShutdownContext(aCtx)
|
||||
{
|
||||
}
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mThread->mShutdownContext = mShutdownContext;
|
||||
MessageLoop::current()->Quit();
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsRefPtr<nsThread> mThread;
|
||||
nsThreadShutdownContext *mShutdownContext;
|
||||
nsThreadShutdownContext* mShutdownContext;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -272,8 +301,8 @@ SetupCurrentThreadForChaosMode()
|
||||
setpriority(PRIO_PROCESS, 0, ChaosMode::randomUint32LessThan(4));
|
||||
#else
|
||||
// We should set the affinity here but NSPR doesn't provide a way to expose it.
|
||||
PR_SetThreadPriority(PR_GetCurrentThread(),
|
||||
PRThreadPriority(ChaosMode::randomUint32LessThan(PR_PRIORITY_LAST + 1)));
|
||||
uint32_t priority = ChaosMode::randomUint32LessThan(PR_PRIORITY_LAST + 1);
|
||||
PR_SetThreadPriority(PR_GetCurrentThread(), PRThreadPriority(priority));
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SCHED_SETAFFINITY
|
||||
@ -288,9 +317,9 @@ SetupCurrentThreadForChaosMode()
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
nsThread::ThreadFunc(void *arg)
|
||||
nsThread::ThreadFunc(void* aArg)
|
||||
{
|
||||
nsThread *self = static_cast<nsThread *>(arg); // strong reference
|
||||
nsThread* self = static_cast<nsThread*>(aArg); // strong reference
|
||||
self->mThread = PR_GetCurrentThread();
|
||||
SetupCurrentThreadForChaosMode();
|
||||
|
||||
@ -308,7 +337,8 @@ nsThread::ThreadFunc(void *arg)
|
||||
event->Run(); // unblocks nsThread::Init
|
||||
event = nullptr;
|
||||
|
||||
{ // Scope for MessageLoop.
|
||||
{
|
||||
// Scope for MessageLoop.
|
||||
nsAutoPtr<MessageLoop> loop(
|
||||
new MessageLoop(MessageLoop::TYPE_MOZILLA_NONMAINTHREAD));
|
||||
|
||||
@ -384,13 +414,13 @@ nsThread::Init()
|
||||
{
|
||||
// spawn thread and wait until it is fully setup
|
||||
nsRefPtr<nsThreadStartupEvent> startup = new nsThreadStartupEvent();
|
||||
|
||||
|
||||
NS_ADDREF_THIS();
|
||||
|
||||
|
||||
mShutdownRequired = true;
|
||||
|
||||
// ThreadFunc is responsible for setting mThread
|
||||
PRThread *thr = PR_CreateThread(PR_USER_THREAD, ThreadFunc, this,
|
||||
PRThread* thr = PR_CreateThread(PR_USER_THREAD, ThreadFunc, this,
|
||||
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
|
||||
PR_JOINABLE_THREAD, mStackSize);
|
||||
if (!thr) {
|
||||
@ -423,84 +453,90 @@ nsThread::InitCurrentThread()
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsThread::PutEvent(nsIRunnable *event, nsNestedEventTarget *target)
|
||||
nsThread::PutEvent(nsIRunnable* aEvent, nsNestedEventTarget* aTarget)
|
||||
{
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
nsChainedEventQueue *queue = target ? target->mQueue : &mEventsRoot;
|
||||
nsChainedEventQueue* queue = aTarget ? aTarget->mQueue : &mEventsRoot;
|
||||
if (!queue || (queue == &mEventsRoot && mEventsAreDoomed)) {
|
||||
NS_WARNING("An event was posted to a thread that will never run it (rejected)");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
queue->PutEvent(event);
|
||||
queue->PutEvent(aEvent);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThreadObserver> obs = GetObserver();
|
||||
if (obs)
|
||||
if (obs) {
|
||||
obs->OnDispatchedEvent(this);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsThread::DispatchInternal(nsIRunnable *event, uint32_t flags,
|
||||
nsNestedEventTarget *target)
|
||||
nsThread::DispatchInternal(nsIRunnable* aEvent, uint32_t aFlags,
|
||||
nsNestedEventTarget* aTarget)
|
||||
{
|
||||
if (NS_WARN_IF(!event))
|
||||
if (NS_WARN_IF(!aEvent)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (gXPCOMThreadsShutDown && MAIN_THREAD != mIsMainThread && !target) {
|
||||
if (gXPCOMThreadsShutDown && MAIN_THREAD != mIsMainThread && !aTarget) {
|
||||
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
|
||||
}
|
||||
|
||||
#ifdef MOZ_TASK_TRACER
|
||||
nsRefPtr<nsIRunnable> tracedRunnable = CreateTracedRunnable(event);
|
||||
event = tracedRunnable;
|
||||
nsRefPtr<nsIRunnable> tracedRunnable = CreateTracedRunnable(aEvent);
|
||||
aEvent = tracedRunnable;
|
||||
#endif
|
||||
|
||||
if (flags & DISPATCH_SYNC) {
|
||||
nsThread *thread = nsThreadManager::get()->GetCurrentThread();
|
||||
if (NS_WARN_IF(!thread))
|
||||
if (aFlags & DISPATCH_SYNC) {
|
||||
nsThread* thread = nsThreadManager::get()->GetCurrentThread();
|
||||
if (NS_WARN_IF(!thread)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// XXX we should be able to do something better here... we should
|
||||
// be able to monitor the slot occupied by this event and use
|
||||
// that to tell us when the event has been processed.
|
||||
|
||||
nsRefPtr<nsThreadSyncDispatch> wrapper =
|
||||
new nsThreadSyncDispatch(thread, event);
|
||||
if (!wrapper)
|
||||
new nsThreadSyncDispatch(thread, aEvent);
|
||||
if (!wrapper) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
nsresult rv = PutEvent(wrapper, target);
|
||||
}
|
||||
nsresult rv = PutEvent(wrapper, aTarget);
|
||||
// Don't wait for the event to finish if we didn't dispatch it...
|
||||
if (NS_FAILED(rv))
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Allows waiting; ensure no locks are held that would deadlock us!
|
||||
while (wrapper->IsPending())
|
||||
while (wrapper->IsPending()) {
|
||||
NS_ProcessNextEvent(thread, true);
|
||||
}
|
||||
return wrapper->Result();
|
||||
}
|
||||
|
||||
NS_ASSERTION(flags == NS_DISPATCH_NORMAL, "unexpected dispatch flags");
|
||||
return PutEvent(event, target);
|
||||
NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "unexpected dispatch flags");
|
||||
return PutEvent(aEvent, aTarget);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIEventTarget
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::Dispatch(nsIRunnable *event, uint32_t flags)
|
||||
nsThread::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
|
||||
{
|
||||
LOG(("THRD(%p) Dispatch [%p %x]\n", this, event, flags));
|
||||
LOG(("THRD(%p) Dispatch [%p %x]\n", this, aEvent, aFlags));
|
||||
|
||||
return DispatchInternal(event, flags, nullptr);
|
||||
return DispatchInternal(aEvent, aFlags, nullptr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::IsOnCurrentThread(bool *result)
|
||||
nsThread::IsOnCurrentThread(bool* aResult)
|
||||
{
|
||||
*result = (PR_GetCurrentThread() == mThread);
|
||||
*aResult = (PR_GetCurrentThread() == mThread);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -508,9 +544,9 @@ nsThread::IsOnCurrentThread(bool *result)
|
||||
// nsIThread
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetPRThread(PRThread **result)
|
||||
nsThread::GetPRThread(PRThread** aResult)
|
||||
{
|
||||
*result = mThread;
|
||||
*aResult = mThread;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -522,17 +558,20 @@ nsThread::Shutdown()
|
||||
// XXX If we make this warn, then we hit that warning at xpcom shutdown while
|
||||
// shutting down a thread in a thread pool. That happens b/c the thread
|
||||
// in the thread pool is already shutdown by the thread manager.
|
||||
if (!mThread)
|
||||
if (!mThread) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(mThread == PR_GetCurrentThread()))
|
||||
if (NS_WARN_IF(mThread == PR_GetCurrentThread())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Prevent multiple calls to this method
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
if (!mShutdownRequired)
|
||||
if (!mShutdownRequired) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
mShutdownRequired = false;
|
||||
}
|
||||
|
||||
@ -543,19 +582,21 @@ nsThread::Shutdown()
|
||||
// Set mShutdownContext and wake up the thread in case it is waiting for
|
||||
// events to process.
|
||||
nsCOMPtr<nsIRunnable> event = new nsThreadShutdownEvent(this, &context);
|
||||
if (!event)
|
||||
if (!event) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
// XXXroc What if posting the event fails due to OOM?
|
||||
PutEvent(event, nullptr);
|
||||
|
||||
// We could still end up with other events being added after the shutdown
|
||||
// task, but that's okay because we process pending events in ThreadFunc
|
||||
// after setting mShutdownContext just before exiting.
|
||||
|
||||
|
||||
// Process events on the current thread until we receive a shutdown ACK.
|
||||
// Allows waiting; ensure no locks are held that would deadlock us!
|
||||
while (!context.shutdownAck)
|
||||
while (!context.shutdownAck) {
|
||||
NS_ProcessNextEvent(context.joiningThread, true);
|
||||
}
|
||||
|
||||
// Now, it should be safe to join without fear of dead-locking.
|
||||
|
||||
@ -578,44 +619,50 @@ nsThread::Shutdown()
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::HasPendingEvents(bool *result)
|
||||
nsThread::HasPendingEvents(bool* aResult)
|
||||
{
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread))
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) {
|
||||
return NS_ERROR_NOT_SAME_THREAD;
|
||||
}
|
||||
|
||||
*result = mEvents->GetEvent(false, nullptr);
|
||||
*aResult = mEvents->GetEvent(false, nullptr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef MOZ_CANARY
|
||||
void canary_alarm_handler (int signum);
|
||||
void canary_alarm_handler(int signum);
|
||||
|
||||
class Canary {
|
||||
//XXX ToDo: support nested loops
|
||||
class Canary
|
||||
{
|
||||
//XXX ToDo: support nested loops
|
||||
public:
|
||||
Canary() {
|
||||
Canary()
|
||||
{
|
||||
if (sCanaryOutputFD > 0 && EventLatencyIsImportant()) {
|
||||
signal(SIGALRM, canary_alarm_handler);
|
||||
ualarm(15000, 0);
|
||||
ualarm(15000, 0);
|
||||
}
|
||||
}
|
||||
|
||||
~Canary() {
|
||||
if (sCanaryOutputFD != 0 && EventLatencyIsImportant())
|
||||
~Canary()
|
||||
{
|
||||
if (sCanaryOutputFD != 0 && EventLatencyIsImportant()) {
|
||||
ualarm(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static bool EventLatencyIsImportant() {
|
||||
static bool EventLatencyIsImportant()
|
||||
{
|
||||
return NS_IsMainThread() && XRE_GetProcessType() == GeckoProcessType_Default;
|
||||
}
|
||||
};
|
||||
|
||||
void canary_alarm_handler (int signum)
|
||||
void canary_alarm_handler(int signum)
|
||||
{
|
||||
void *array[30];
|
||||
void* array[30];
|
||||
const char msg[29] = "event took too long to run:\n";
|
||||
// use write to be safe in the signal handler
|
||||
write(sCanaryOutputFD, msg, sizeof(msg));
|
||||
write(sCanaryOutputFD, msg, sizeof(msg));
|
||||
backtrace_symbols_fd(array, backtrace(array, 30), sCanaryOutputFD);
|
||||
}
|
||||
|
||||
@ -635,12 +682,13 @@ void canary_alarm_handler (int signum)
|
||||
PR_END_MACRO
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::ProcessNextEvent(bool mayWait, bool *result)
|
||||
nsThread::ProcessNextEvent(bool aMayWait, bool* aResult)
|
||||
{
|
||||
LOG(("THRD(%p) ProcessNextEvent [%u %u]\n", this, mayWait, mRunningEvent));
|
||||
LOG(("THRD(%p) ProcessNextEvent [%u %u]\n", this, aMayWait, mRunningEvent));
|
||||
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread))
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) {
|
||||
return NS_ERROR_NOT_SAME_THREAD;
|
||||
}
|
||||
|
||||
// The toplevel event loop normally blocks waiting for the next event, but
|
||||
// if we're trying to shut this thread down, we must exit the event loop when
|
||||
@ -650,10 +698,11 @@ nsThread::ProcessNextEvent(bool mayWait, bool *result)
|
||||
// to block even if something has requested shutdown of the thread. Otherwise
|
||||
// we'll just busywait as we endlessly look for an event, fail to find one,
|
||||
// and repeat the nested event loop since its state change hasn't happened yet.
|
||||
bool reallyWait = mayWait && (mRunningEvent > 0 || !ShuttingDown());
|
||||
bool reallyWait = aMayWait && (mRunningEvent > 0 || !ShuttingDown());
|
||||
|
||||
if (MAIN_THREAD == mIsMainThread && reallyWait)
|
||||
if (MAIN_THREAD == mIsMainThread && reallyWait) {
|
||||
HangMonitor::Suspend();
|
||||
}
|
||||
|
||||
// Fire a memory pressure notification, if we're the main thread and one is
|
||||
// pending.
|
||||
@ -670,7 +719,7 @@ nsThread::ProcessNextEvent(bool mayWait, bool *result)
|
||||
if (os) {
|
||||
os->NotifyObservers(nullptr, "memory-pressure",
|
||||
mpPending == MemPressure_New ? lowMem.get() :
|
||||
lowMemOngoing.get());
|
||||
lowMemOngoing.get());
|
||||
} else {
|
||||
NS_WARNING("Can't get observer service!");
|
||||
}
|
||||
@ -679,12 +728,14 @@ nsThread::ProcessNextEvent(bool mayWait, bool *result)
|
||||
|
||||
bool notifyMainThreadObserver =
|
||||
(MAIN_THREAD == mIsMainThread) && sMainThreadObserver;
|
||||
if (notifyMainThreadObserver)
|
||||
sMainThreadObserver->OnProcessNextEvent(this, reallyWait, mRunningEvent);
|
||||
if (notifyMainThreadObserver) {
|
||||
sMainThreadObserver->OnProcessNextEvent(this, reallyWait, mRunningEvent);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThreadObserver> obs = mObserver;
|
||||
if (obs)
|
||||
if (obs) {
|
||||
obs->OnProcessNextEvent(this, reallyWait, mRunningEvent);
|
||||
}
|
||||
|
||||
NOTIFY_EVENT_OBSERVERS(OnProcessNextEvent,
|
||||
(this, reallyWait, mRunningEvent));
|
||||
@ -705,14 +756,15 @@ nsThread::ProcessNextEvent(bool mayWait, bool *result)
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
mEvents->GetEvent(reallyWait, getter_AddRefs(event));
|
||||
|
||||
*result = (event.get() != nullptr);
|
||||
*aResult = (event.get() != nullptr);
|
||||
|
||||
if (event) {
|
||||
LOG(("THRD(%p) running [%p]\n", this, event.get()));
|
||||
if (MAIN_THREAD == mIsMainThread)
|
||||
if (MAIN_THREAD == mIsMainThread) {
|
||||
HangMonitor::NotifyActivity();
|
||||
}
|
||||
event->Run();
|
||||
} else if (mayWait) {
|
||||
} else if (aMayWait) {
|
||||
MOZ_ASSERT(ShuttingDown(),
|
||||
"This should only happen when shutting down");
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
@ -722,13 +774,15 @@ nsThread::ProcessNextEvent(bool mayWait, bool *result)
|
||||
--mRunningEvent;
|
||||
|
||||
NOTIFY_EVENT_OBSERVERS(AfterProcessNextEvent,
|
||||
(this, mRunningEvent, *result));
|
||||
(this, mRunningEvent, *aResult));
|
||||
|
||||
if (obs)
|
||||
obs->AfterProcessNextEvent(this, mRunningEvent, *result);
|
||||
if (obs) {
|
||||
obs->AfterProcessNextEvent(this, mRunningEvent, *aResult);
|
||||
}
|
||||
|
||||
if (notifyMainThreadObserver && sMainThreadObserver)
|
||||
sMainThreadObserver->AfterProcessNextEvent(this, mRunningEvent, *result);
|
||||
if (notifyMainThreadObserver && sMainThreadObserver) {
|
||||
sMainThreadObserver->AfterProcessNextEvent(this, mRunningEvent, *aResult);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -737,17 +791,18 @@ nsThread::ProcessNextEvent(bool mayWait, bool *result)
|
||||
// nsISupportsPriority
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetPriority(int32_t *priority)
|
||||
nsThread::GetPriority(int32_t* aPriority)
|
||||
{
|
||||
*priority = mPriority;
|
||||
*aPriority = mPriority;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::SetPriority(int32_t priority)
|
||||
nsThread::SetPriority(int32_t aPriority)
|
||||
{
|
||||
if (NS_WARN_IF(!mThread))
|
||||
if (NS_WARN_IF(!mThread)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
// NSPR defines the following four thread priorities:
|
||||
// PR_PRIORITY_LOW
|
||||
@ -756,7 +811,7 @@ nsThread::SetPriority(int32_t priority)
|
||||
// PR_PRIORITY_URGENT
|
||||
// We map the priority values defined on nsISupportsPriority to these values.
|
||||
|
||||
mPriority = priority;
|
||||
mPriority = aPriority;
|
||||
|
||||
PRThreadPriority pri;
|
||||
if (mPriority <= PRIORITY_HIGHEST) {
|
||||
@ -777,55 +832,59 @@ nsThread::SetPriority(int32_t priority)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::AdjustPriority(int32_t delta)
|
||||
nsThread::AdjustPriority(int32_t aDelta)
|
||||
{
|
||||
return SetPriority(mPriority + delta);
|
||||
return SetPriority(mPriority + aDelta);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIThreadInternal
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetObserver(nsIThreadObserver **obs)
|
||||
nsThread::GetObserver(nsIThreadObserver** aObs)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
NS_IF_ADDREF(*obs = mObserver);
|
||||
NS_IF_ADDREF(*aObs = mObserver);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::SetObserver(nsIThreadObserver *obs)
|
||||
nsThread::SetObserver(nsIThreadObserver* aObs)
|
||||
{
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread))
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) {
|
||||
return NS_ERROR_NOT_SAME_THREAD;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mLock);
|
||||
mObserver = obs;
|
||||
mObserver = aObs;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetRecursionDepth(uint32_t *depth)
|
||||
nsThread::GetRecursionDepth(uint32_t* aDepth)
|
||||
{
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread))
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) {
|
||||
return NS_ERROR_NOT_SAME_THREAD;
|
||||
}
|
||||
|
||||
*depth = mRunningEvent;
|
||||
*aDepth = mRunningEvent;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::AddObserver(nsIThreadObserver *observer)
|
||||
nsThread::AddObserver(nsIThreadObserver* aObserver)
|
||||
{
|
||||
if (NS_WARN_IF(!observer))
|
||||
if (NS_WARN_IF(!aObserver)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread))
|
||||
}
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) {
|
||||
return NS_ERROR_NOT_SAME_THREAD;
|
||||
}
|
||||
|
||||
NS_WARN_IF_FALSE(!mEventObservers.Contains(observer),
|
||||
NS_WARN_IF_FALSE(!mEventObservers.Contains(aObserver),
|
||||
"Adding an observer twice!");
|
||||
|
||||
if (!mEventObservers.AppendElement(observer)) {
|
||||
if (!mEventObservers.AppendElement(aObserver)) {
|
||||
NS_WARNING("Out of memory!");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -834,12 +893,13 @@ nsThread::AddObserver(nsIThreadObserver *observer)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::RemoveObserver(nsIThreadObserver *observer)
|
||||
nsThread::RemoveObserver(nsIThreadObserver* aObserver)
|
||||
{
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread))
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) {
|
||||
return NS_ERROR_NOT_SAME_THREAD;
|
||||
}
|
||||
|
||||
if (observer && !mEventObservers.RemoveElement(observer)) {
|
||||
if (aObserver && !mEventObservers.RemoveElement(aObserver)) {
|
||||
NS_WARNING("Removing an observer that was never added!");
|
||||
}
|
||||
|
||||
@ -847,12 +907,13 @@ nsThread::RemoveObserver(nsIThreadObserver *observer)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::PushEventQueue(nsIEventTarget **result)
|
||||
nsThread::PushEventQueue(nsIEventTarget** aResult)
|
||||
{
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread))
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) {
|
||||
return NS_ERROR_NOT_SAME_THREAD;
|
||||
}
|
||||
|
||||
nsChainedEventQueue *queue = new nsChainedEventQueue();
|
||||
nsChainedEventQueue* queue = new nsChainedEventQueue();
|
||||
queue->mEventTarget = new nsNestedEventTarget(this, queue);
|
||||
|
||||
{
|
||||
@ -861,18 +922,20 @@ nsThread::PushEventQueue(nsIEventTarget **result)
|
||||
mEvents = queue;
|
||||
}
|
||||
|
||||
NS_ADDREF(*result = queue->mEventTarget);
|
||||
NS_ADDREF(*aResult = queue->mEventTarget);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::PopEventQueue(nsIEventTarget *innermostTarget)
|
||||
nsThread::PopEventQueue(nsIEventTarget* aInnermostTarget)
|
||||
{
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread))
|
||||
if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) {
|
||||
return NS_ERROR_NOT_SAME_THREAD;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!innermostTarget))
|
||||
if (NS_WARN_IF(!aInnermostTarget)) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
// Don't delete or release anything while holding the lock.
|
||||
nsAutoPtr<nsChainedEventQueue> queue;
|
||||
@ -882,8 +945,9 @@ nsThread::PopEventQueue(nsIEventTarget *innermostTarget)
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
// Make sure we're popping the innermost event target.
|
||||
if (NS_WARN_IF(mEvents->mEventTarget != innermostTarget))
|
||||
if (NS_WARN_IF(mEvents->mEventTarget != aInnermostTarget)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mEvents != &mEventsRoot);
|
||||
|
||||
@ -891,8 +955,9 @@ nsThread::PopEventQueue(nsIEventTarget *innermostTarget)
|
||||
mEvents = mEvents->mNext;
|
||||
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
while (queue->GetEvent(false, getter_AddRefs(event)))
|
||||
while (queue->GetEvent(false, getter_AddRefs(event))) {
|
||||
mEvents->PutEvent(event);
|
||||
}
|
||||
|
||||
// Don't let the event target post any more events.
|
||||
queue->mEventTarget.swap(target);
|
||||
@ -936,16 +1001,16 @@ nsThreadSyncDispatch::Run()
|
||||
NS_IMPL_ISUPPORTS(nsThread::nsNestedEventTarget, nsIEventTarget)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::nsNestedEventTarget::Dispatch(nsIRunnable *event, uint32_t flags)
|
||||
nsThread::nsNestedEventTarget::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
|
||||
{
|
||||
LOG(("THRD(%p) Dispatch [%p %x] to nested loop %p\n", mThread.get(), event,
|
||||
flags, this));
|
||||
LOG(("THRD(%p) Dispatch [%p %x] to nested loop %p\n", mThread.get(), aEvent,
|
||||
aFlags, this));
|
||||
|
||||
return mThread->DispatchInternal(event, flags, this);
|
||||
return mThread->DispatchInternal(aEvent, aFlags, this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::nsNestedEventTarget::IsOnCurrentThread(bool *result)
|
||||
nsThread::nsNestedEventTarget::IsOnCurrentThread(bool* aResult)
|
||||
{
|
||||
return mThread->IsOnCurrentThread(result);
|
||||
return mThread->IsOnCurrentThread(aResult);
|
||||
}
|
||||
|
@ -18,8 +18,9 @@
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
// A native thread
|
||||
class nsThread : public nsIThreadInternal,
|
||||
public nsISupportsPriority
|
||||
class nsThread
|
||||
: public nsIThreadInternal
|
||||
, public nsISupportsPriority
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
@ -28,7 +29,8 @@ public:
|
||||
NS_DECL_NSITHREADINTERNAL
|
||||
NS_DECL_NSISUPPORTSPRIORITY
|
||||
|
||||
enum MainThreadFlag {
|
||||
enum MainThreadFlag
|
||||
{
|
||||
MAIN_THREAD,
|
||||
NOT_MAIN_THREAD
|
||||
};
|
||||
@ -42,14 +44,23 @@ public:
|
||||
nsresult InitCurrentThread();
|
||||
|
||||
// The PRThread corresponding to this thread.
|
||||
PRThread *GetPRThread() { return mThread; }
|
||||
PRThread* GetPRThread()
|
||||
{
|
||||
return mThread;
|
||||
}
|
||||
|
||||
// If this flag is true, then the nsThread was created using
|
||||
// nsIThreadManager::NewThread.
|
||||
bool ShutdownRequired() { return mShutdownRequired; }
|
||||
bool ShutdownRequired()
|
||||
{
|
||||
return mShutdownRequired;
|
||||
}
|
||||
|
||||
// Clear the observer list.
|
||||
void ClearObservers() { mEventObservers.Clear(); }
|
||||
void ClearObservers()
|
||||
{
|
||||
mEventObservers.Clear();
|
||||
}
|
||||
|
||||
static nsresult
|
||||
SetMainThreadObserver(nsIThreadObserver* aObserver);
|
||||
@ -66,59 +77,72 @@ protected:
|
||||
|
||||
virtual ~nsThread();
|
||||
|
||||
bool ShuttingDown() { return mShutdownContext != nullptr; }
|
||||
bool ShuttingDown()
|
||||
{
|
||||
return mShutdownContext != nullptr;
|
||||
}
|
||||
|
||||
static void ThreadFunc(void *arg);
|
||||
static void ThreadFunc(void* aArg);
|
||||
|
||||
// Helper
|
||||
already_AddRefed<nsIThreadObserver> GetObserver() {
|
||||
nsIThreadObserver *obs;
|
||||
already_AddRefed<nsIThreadObserver> GetObserver()
|
||||
{
|
||||
nsIThreadObserver* obs;
|
||||
nsThread::GetObserver(&obs);
|
||||
return already_AddRefed<nsIThreadObserver>(obs);
|
||||
}
|
||||
|
||||
// Wrappers for event queue methods:
|
||||
bool GetEvent(bool mayWait, nsIRunnable **event) {
|
||||
return mEvents->GetEvent(mayWait, event);
|
||||
bool GetEvent(bool aMayWait, nsIRunnable** aEvent)
|
||||
{
|
||||
return mEvents->GetEvent(aMayWait, aEvent);
|
||||
}
|
||||
nsresult PutEvent(nsIRunnable *event, nsNestedEventTarget *target);
|
||||
nsresult PutEvent(nsIRunnable* aEvent, nsNestedEventTarget* aTarget);
|
||||
|
||||
nsresult DispatchInternal(nsIRunnable *event, uint32_t flags,
|
||||
nsNestedEventTarget *target);
|
||||
nsresult DispatchInternal(nsIRunnable* aEvent, uint32_t aFlags,
|
||||
nsNestedEventTarget* aTarget);
|
||||
|
||||
// Wrapper for nsEventQueue that supports chaining.
|
||||
class nsChainedEventQueue {
|
||||
class nsChainedEventQueue
|
||||
{
|
||||
public:
|
||||
nsChainedEventQueue()
|
||||
: mNext(nullptr) {
|
||||
: mNext(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
bool GetEvent(bool mayWait, nsIRunnable **event) {
|
||||
return mQueue.GetEvent(mayWait, event);
|
||||
bool GetEvent(bool aMayWait, nsIRunnable** aEvent)
|
||||
{
|
||||
return mQueue.GetEvent(aMayWait, aEvent);
|
||||
}
|
||||
|
||||
void PutEvent(nsIRunnable *event) {
|
||||
mQueue.PutEvent(event);
|
||||
void PutEvent(nsIRunnable* aEvent)
|
||||
{
|
||||
mQueue.PutEvent(aEvent);
|
||||
}
|
||||
|
||||
bool HasPendingEvent() {
|
||||
bool HasPendingEvent()
|
||||
{
|
||||
return mQueue.HasPendingEvent();
|
||||
}
|
||||
|
||||
nsChainedEventQueue *mNext;
|
||||
nsChainedEventQueue* mNext;
|
||||
nsRefPtr<nsNestedEventTarget> mEventTarget;
|
||||
|
||||
private:
|
||||
nsEventQueue mQueue;
|
||||
};
|
||||
|
||||
class nsNestedEventTarget MOZ_FINAL : public nsIEventTarget {
|
||||
class nsNestedEventTarget MOZ_FINAL : public nsIEventTarget
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIEVENTTARGET
|
||||
|
||||
nsNestedEventTarget(nsThread *thread, nsChainedEventQueue *queue)
|
||||
: mThread(thread), mQueue(queue) {
|
||||
nsNestedEventTarget(nsThread* aThread, nsChainedEventQueue* aQueue)
|
||||
: mThread(aThread)
|
||||
, mQueue(aQueue)
|
||||
{
|
||||
}
|
||||
|
||||
nsRefPtr<nsThread> mThread;
|
||||
@ -127,7 +151,9 @@ protected:
|
||||
nsChainedEventQueue* mQueue;
|
||||
|
||||
private:
|
||||
~nsNestedEventTarget() {}
|
||||
~nsNestedEventTarget()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// This lock protects access to mObserver, mEvents and mEventsAreDoomed.
|
||||
@ -142,15 +168,15 @@ protected:
|
||||
// Only accessed on the target thread.
|
||||
nsAutoTObserverArray<nsCOMPtr<nsIThreadObserver>, 2> mEventObservers;
|
||||
|
||||
nsChainedEventQueue *mEvents; // never null
|
||||
nsChainedEventQueue* mEvents; // never null
|
||||
nsChainedEventQueue mEventsRoot;
|
||||
|
||||
int32_t mPriority;
|
||||
PRThread *mThread;
|
||||
PRThread* mThread;
|
||||
uint32_t mRunningEvent; // counter
|
||||
uint32_t mStackSize;
|
||||
|
||||
struct nsThreadShutdownContext *mShutdownContext;
|
||||
struct nsThreadShutdownContext* mShutdownContext;
|
||||
|
||||
bool mShutdownRequired;
|
||||
// Set to true when events posted to this thread will never run.
|
||||
@ -160,17 +186,23 @@ protected:
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsThreadSyncDispatch : public nsRunnable {
|
||||
class nsThreadSyncDispatch : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsThreadSyncDispatch(nsIThread *origin, nsIRunnable *task)
|
||||
: mOrigin(origin), mSyncTask(task), mResult(NS_ERROR_NOT_INITIALIZED) {
|
||||
nsThreadSyncDispatch(nsIThread* aOrigin, nsIRunnable* aTask)
|
||||
: mOrigin(aOrigin)
|
||||
, mSyncTask(aTask)
|
||||
, mResult(NS_ERROR_NOT_INITIALIZED)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsPending() {
|
||||
bool IsPending()
|
||||
{
|
||||
return mSyncTask != nullptr;
|
||||
}
|
||||
|
||||
nsresult Result() {
|
||||
nsresult Result()
|
||||
{
|
||||
return mResult;
|
||||
}
|
||||
|
||||
|
@ -24,27 +24,35 @@ DWORD gTLSThreadIDIndex = TlsAlloc();
|
||||
NS_TLS mozilla::threads::ID gTLSThreadID = mozilla::threads::Generic;
|
||||
#endif
|
||||
|
||||
typedef nsTArray< nsRefPtr<nsThread> > nsThreadArray;
|
||||
typedef nsTArray<nsRefPtr<nsThread>> nsThreadArray;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
ReleaseObject(void *data)
|
||||
ReleaseObject(void* aData)
|
||||
{
|
||||
static_cast<nsISupports *>(data)->Release();
|
||||
static_cast<nsISupports*>(aData)->Release();
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
AppendAndRemoveThread(PRThread *key, nsRefPtr<nsThread> &thread, void *arg)
|
||||
AppendAndRemoveThread(PRThread* aKey, nsRefPtr<nsThread>& aThread, void* aArg)
|
||||
{
|
||||
nsThreadArray *threads = static_cast<nsThreadArray *>(arg);
|
||||
threads->AppendElement(thread);
|
||||
nsThreadArray* threads = static_cast<nsThreadArray*>(aArg);
|
||||
threads->AppendElement(aThread);
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
// statically allocated instance
|
||||
NS_IMETHODIMP_(MozExternalRefCountType) nsThreadManager::AddRef() { return 2; }
|
||||
NS_IMETHODIMP_(MozExternalRefCountType) nsThreadManager::Release() { return 1; }
|
||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||
nsThreadManager::AddRef()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||
nsThreadManager::Release()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
NS_IMPL_CLASSINFO(nsThreadManager, nullptr,
|
||||
nsIClassInfo::THREADSAFE | nsIClassInfo::SINGLETON,
|
||||
NS_THREADMANAGER_CID)
|
||||
@ -59,11 +67,13 @@ nsThreadManager::Init()
|
||||
// Child processes need to initialize the thread manager before they
|
||||
// initialize XPCOM in order to set up the crash reporter. This leads to
|
||||
// situations where we get initialized twice.
|
||||
if (mInitialized)
|
||||
if (mInitialized) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (PR_NewThreadPrivateIndex(&mCurThreadIndex, ReleaseObject) == PR_FAILURE)
|
||||
if (PR_NewThreadPrivateIndex(&mCurThreadIndex, ReleaseObject) == PR_FAILURE) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mLock = new Mutex("nsThreadManager.mLock");
|
||||
|
||||
@ -71,9 +81,10 @@ nsThreadManager::Init()
|
||||
const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NONBLOCK;
|
||||
const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
char* env_var_flag = getenv("MOZ_KILL_CANARIES");
|
||||
sCanaryOutputFD = env_var_flag ? (env_var_flag[0] ?
|
||||
open(env_var_flag, flags, mode) :
|
||||
STDERR_FILENO) : 0;
|
||||
sCanaryOutputFD =
|
||||
env_var_flag ? (env_var_flag[0] ? open(env_var_flag, flags, mode) :
|
||||
STDERR_FILENO) :
|
||||
0;
|
||||
#endif
|
||||
|
||||
// Setup "main" thread
|
||||
@ -90,7 +101,7 @@ nsThreadManager::Init()
|
||||
mMainThread->GetPRThread(&mMainPRThread);
|
||||
|
||||
#ifdef XP_WIN
|
||||
TlsSetValue(gTLSThreadIDIndex, (void*) mozilla::threads::Main);
|
||||
TlsSetValue(gTLSThreadIDIndex, (void*)mozilla::threads::Main);
|
||||
#elif defined(NS_TLS)
|
||||
gTLSThreadID = mozilla::threads::Main;
|
||||
#endif
|
||||
@ -126,16 +137,17 @@ nsThreadManager::Shutdown()
|
||||
// accepting new events, but that could lead to badness if one of those
|
||||
// threads is stuck waiting for a response from another thread. To do it
|
||||
// right, we'd need some way to interrupt the threads.
|
||||
//
|
||||
//
|
||||
// Instead, we process events on the current thread while waiting for threads
|
||||
// to shutdown. This means that we have to preserve a mostly functioning
|
||||
// world until such time as the threads exit.
|
||||
|
||||
// Shutdown all threads that require it (join with threads that we created).
|
||||
for (uint32_t i = 0; i < threads.Length(); ++i) {
|
||||
nsThread *thread = threads[i];
|
||||
if (thread->ShutdownRequired())
|
||||
nsThread* thread = threads[i];
|
||||
if (thread->ShutdownRequired()) {
|
||||
thread->Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
// In case there are any more events somehow...
|
||||
@ -164,9 +176,9 @@ nsThreadManager::Shutdown()
|
||||
}
|
||||
|
||||
void
|
||||
nsThreadManager::RegisterCurrentThread(nsThread *thread)
|
||||
nsThreadManager::RegisterCurrentThread(nsThread* aThread)
|
||||
{
|
||||
MOZ_ASSERT(thread->GetPRThread() == PR_GetCurrentThread(), "bad thread");
|
||||
MOZ_ASSERT(aThread->GetPRThread() == PR_GetCurrentThread(), "bad aThread");
|
||||
|
||||
MutexAutoLock lock(*mLock);
|
||||
|
||||
@ -175,33 +187,34 @@ nsThreadManager::RegisterCurrentThread(nsThread *thread)
|
||||
mHighestNumberOfThreads = mCurrentNumberOfThreads;
|
||||
}
|
||||
|
||||
mThreadsByPRThread.Put(thread->GetPRThread(), thread); // XXX check OOM?
|
||||
mThreadsByPRThread.Put(aThread->GetPRThread(), aThread); // XXX check OOM?
|
||||
|
||||
NS_ADDREF(thread); // for TLS entry
|
||||
PR_SetThreadPrivate(mCurThreadIndex, thread);
|
||||
NS_ADDREF(aThread); // for TLS entry
|
||||
PR_SetThreadPrivate(mCurThreadIndex, aThread);
|
||||
}
|
||||
|
||||
void
|
||||
nsThreadManager::UnregisterCurrentThread(nsThread *thread)
|
||||
nsThreadManager::UnregisterCurrentThread(nsThread* aThread)
|
||||
{
|
||||
MOZ_ASSERT(thread->GetPRThread() == PR_GetCurrentThread(), "bad thread");
|
||||
MOZ_ASSERT(aThread->GetPRThread() == PR_GetCurrentThread(), "bad aThread");
|
||||
|
||||
MutexAutoLock lock(*mLock);
|
||||
|
||||
--mCurrentNumberOfThreads;
|
||||
mThreadsByPRThread.Remove(thread->GetPRThread());
|
||||
mThreadsByPRThread.Remove(aThread->GetPRThread());
|
||||
|
||||
PR_SetThreadPrivate(mCurThreadIndex, nullptr);
|
||||
// Ref-count balanced via ReleaseObject
|
||||
}
|
||||
|
||||
nsThread *
|
||||
nsThread*
|
||||
nsThreadManager::GetCurrentThread()
|
||||
{
|
||||
// read thread local storage
|
||||
void *data = PR_GetThreadPrivate(mCurThreadIndex);
|
||||
if (data)
|
||||
return static_cast<nsThread *>(data);
|
||||
void* data = PR_GetThreadPrivate(mCurThreadIndex);
|
||||
if (data) {
|
||||
return static_cast<nsThread*>(data);
|
||||
}
|
||||
|
||||
if (!mInitialized) {
|
||||
return nullptr;
|
||||
@ -209,24 +222,27 @@ nsThreadManager::GetCurrentThread()
|
||||
|
||||
// OK, that's fine. We'll dynamically create one :-)
|
||||
nsRefPtr<nsThread> thread = new nsThread(nsThread::NOT_MAIN_THREAD, 0);
|
||||
if (!thread || NS_FAILED(thread->InitCurrentThread()))
|
||||
if (!thread || NS_FAILED(thread->InitCurrentThread())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return thread.get(); // reference held in TLS
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadManager::NewThread(uint32_t creationFlags,
|
||||
uint32_t stackSize,
|
||||
nsIThread **result)
|
||||
nsThreadManager::NewThread(uint32_t aCreationFlags,
|
||||
uint32_t aStackSize,
|
||||
nsIThread** aResult)
|
||||
{
|
||||
// No new threads during Shutdown
|
||||
if (NS_WARN_IF(!mInitialized))
|
||||
if (NS_WARN_IF(!mInitialized)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
nsThread *thr = new nsThread(nsThread::NOT_MAIN_THREAD, stackSize);
|
||||
if (!thr)
|
||||
nsThread* thr = new nsThread(nsThread::NOT_MAIN_THREAD, aStackSize);
|
||||
if (!thr) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
NS_ADDREF(thr);
|
||||
|
||||
nsresult rv = thr->Init();
|
||||
@ -239,58 +255,63 @@ nsThreadManager::NewThread(uint32_t creationFlags,
|
||||
// however, it is possible that it could have also been replaced by now, so
|
||||
// we cannot really assert that it was added.
|
||||
|
||||
*result = thr;
|
||||
*aResult = thr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadManager::GetThreadFromPRThread(PRThread *thread, nsIThread **result)
|
||||
nsThreadManager::GetThreadFromPRThread(PRThread* aThread, nsIThread** aResult)
|
||||
{
|
||||
// Keep this functioning during Shutdown
|
||||
if (NS_WARN_IF(!mMainThread))
|
||||
if (NS_WARN_IF(!mMainThread)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
if (NS_WARN_IF(!thread))
|
||||
}
|
||||
if (NS_WARN_IF(!aThread)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsRefPtr<nsThread> temp;
|
||||
{
|
||||
MutexAutoLock lock(*mLock);
|
||||
mThreadsByPRThread.Get(thread, getter_AddRefs(temp));
|
||||
mThreadsByPRThread.Get(aThread, getter_AddRefs(temp));
|
||||
}
|
||||
|
||||
NS_IF_ADDREF(*result = temp);
|
||||
NS_IF_ADDREF(*aResult = temp);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadManager::GetMainThread(nsIThread **result)
|
||||
nsThreadManager::GetMainThread(nsIThread** aResult)
|
||||
{
|
||||
// Keep this functioning during Shutdown
|
||||
if (NS_WARN_IF(!mMainThread))
|
||||
if (NS_WARN_IF(!mMainThread)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
NS_ADDREF(*result = mMainThread);
|
||||
}
|
||||
NS_ADDREF(*aResult = mMainThread);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadManager::GetCurrentThread(nsIThread **result)
|
||||
nsThreadManager::GetCurrentThread(nsIThread** aResult)
|
||||
{
|
||||
// Keep this functioning during Shutdown
|
||||
if (NS_WARN_IF(!mMainThread))
|
||||
if (NS_WARN_IF(!mMainThread)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
*result = GetCurrentThread();
|
||||
if (!*result)
|
||||
}
|
||||
*aResult = GetCurrentThread();
|
||||
if (!*aResult) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*result);
|
||||
}
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadManager::GetIsMainThread(bool *result)
|
||||
nsThreadManager::GetIsMainThread(bool* aResult)
|
||||
{
|
||||
// This method may be called post-Shutdown
|
||||
|
||||
*result = (PR_GetCurrentThread() == mMainPRThread);
|
||||
*aResult = (PR_GetCurrentThread() == mMainPRThread);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,8 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITHREADMANAGER
|
||||
|
||||
static nsThreadManager *get() {
|
||||
static nsThreadManager* get()
|
||||
{
|
||||
static nsThreadManager sInstance;
|
||||
return &sInstance;
|
||||
}
|
||||
@ -33,15 +34,15 @@ public:
|
||||
|
||||
// Called by nsThread to inform the ThreadManager it exists. This method
|
||||
// must be called when the given thread is the current thread.
|
||||
void RegisterCurrentThread(nsThread *thread);
|
||||
void RegisterCurrentThread(nsThread* aThread);
|
||||
|
||||
// Called by nsThread to inform the ThreadManager it is going away. This
|
||||
// method must be called when the given thread is the current thread.
|
||||
void UnregisterCurrentThread(nsThread *thread);
|
||||
void UnregisterCurrentThread(nsThread* aThread);
|
||||
|
||||
// Returns the current thread. Returns null if OOM or if ThreadManager isn't
|
||||
// initialized.
|
||||
nsThread *GetCurrentThread();
|
||||
nsThread* GetCurrentThread();
|
||||
|
||||
// Returns the maximal number of threads that have been in existence
|
||||
// simultaneously during the execution of the thread manager.
|
||||
@ -49,7 +50,9 @@ public:
|
||||
|
||||
// This needs to be public in order to support static instantiation of this
|
||||
// class with older compilers (e.g., egcs-2.91.66).
|
||||
~nsThreadManager() {}
|
||||
~nsThreadManager()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
nsThreadManager()
|
||||
@ -58,22 +61,23 @@ private:
|
||||
, mLock(nullptr)
|
||||
, mInitialized(false)
|
||||
, mCurrentNumberOfThreads(1)
|
||||
, mHighestNumberOfThreads(1) {
|
||||
, mHighestNumberOfThreads(1)
|
||||
{
|
||||
}
|
||||
|
||||
nsRefPtrHashtable<nsPtrHashKey<PRThread>, nsThread> mThreadsByPRThread;
|
||||
unsigned mCurThreadIndex; // thread-local-storage index
|
||||
nsRefPtr<nsThread> mMainThread;
|
||||
PRThread *mMainPRThread;
|
||||
PRThread* mMainPRThread;
|
||||
// This is a pointer in order to allow creating nsThreadManager from
|
||||
// the static context in debug builds.
|
||||
nsAutoPtr<mozilla::Mutex> mLock; // protects tables
|
||||
bool mInitialized;
|
||||
|
||||
// The current number of threads
|
||||
uint32_t mCurrentNumberOfThreads;
|
||||
// The highest number of threads encountered so far during the session
|
||||
uint32_t mHighestNumberOfThreads;
|
||||
// The current number of threads
|
||||
uint32_t mCurrentNumberOfThreads;
|
||||
// The highest number of threads encountered so far during the session
|
||||
uint32_t mHighestNumberOfThreads;
|
||||
};
|
||||
|
||||
#define NS_THREADMANAGER_CID \
|
||||
|
@ -16,12 +16,13 @@
|
||||
using namespace mozilla;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
static PRLogModuleInfo *
|
||||
static PRLogModuleInfo*
|
||||
GetThreadPoolLog()
|
||||
{
|
||||
static PRLogModuleInfo *sLog;
|
||||
if (!sLog)
|
||||
static PRLogModuleInfo* sLog;
|
||||
if (!sLog) {
|
||||
sLog = PR_NewLogModule("nsThreadPool");
|
||||
}
|
||||
return sLog;
|
||||
}
|
||||
#endif
|
||||
@ -66,7 +67,7 @@ nsThreadPool::~nsThreadPool()
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsThreadPool::PutEvent(nsIRunnable *event)
|
||||
nsThreadPool::PutEvent(nsIRunnable* aEvent)
|
||||
{
|
||||
// Avoid spawning a new thread while holding the event queue lock...
|
||||
|
||||
@ -77,31 +78,34 @@ nsThreadPool::PutEvent(nsIRunnable *event)
|
||||
|
||||
LOG(("THRD-P(%p) put [%d %d %d]\n", this, mIdleCount, mThreads.Count(),
|
||||
mThreadLimit));
|
||||
MOZ_ASSERT(mIdleCount <= (uint32_t) mThreads.Count(), "oops");
|
||||
MOZ_ASSERT(mIdleCount <= (uint32_t)mThreads.Count(), "oops");
|
||||
|
||||
// Make sure we have a thread to service this event.
|
||||
if (mIdleCount == 0 && mThreads.Count() < (int32_t) mThreadLimit)
|
||||
if (mIdleCount == 0 && mThreads.Count() < (int32_t)mThreadLimit) {
|
||||
spawnThread = true;
|
||||
}
|
||||
|
||||
mEvents.PutEvent(event);
|
||||
mEvents.PutEvent(aEvent);
|
||||
stackSize = mStackSize;
|
||||
}
|
||||
|
||||
LOG(("THRD-P(%p) put [spawn=%d]\n", this, spawnThread));
|
||||
if (!spawnThread)
|
||||
if (!spawnThread) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsThreadManager::get()->NewThread(0,
|
||||
stackSize,
|
||||
getter_AddRefs(thread));
|
||||
if (NS_WARN_IF(!thread))
|
||||
if (NS_WARN_IF(!thread)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
bool killThread = false;
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
|
||||
if (mThreads.Count() < (int32_t) mThreadLimit) {
|
||||
if (mThreads.Count() < (int32_t)mThreadLimit) {
|
||||
mThreads.AppendObject(thread);
|
||||
} else {
|
||||
killThread = true; // okay, we don't need this thread anymore
|
||||
@ -126,16 +130,16 @@ nsThreadPool::PutEvent(nsIRunnable *event)
|
||||
}
|
||||
|
||||
void
|
||||
nsThreadPool::ShutdownThread(nsIThread *thread)
|
||||
nsThreadPool::ShutdownThread(nsIThread* aThread)
|
||||
{
|
||||
LOG(("THRD-P(%p) shutdown async [%p]\n", this, thread));
|
||||
LOG(("THRD-P(%p) shutdown async [%p]\n", this, aThread));
|
||||
|
||||
// This method is responsible for calling Shutdown on |thread|. This must be
|
||||
// This method is responsible for calling Shutdown on |aThread|. This must be
|
||||
// done from some other thread, so we use the main thread of the application.
|
||||
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "wrong thread");
|
||||
|
||||
nsRefPtr<nsIRunnable> r = NS_NewRunnableMethod(thread, &nsIThread::Shutdown);
|
||||
nsRefPtr<nsIRunnable> r = NS_NewRunnableMethod(aThread, &nsIThread::Shutdown);
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
@ -178,8 +182,9 @@ nsThreadPool::Run()
|
||||
} else {
|
||||
if (wasIdle) {
|
||||
// if too many idle threads or idle for too long, then bail.
|
||||
if (mIdleCount > mIdleThreadLimit || (now - idleSince) >= timeout)
|
||||
if (mIdleCount > mIdleThreadLimit || (now - idleSince) >= timeout) {
|
||||
exitThread = true;
|
||||
}
|
||||
} else {
|
||||
// if would be too many idle threads...
|
||||
if (mIdleCount == mIdleThreadLimit) {
|
||||
@ -193,8 +198,9 @@ nsThreadPool::Run()
|
||||
}
|
||||
|
||||
if (exitThread) {
|
||||
if (wasIdle)
|
||||
if (wasIdle) {
|
||||
--mIdleCount;
|
||||
}
|
||||
shutdownThreadOnExit = mThreads.RemoveObject(current);
|
||||
} else {
|
||||
PRIntervalTime delta = timeout - (now - idleSince);
|
||||
@ -225,44 +231,47 @@ nsThreadPool::Run()
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadPool::Dispatch(nsIRunnable *event, uint32_t flags)
|
||||
nsThreadPool::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
|
||||
{
|
||||
LOG(("THRD-P(%p) dispatch [%p %x]\n", this, event, flags));
|
||||
LOG(("THRD-P(%p) dispatch [%p %x]\n", this, aEvent, aFlags));
|
||||
|
||||
if (NS_WARN_IF(mShutdown))
|
||||
if (NS_WARN_IF(mShutdown)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (flags & DISPATCH_SYNC) {
|
||||
if (aFlags & DISPATCH_SYNC) {
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsThreadManager::get()->GetCurrentThread(getter_AddRefs(thread));
|
||||
if (NS_WARN_IF(!thread))
|
||||
if (NS_WARN_IF(!thread)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsRefPtr<nsThreadSyncDispatch> wrapper =
|
||||
new nsThreadSyncDispatch(thread, event);
|
||||
new nsThreadSyncDispatch(thread, aEvent);
|
||||
PutEvent(wrapper);
|
||||
|
||||
while (wrapper->IsPending())
|
||||
while (wrapper->IsPending()) {
|
||||
NS_ProcessNextEvent(thread);
|
||||
}
|
||||
} else {
|
||||
NS_ASSERTION(flags == NS_DISPATCH_NORMAL, "unexpected dispatch flags");
|
||||
PutEvent(event);
|
||||
NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "unexpected dispatch flags");
|
||||
PutEvent(aEvent);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadPool::IsOnCurrentThread(bool *result)
|
||||
nsThreadPool::IsOnCurrentThread(bool* aResult)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
|
||||
nsIThread* thread = NS_GetCurrentThread();
|
||||
for (uint32_t i = 0; i < static_cast<uint32_t>(mThreads.Count()); ++i) {
|
||||
if (mThreads[i] == thread) {
|
||||
*result = true;
|
||||
*aResult = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
*result = false;
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -288,26 +297,28 @@ nsThreadPool::Shutdown()
|
||||
// It's important that we shutdown the threads while outside the event queue
|
||||
// monitor. Otherwise, we could end up dead-locking.
|
||||
|
||||
for (int32_t i = 0; i < threads.Count(); ++i)
|
||||
for (int32_t i = 0; i < threads.Count(); ++i) {
|
||||
threads[i]->Shutdown();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadPool::GetThreadLimit(uint32_t *value)
|
||||
nsThreadPool::GetThreadLimit(uint32_t* aValue)
|
||||
{
|
||||
*value = mThreadLimit;
|
||||
*aValue = mThreadLimit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadPool::SetThreadLimit(uint32_t value)
|
||||
nsThreadPool::SetThreadLimit(uint32_t aValue)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
|
||||
mThreadLimit = value;
|
||||
if (mIdleThreadLimit > mThreadLimit)
|
||||
mThreadLimit = aValue;
|
||||
if (mIdleThreadLimit > mThreadLimit) {
|
||||
mIdleThreadLimit = mThreadLimit;
|
||||
}
|
||||
|
||||
if (static_cast<uint32_t>(mThreads.Count()) > mThreadLimit) {
|
||||
mon.NotifyAll(); // wake up threads so they observe this change
|
||||
@ -316,19 +327,20 @@ nsThreadPool::SetThreadLimit(uint32_t value)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadPool::GetIdleThreadLimit(uint32_t *value)
|
||||
nsThreadPool::GetIdleThreadLimit(uint32_t* aValue)
|
||||
{
|
||||
*value = mIdleThreadLimit;
|
||||
*aValue = mIdleThreadLimit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadPool::SetIdleThreadLimit(uint32_t value)
|
||||
nsThreadPool::SetIdleThreadLimit(uint32_t aValue)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
|
||||
mIdleThreadLimit = value;
|
||||
if (mIdleThreadLimit > mThreadLimit)
|
||||
mIdleThreadLimit = aValue;
|
||||
if (mIdleThreadLimit > mThreadLimit) {
|
||||
mIdleThreadLimit = mThreadLimit;
|
||||
}
|
||||
|
||||
// Do we need to kill some idle threads?
|
||||
if (mIdleCount > mIdleThreadLimit) {
|
||||
@ -338,18 +350,18 @@ nsThreadPool::SetIdleThreadLimit(uint32_t value)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadPool::GetIdleThreadTimeout(uint32_t *value)
|
||||
nsThreadPool::GetIdleThreadTimeout(uint32_t* aValue)
|
||||
{
|
||||
*value = mIdleThreadTimeout;
|
||||
*aValue = mIdleThreadTimeout;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadPool::SetIdleThreadTimeout(uint32_t value)
|
||||
nsThreadPool::SetIdleThreadTimeout(uint32_t aValue)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
|
||||
uint32_t oldTimeout = mIdleThreadTimeout;
|
||||
mIdleThreadTimeout = value;
|
||||
mIdleThreadTimeout = aValue;
|
||||
|
||||
// Do we need to notify any idle threads that their sleep time has shortened?
|
||||
if (mIdleThreadTimeout < oldTimeout && mIdleCount > 0) {
|
||||
@ -359,18 +371,18 @@ nsThreadPool::SetIdleThreadTimeout(uint32_t value)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadPool::GetThreadStackSize(uint32_t* value)
|
||||
nsThreadPool::GetThreadStackSize(uint32_t* aValue)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
|
||||
*value = mStackSize;
|
||||
*aValue = mStackSize;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadPool::SetThreadStackSize(uint32_t value)
|
||||
nsThreadPool::SetThreadStackSize(uint32_t aValue)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
|
||||
mStackSize = value;
|
||||
mStackSize = aValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -398,8 +410,9 @@ nsThreadPool::SetName(const nsACString& aName)
|
||||
{
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
|
||||
if (mThreads.Count())
|
||||
if (mThreads.Count()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
mName = aName;
|
||||
|
@ -16,8 +16,9 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsThreadPool MOZ_FINAL : public nsIThreadPool,
|
||||
public nsIRunnable
|
||||
class nsThreadPool MOZ_FINAL
|
||||
: public nsIThreadPool
|
||||
, public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
@ -30,8 +31,8 @@ public:
|
||||
private:
|
||||
~nsThreadPool();
|
||||
|
||||
void ShutdownThread(nsIThread *thread);
|
||||
nsresult PutEvent(nsIRunnable *event);
|
||||
void ShutdownThread(nsIThread* aThread);
|
||||
nsresult PutEvent(nsIRunnable* aEvent);
|
||||
|
||||
nsCOMArray<nsIThread> mThreads;
|
||||
nsEventQueue mEvents;
|
||||
|
@ -26,9 +26,10 @@ static TimerThread* gThread = nullptr;
|
||||
PRLogModuleInfo*
|
||||
GetTimerLog()
|
||||
{
|
||||
static PRLogModuleInfo *sLog;
|
||||
if (!sLog)
|
||||
static PRLogModuleInfo* sLog;
|
||||
if (!sLog) {
|
||||
sLog = PR_NewLogModule("nsTimerImpl");
|
||||
}
|
||||
return sLog;
|
||||
}
|
||||
|
||||
@ -40,16 +41,17 @@ double nsTimerImpl::sDeltaNum = 0;
|
||||
|
||||
static void
|
||||
myNS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues,
|
||||
double *meanResult, double *stdDevResult)
|
||||
double* meanResult, double* stdDevResult)
|
||||
{
|
||||
double mean = 0.0, var = 0.0, stdDev = 0.0;
|
||||
if (n > 0.0 && sumOfValues >= 0) {
|
||||
mean = sumOfValues / n;
|
||||
double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues);
|
||||
if (temp < 0.0 || n <= 1)
|
||||
if (temp < 0.0 || n <= 1) {
|
||||
var = 0.0;
|
||||
else
|
||||
} else {
|
||||
var = temp / (n * (n - 1));
|
||||
}
|
||||
// for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this:
|
||||
stdDev = var != 0.0 ? sqrt(var) : 0.0;
|
||||
}
|
||||
@ -77,7 +79,8 @@ namespace {
|
||||
class TimerEventAllocator
|
||||
{
|
||||
private:
|
||||
struct FreeEntry {
|
||||
struct FreeEntry
|
||||
{
|
||||
FreeEntry* mNext;
|
||||
};
|
||||
|
||||
@ -87,8 +90,8 @@ private:
|
||||
|
||||
public:
|
||||
TimerEventAllocator()
|
||||
: mFirstFree(nullptr),
|
||||
mMonitor("TimerEventAllocator")
|
||||
: mFirstFree(nullptr)
|
||||
, mMonitor("TimerEventAllocator")
|
||||
{
|
||||
PL_InitArenaPool(&mPool, "TimerEventPool", 4096, /* align = */ 0);
|
||||
}
|
||||
@ -104,13 +107,16 @@ public:
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class nsTimerEvent : public nsRunnable {
|
||||
class nsTimerEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD Run();
|
||||
|
||||
nsTimerEvent(nsTimerImpl *timer, int32_t generation)
|
||||
: mTimer(dont_AddRef(timer)), mGeneration(generation) {
|
||||
// timer is already addref'd for us
|
||||
nsTimerEvent(nsTimerImpl* aTimer, int32_t aGeneration)
|
||||
: mTimer(dont_AddRef(aTimer))
|
||||
, mGeneration(aGeneration)
|
||||
{
|
||||
// aTimer is already addref'd for us
|
||||
MOZ_COUNT_CTOR(nsTimerEvent);
|
||||
|
||||
MOZ_ASSERT(gThread->IsOnTimerThread(),
|
||||
@ -127,17 +133,20 @@ public:
|
||||
static void Shutdown();
|
||||
static void DeleteAllocatorIfNeeded();
|
||||
|
||||
static void* operator new(size_t size) CPP_THROW_NEW {
|
||||
return sAllocator->Alloc(size);
|
||||
static void* operator new(size_t aSize) CPP_THROW_NEW
|
||||
{
|
||||
return sAllocator->Alloc(aSize);
|
||||
}
|
||||
void operator delete(void* p) {
|
||||
sAllocator->Free(p);
|
||||
void operator delete(void* aPtr)
|
||||
{
|
||||
sAllocator->Free(aPtr);
|
||||
DeleteAllocatorIfNeeded();
|
||||
}
|
||||
|
||||
private:
|
||||
nsTimerEvent(); // Not implemented
|
||||
~nsTimerEvent() {
|
||||
~nsTimerEvent()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsTimerEvent);
|
||||
|
||||
MOZ_ASSERT(!sCanDeleteAllocator || sAllocatorUsers > 0,
|
||||
@ -159,7 +168,8 @@ bool nsTimerEvent::sCanDeleteAllocator = false;
|
||||
|
||||
namespace {
|
||||
|
||||
void* TimerEventAllocator::Alloc(size_t aSize)
|
||||
void*
|
||||
TimerEventAllocator::Alloc(size_t aSize)
|
||||
{
|
||||
MOZ_ASSERT(aSize == sizeof(nsTimerEvent));
|
||||
|
||||
@ -169,17 +179,18 @@ void* TimerEventAllocator::Alloc(size_t aSize)
|
||||
if (mFirstFree) {
|
||||
p = mFirstFree;
|
||||
mFirstFree = mFirstFree->mNext;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
PL_ARENA_ALLOCATE(p, &mPool, aSize);
|
||||
if (!p)
|
||||
if (!p) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void TimerEventAllocator::Free(void* aPtr)
|
||||
void
|
||||
TimerEventAllocator::Free(void* aPtr)
|
||||
{
|
||||
mozilla::MonitorAutoLock lock(mMonitor);
|
||||
|
||||
@ -194,7 +205,8 @@ void TimerEventAllocator::Free(void* aPtr)
|
||||
NS_IMPL_QUERY_INTERFACE(nsTimerImpl, nsITimer)
|
||||
NS_IMPL_ADDREF(nsTimerImpl)
|
||||
|
||||
NS_IMETHODIMP_(MozExternalRefCountType) nsTimerImpl::Release(void)
|
||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||
nsTimerImpl::Release(void)
|
||||
{
|
||||
nsrefcnt count;
|
||||
|
||||
@ -243,8 +255,9 @@ NS_IMETHODIMP_(MozExternalRefCountType) nsTimerImpl::Release(void)
|
||||
mCanceled = true;
|
||||
|
||||
MOZ_ASSERT(gThread, "Armed timer exists after the thread timer stopped.");
|
||||
if (NS_SUCCEEDED(gThread->RemoveTimer(this)))
|
||||
if (NS_SUCCEEDED(gThread->RemoveTimer(this))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
@ -279,7 +292,9 @@ nsTimerImpl::Startup()
|
||||
nsTimerEvent::Init();
|
||||
|
||||
gThread = new TimerThread();
|
||||
if (!gThread) return NS_ERROR_OUT_OF_MEMORY;
|
||||
if (!gThread) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
NS_ADDREF(gThread);
|
||||
rv = gThread->InitLocks();
|
||||
@ -291,20 +306,25 @@ nsTimerImpl::Startup()
|
||||
return rv;
|
||||
}
|
||||
|
||||
void nsTimerImpl::Shutdown()
|
||||
void
|
||||
nsTimerImpl::Shutdown()
|
||||
{
|
||||
#ifdef DEBUG_TIMERS
|
||||
if (PR_LOG_TEST(GetTimerLog(), PR_LOG_DEBUG)) {
|
||||
double mean = 0, stddev = 0;
|
||||
myNS_MeanAndStdDev(sDeltaNum, sDeltaSum, sDeltaSumSquared, &mean, &stddev);
|
||||
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("sDeltaNum = %f, sDeltaSum = %f, sDeltaSumSquared = %f\n", sDeltaNum, sDeltaSum, sDeltaSumSquared));
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("mean: %fms, stddev: %fms\n", mean, stddev));
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG,
|
||||
("sDeltaNum = %f, sDeltaSum = %f, sDeltaSumSquared = %f\n",
|
||||
sDeltaNum, sDeltaSum, sDeltaSumSquared));
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG,
|
||||
("mean: %fms, stddev: %fms\n", mean, stddev));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!gThread)
|
||||
if (!gThread) {
|
||||
return;
|
||||
}
|
||||
|
||||
gThread->Shutdown();
|
||||
NS_RELEASE(gThread);
|
||||
@ -313,20 +333,23 @@ void nsTimerImpl::Shutdown()
|
||||
}
|
||||
|
||||
|
||||
nsresult nsTimerImpl::InitCommon(uint32_t aType, uint32_t aDelay)
|
||||
nsresult
|
||||
nsTimerImpl::InitCommon(uint32_t aType, uint32_t aDelay)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (NS_WARN_IF(!gThread))
|
||||
if (NS_WARN_IF(!gThread)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!mEventTarget) {
|
||||
NS_ERROR("mEventTarget is NULL");
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
rv = gThread->Init();
|
||||
if (NS_WARN_IF(NS_FAILED(rv)))
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* In case of re-Init, both with and without a preceding Cancel, clear the
|
||||
@ -342,8 +365,9 @@ nsresult nsTimerImpl::InitCommon(uint32_t aType, uint32_t aDelay)
|
||||
* be cleared by another CPU whose store hasn't reached our CPU's cache),
|
||||
* because RemoveTimer is idempotent.
|
||||
*/
|
||||
if (mArmed)
|
||||
if (mArmed) {
|
||||
gThread->RemoveTimer(this);
|
||||
}
|
||||
mCanceled = false;
|
||||
mTimeout = TimeStamp();
|
||||
mGeneration = gGenerator++;
|
||||
@ -354,14 +378,16 @@ nsresult nsTimerImpl::InitCommon(uint32_t aType, uint32_t aDelay)
|
||||
return gThread->AddTimer(this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc,
|
||||
void *aClosure,
|
||||
uint32_t aDelay,
|
||||
uint32_t aType)
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc,
|
||||
void* aClosure,
|
||||
uint32_t aDelay,
|
||||
uint32_t aType)
|
||||
{
|
||||
if (NS_WARN_IF(!aFunc))
|
||||
if (NS_WARN_IF(!aFunc)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
}
|
||||
|
||||
ReleaseCallback();
|
||||
mCallbackType = CALLBACK_TYPE_FUNC;
|
||||
mCallback.c = aFunc;
|
||||
@ -370,12 +396,14 @@ NS_IMETHODIMP nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc,
|
||||
return InitCommon(aType, aDelay);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTimerImpl::InitWithCallback(nsITimerCallback *aCallback,
|
||||
uint32_t aDelay,
|
||||
uint32_t aType)
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::InitWithCallback(nsITimerCallback* aCallback,
|
||||
uint32_t aDelay,
|
||||
uint32_t aType)
|
||||
{
|
||||
if (NS_WARN_IF(!aCallback))
|
||||
if (NS_WARN_IF(!aCallback)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ReleaseCallback();
|
||||
mCallbackType = CALLBACK_TYPE_INTERFACE;
|
||||
@ -385,12 +413,12 @@ NS_IMETHODIMP nsTimerImpl::InitWithCallback(nsITimerCallback *aCallback,
|
||||
return InitCommon(aType, aDelay);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTimerImpl::Init(nsIObserver *aObserver,
|
||||
uint32_t aDelay,
|
||||
uint32_t aType)
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::Init(nsIObserver* aObserver, uint32_t aDelay, uint32_t aType)
|
||||
{
|
||||
if (NS_WARN_IF(!aObserver))
|
||||
if (NS_WARN_IF(!aObserver)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ReleaseCallback();
|
||||
mCallbackType = CALLBACK_TYPE_OBSERVER;
|
||||
@ -400,19 +428,22 @@ NS_IMETHODIMP nsTimerImpl::Init(nsIObserver *aObserver,
|
||||
return InitCommon(aType, aDelay);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTimerImpl::Cancel()
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::Cancel()
|
||||
{
|
||||
mCanceled = true;
|
||||
|
||||
if (gThread)
|
||||
if (gThread) {
|
||||
gThread->RemoveTimer(this);
|
||||
}
|
||||
|
||||
ReleaseCallback();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTimerImpl::SetDelay(uint32_t aDelay)
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::SetDelay(uint32_t aDelay)
|
||||
{
|
||||
if (mCallbackType == CALLBACK_TYPE_UNKNOWN && mType == TYPE_ONE_SHOT) {
|
||||
// This may happen if someone tries to re-use a one-shot timer
|
||||
@ -424,24 +455,28 @@ NS_IMETHODIMP nsTimerImpl::SetDelay(uint32_t aDelay)
|
||||
|
||||
// If we're already repeating precisely, update mTimeout now so that the
|
||||
// new delay takes effect in the future.
|
||||
if (!mTimeout.IsNull() && mType == TYPE_REPEATING_PRECISE)
|
||||
if (!mTimeout.IsNull() && mType == TYPE_REPEATING_PRECISE) {
|
||||
mTimeout = TimeStamp::Now();
|
||||
}
|
||||
|
||||
SetDelayInternal(aDelay);
|
||||
|
||||
if (!mFiring && gThread)
|
||||
if (!mFiring && gThread) {
|
||||
gThread->TimerDelayChanged(this);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTimerImpl::GetDelay(uint32_t* aDelay)
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::GetDelay(uint32_t* aDelay)
|
||||
{
|
||||
*aDelay = mDelay;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTimerImpl::SetType(uint32_t aType)
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::SetType(uint32_t aType)
|
||||
{
|
||||
mType = (uint8_t)aType;
|
||||
// XXX if this is called, we should change the actual type.. this could effect
|
||||
@ -450,57 +485,67 @@ NS_IMETHODIMP nsTimerImpl::SetType(uint32_t aType)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTimerImpl::GetType(uint32_t* aType)
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::GetType(uint32_t* aType)
|
||||
{
|
||||
*aType = mType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsTimerImpl::GetClosure(void** aClosure)
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::GetClosure(void** aClosure)
|
||||
{
|
||||
*aClosure = mClosure;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsTimerImpl::GetCallback(nsITimerCallback **aCallback)
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::GetCallback(nsITimerCallback** aCallback)
|
||||
{
|
||||
if (mCallbackType == CALLBACK_TYPE_INTERFACE)
|
||||
if (mCallbackType == CALLBACK_TYPE_INTERFACE) {
|
||||
NS_IF_ADDREF(*aCallback = mCallback.i);
|
||||
else if (mTimerCallbackWhileFiring)
|
||||
} else if (mTimerCallbackWhileFiring) {
|
||||
NS_ADDREF(*aCallback = mTimerCallbackWhileFiring);
|
||||
else
|
||||
} else {
|
||||
*aCallback = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsTimerImpl::GetTarget(nsIEventTarget** aTarget)
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::GetTarget(nsIEventTarget** aTarget)
|
||||
{
|
||||
NS_IF_ADDREF(*aTarget = mEventTarget);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsTimerImpl::SetTarget(nsIEventTarget* aTarget)
|
||||
NS_IMETHODIMP
|
||||
nsTimerImpl::SetTarget(nsIEventTarget* aTarget)
|
||||
{
|
||||
if (NS_WARN_IF(mCallbackType != CALLBACK_TYPE_UNKNOWN))
|
||||
if (NS_WARN_IF(mCallbackType != CALLBACK_TYPE_UNKNOWN)) {
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
}
|
||||
|
||||
if (aTarget)
|
||||
if (aTarget) {
|
||||
mEventTarget = aTarget;
|
||||
else
|
||||
} else {
|
||||
mEventTarget = static_cast<nsIEventTarget*>(NS_GetCurrentThread());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
void nsTimerImpl::Fire()
|
||||
void
|
||||
nsTimerImpl::Fire()
|
||||
{
|
||||
if (mCanceled)
|
||||
if (mCanceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
PROFILER_LABEL("Timer", "Fire");
|
||||
|
||||
@ -519,10 +564,16 @@ void nsTimerImpl::Fire()
|
||||
sDeltaSumSquared += double(d) * double(d);
|
||||
sDeltaNum++;
|
||||
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("[this=%p] expected delay time %4ums\n", this, mDelay));
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("[this=%p] actual delay time %fms\n", this, a.ToMilliseconds()));
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("[this=%p] (mType is %d) -------\n", this, mType));
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("[this=%p] delta %4dms\n", this, (a > b) ? (int32_t)d : -(int32_t)d));
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG,
|
||||
("[this=%p] expected delay time %4ums\n", this, mDelay));
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG,
|
||||
("[this=%p] actual delay time %fms\n", this,
|
||||
a.ToMilliseconds()));
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG,
|
||||
("[this=%p] (mType is %d) -------\n", this, mType));
|
||||
PR_LOG(GetTimerLog(), PR_LOG_DEBUG,
|
||||
("[this=%p] delta %4dms\n",
|
||||
this, (a > b) ? (int32_t)d : -(int32_t)d));
|
||||
|
||||
mStart = mStart2;
|
||||
mStart2 = TimeStamp();
|
||||
@ -536,18 +587,20 @@ void nsTimerImpl::Fire()
|
||||
timeout -= TimeDuration::FromMilliseconds(mDelay);
|
||||
}
|
||||
|
||||
if (mCallbackType == CALLBACK_TYPE_INTERFACE)
|
||||
if (mCallbackType == CALLBACK_TYPE_INTERFACE) {
|
||||
mTimerCallbackWhileFiring = mCallback.i;
|
||||
}
|
||||
mFiring = true;
|
||||
|
||||
// Handle callbacks that re-init the timer, but avoid leaking.
|
||||
// See bug 330128.
|
||||
CallbackUnion callback = mCallback;
|
||||
unsigned callbackType = mCallbackType;
|
||||
if (callbackType == CALLBACK_TYPE_INTERFACE)
|
||||
if (callbackType == CALLBACK_TYPE_INTERFACE) {
|
||||
NS_ADDREF(callback.i);
|
||||
else if (callbackType == CALLBACK_TYPE_OBSERVER)
|
||||
} else if (callbackType == CALLBACK_TYPE_OBSERVER) {
|
||||
NS_ADDREF(callback.o);
|
||||
}
|
||||
ReleaseCallback();
|
||||
|
||||
switch (callbackType) {
|
||||
@ -562,7 +615,8 @@ void nsTimerImpl::Fire()
|
||||
NS_TIMER_CALLBACK_TOPIC,
|
||||
nullptr);
|
||||
break;
|
||||
default:;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
// If the callback didn't re-init the timer, and it's not a one-shot timer,
|
||||
@ -573,10 +627,11 @@ void nsTimerImpl::Fire()
|
||||
mCallbackType = callbackType;
|
||||
} else {
|
||||
// The timer was a one-shot, or the callback was reinitialized.
|
||||
if (callbackType == CALLBACK_TYPE_INTERFACE)
|
||||
if (callbackType == CALLBACK_TYPE_INTERFACE) {
|
||||
NS_RELEASE(callback.i);
|
||||
else if (callbackType == CALLBACK_TYPE_OBSERVER)
|
||||
} else if (callbackType == CALLBACK_TYPE_OBSERVER) {
|
||||
NS_RELEASE(callback.o);
|
||||
}
|
||||
}
|
||||
|
||||
mFiring = false;
|
||||
@ -594,27 +649,32 @@ void nsTimerImpl::Fire()
|
||||
// that in PostTimerEvent, but make sure that we aren't armed already (which
|
||||
// can happen if the callback reinitialized the timer).
|
||||
if (IsRepeating() && mType != TYPE_REPEATING_PRECISE && !mArmed) {
|
||||
if (mType == TYPE_REPEATING_SLACK)
|
||||
SetDelayInternal(mDelay); // force mTimeout to be recomputed. For
|
||||
// REPEATING_PRECISE_CAN_SKIP timers this has
|
||||
// already happened.
|
||||
if (gThread)
|
||||
if (mType == TYPE_REPEATING_SLACK) {
|
||||
SetDelayInternal(mDelay); // force mTimeout to be recomputed. For
|
||||
}
|
||||
// REPEATING_PRECISE_CAN_SKIP timers this has
|
||||
// already happened.
|
||||
if (gThread) {
|
||||
gThread->AddTimer(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsTimerEvent::Init()
|
||||
void
|
||||
nsTimerEvent::Init()
|
||||
{
|
||||
sAllocator = new TimerEventAllocator();
|
||||
}
|
||||
|
||||
void nsTimerEvent::Shutdown()
|
||||
void
|
||||
nsTimerEvent::Shutdown()
|
||||
{
|
||||
sCanDeleteAllocator = true;
|
||||
DeleteAllocatorIfNeeded();
|
||||
}
|
||||
|
||||
void nsTimerEvent::DeleteAllocatorIfNeeded()
|
||||
void
|
||||
nsTimerEvent::DeleteAllocatorIfNeeded()
|
||||
{
|
||||
if (sCanDeleteAllocator && sAllocatorUsers == 0) {
|
||||
delete sAllocator;
|
||||
@ -622,10 +682,12 @@ void nsTimerEvent::DeleteAllocatorIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTimerEvent::Run()
|
||||
NS_IMETHODIMP
|
||||
nsTimerEvent::Run()
|
||||
{
|
||||
if (mGeneration != mTimer->GetGeneration())
|
||||
if (mGeneration != mTimer->GetGeneration()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TIMERS
|
||||
if (PR_LOG_TEST(GetTimerLog(), PR_LOG_DEBUG)) {
|
||||
@ -641,7 +703,8 @@ NS_IMETHODIMP nsTimerEvent::Run()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsTimerImpl::PostTimerEvent()
|
||||
nsresult
|
||||
nsTimerImpl::PostTimerEvent()
|
||||
{
|
||||
if (!mEventTarget) {
|
||||
NS_ERROR("Attempt to post timer event to NULL event target");
|
||||
@ -656,8 +719,9 @@ nsresult nsTimerImpl::PostTimerEvent()
|
||||
// re-initialized after being canceled.
|
||||
|
||||
nsRefPtr<nsTimerEvent> event = new nsTimerEvent(this, mGeneration);
|
||||
if (!event)
|
||||
if (!event) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TIMERS
|
||||
if (PR_LOG_TEST(GetTimerLog(), PR_LOG_DEBUG)) {
|
||||
@ -673,56 +737,62 @@ nsresult nsTimerImpl::PostTimerEvent()
|
||||
// But only re-arm REPEATING_PRECISE timers.
|
||||
if (gThread && mType == TYPE_REPEATING_PRECISE) {
|
||||
nsresult rv = gThread->AddTimer(this);
|
||||
if (NS_FAILED(rv))
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = mEventTarget->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv) && gThread)
|
||||
if (NS_FAILED(rv) && gThread) {
|
||||
gThread->RemoveTimer(this);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void nsTimerImpl::SetDelayInternal(uint32_t aDelay)
|
||||
void
|
||||
nsTimerImpl::SetDelayInternal(uint32_t aDelay)
|
||||
{
|
||||
TimeDuration delayInterval = TimeDuration::FromMilliseconds(aDelay);
|
||||
|
||||
mDelay = aDelay;
|
||||
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
if (mTimeout.IsNull() || mType != TYPE_REPEATING_PRECISE)
|
||||
if (mTimeout.IsNull() || mType != TYPE_REPEATING_PRECISE) {
|
||||
mTimeout = now;
|
||||
}
|
||||
|
||||
mTimeout += delayInterval;
|
||||
|
||||
#ifdef DEBUG_TIMERS
|
||||
if (PR_LOG_TEST(GetTimerLog(), PR_LOG_DEBUG)) {
|
||||
if (mStart.IsNull())
|
||||
if (mStart.IsNull()) {
|
||||
mStart = now;
|
||||
else
|
||||
} else {
|
||||
mStart2 = now;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// NOT FOR PUBLIC CONSUMPTION!
|
||||
nsresult
|
||||
NS_NewTimer(nsITimer* *aResult, nsTimerCallbackFunc aCallback, void *aClosure,
|
||||
NS_NewTimer(nsITimer** aResult, nsTimerCallbackFunc aCallback, void* aClosure,
|
||||
uint32_t aDelay, uint32_t aType)
|
||||
{
|
||||
nsTimerImpl* timer = new nsTimerImpl();
|
||||
if (timer == nullptr)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(timer);
|
||||
nsTimerImpl* timer = new nsTimerImpl();
|
||||
if (!timer) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
NS_ADDREF(timer);
|
||||
|
||||
nsresult rv = timer->InitWithFuncCallback(aCallback, aClosure,
|
||||
aDelay, aType);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(timer);
|
||||
return rv;
|
||||
}
|
||||
nsresult rv = timer->InitWithFuncCallback(aCallback, aClosure,
|
||||
aDelay, aType);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(timer);
|
||||
return rv;
|
||||
}
|
||||
|
||||
*aResult = timer;
|
||||
return NS_OK;
|
||||
*aResult = timer;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
#endif
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
extern PRLogModuleInfo *GetTimerLog();
|
||||
extern PRLogModuleInfo* GetTimerLog();
|
||||
#define DEBUG_TIMERS 1
|
||||
#else
|
||||
#undef DEBUG_TIMERS
|
||||
@ -37,7 +37,8 @@ extern PRLogModuleInfo *GetTimerLog();
|
||||
{0x84, 0x27, 0xfb, 0xab, 0x44, 0xf2, 0x9b, 0xc8} \
|
||||
}
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
CALLBACK_TYPE_UNKNOWN = 0,
|
||||
CALLBACK_TYPE_INTERFACE = 1,
|
||||
CALLBACK_TYPE_FUNC = 2,
|
||||
@ -64,7 +65,10 @@ public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSITIMER
|
||||
|
||||
int32_t GetGeneration() { return mGeneration; }
|
||||
int32_t GetGeneration()
|
||||
{
|
||||
return mGeneration;
|
||||
}
|
||||
|
||||
#ifdef MOZ_TASK_TRACER
|
||||
void DispatchTracedTask()
|
||||
@ -83,33 +87,37 @@ private:
|
||||
// sure that we don't recurse into ReleaseCallback in case
|
||||
// the callback's destructor calls Cancel() or similar.
|
||||
uint8_t cbType = mCallbackType;
|
||||
mCallbackType = CALLBACK_TYPE_UNKNOWN;
|
||||
mCallbackType = CALLBACK_TYPE_UNKNOWN;
|
||||
|
||||
if (cbType == CALLBACK_TYPE_INTERFACE)
|
||||
if (cbType == CALLBACK_TYPE_INTERFACE) {
|
||||
NS_RELEASE(mCallback.i);
|
||||
else if (cbType == CALLBACK_TYPE_OBSERVER)
|
||||
} else if (cbType == CALLBACK_TYPE_OBSERVER) {
|
||||
NS_RELEASE(mCallback.o);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsRepeating() const {
|
||||
bool IsRepeating() const
|
||||
{
|
||||
PR_STATIC_ASSERT(TYPE_ONE_SHOT < TYPE_REPEATING_SLACK);
|
||||
PR_STATIC_ASSERT(TYPE_REPEATING_SLACK < TYPE_REPEATING_PRECISE);
|
||||
PR_STATIC_ASSERT(TYPE_REPEATING_PRECISE < TYPE_REPEATING_PRECISE_CAN_SKIP);
|
||||
return mType >= TYPE_REPEATING_SLACK;
|
||||
}
|
||||
|
||||
bool IsRepeatingPrecisely() const {
|
||||
bool IsRepeatingPrecisely() const
|
||||
{
|
||||
return mType >= TYPE_REPEATING_PRECISE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEventTarget> mEventTarget;
|
||||
|
||||
void * mClosure;
|
||||
void* mClosure;
|
||||
|
||||
union CallbackUnion {
|
||||
union CallbackUnion
|
||||
{
|
||||
nsTimerCallbackFunc c;
|
||||
nsITimerCallback * i;
|
||||
nsIObserver * o;
|
||||
nsITimerCallback* i;
|
||||
nsIObserver* o;
|
||||
} mCallback;
|
||||
|
||||
// Some callers expect to be able to access the callback while the
|
||||
|
Loading…
x
Reference in New Issue
Block a user