Bug 1437167 - Part 1: Stop using PRIntervalTime as the argument to CondVar::Wait and Monitor::Wait, r=mstange, r=froydnj

This commit is contained in:
Nika Layzell 2018-02-09 15:17:26 -05:00
Родитель b286bc10d9
Коммит 0c3ba13e4c
38 изменённых файлов: 206 добавлений и 251 удалений

Просмотреть файл

@ -365,7 +365,7 @@ SystemClockDriver::WaitForNextIteration()
{
mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
TimeDuration timeout = TimeDuration::Forever();
TimeStamp now = TimeStamp::Now();
// This lets us avoid hitting the Atomic twice when we know we won't sleep
@ -384,7 +384,7 @@ SystemClockDriver::WaitForNextIteration()
// Make sure timeoutMS doesn't overflow 32 bits by waking up at
// least once a minute, if we need to wake up at all
timeoutMS = std::max<int64_t>(0, std::min<int64_t>(timeoutMS, 60*1000));
timeout = PR_MillisecondsToInterval(uint32_t(timeoutMS));
timeout = TimeDuration::FromMilliseconds(timeoutMS);
LOG(LogLevel::Verbose,
("Waiting for next iteration; at %f, timeout=%f",
(now - mInitialTimeStamp).ToSeconds(),
@ -394,7 +394,7 @@ SystemClockDriver::WaitForNextIteration()
}
mWaitState = WAITSTATE_WAITING_FOR_NEXT_ITERATION;
}
if (timeout > 0) {
if (!timeout.IsZero()) {
mGraphImpl->GetMonitor().Wait(timeout);
LOG(LogLevel::Verbose,
("Resuming after timeout; at %f, elapsed=%f",

Просмотреть файл

@ -181,7 +181,6 @@ StorageDBThread::StorageDBThread()
, mStatus(NS_OK)
, mWorkerStatements(mWorkerConnection)
, mReaderStatements(mReaderConnection)
, mDirtyEpoch(0)
, mFlushImmediately(false)
, mPriorityCounter(0)
{
@ -531,7 +530,8 @@ StorageDBThread::ThreadFunc()
} while (NS_SUCCEEDED(rv) && processedEvent);
}
if (MOZ_UNLIKELY(TimeUntilFlush() == 0)) {
TimeDuration timeUntilFlush = TimeUntilFlush();
if (MOZ_UNLIKELY(timeUntilFlush.IsZero())) {
// Flush time is up or flush has been forced, do it now.
UnscheduleFlush();
if (mPendingTasks.Prepare()) {
@ -558,7 +558,7 @@ StorageDBThread::ThreadFunc()
SetDefaultPriority(); // urgent preload unscheduled
}
} else if (MOZ_UNLIKELY(!mStopIOThread)) {
lockMonitor.Wait(TimeUntilFlush());
lockMonitor.Wait(timeUntilFlush);
}
} // thread loop
@ -825,7 +825,7 @@ StorageDBThread::ScheduleFlush()
}
// Must be non-zero to indicate we are scheduled
mDirtyEpoch = PR_IntervalNow() | 1;
mDirtyEpoch = TimeStamp::Now();
// Wake the monitor from indefinite sleep...
(mThreadObserver->GetMonitor()).Notify();
@ -836,32 +836,28 @@ StorageDBThread::UnscheduleFlush()
{
// We are just about to do the flush, drop flags
mFlushImmediately = false;
mDirtyEpoch = 0;
mDirtyEpoch = TimeStamp();
}
PRIntervalTime
TimeDuration
StorageDBThread::TimeUntilFlush()
{
if (mFlushImmediately) {
return 0; // Do it now regardless the timeout.
}
static_assert(PR_INTERVAL_NO_TIMEOUT != 0,
"PR_INTERVAL_NO_TIMEOUT must be non-zero");
if (!mDirtyEpoch) {
return PR_INTERVAL_NO_TIMEOUT; // No pending task...
return TimeDuration::Forever(); // No pending task...
}
static const PRIntervalTime kMaxAge = PR_MillisecondsToInterval(FLUSHING_INTERVAL_MS);
PRIntervalTime now = PR_IntervalNow() | 1;
PRIntervalTime age = now - mDirtyEpoch;
TimeStamp now = TimeStamp::Now();
TimeDuration age = now - mDirtyEpoch;
static const TimeDuration kMaxAge = TimeDuration::FromMilliseconds(FLUSHING_INTERVAL_MS);
if (age > kMaxAge) {
return 0; // It is time.
}
return kMaxAge - age; // Time left, this is used to sleep the monitor
return kMaxAge - age; // Time left. This is used to sleep the monitor.
}
void

Просмотреть файл

@ -14,6 +14,7 @@
#include "mozilla/Monitor.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/storage/StatementCache.h"
#include "mozilla/TimeStamp.h"
#include "nsAutoPtr.h"
#include "nsString.h"
#include "nsCOMPtr.h"
@ -440,7 +441,7 @@ private:
// Time the first pending operation has been added to the pending operations
// list
PRIntervalTime mDirtyEpoch;
TimeStamp mDirtyEpoch;
// Flag to force immediate flush of all pending operations
bool mFlushImmediately;
@ -486,12 +487,12 @@ private:
// 2. as in indicator that flush has to be performed
//
// Return:
// - PR_INTERVAL_NO_TIMEOUT when no pending tasks are scheduled
// - larger then zero when tasks have been scheduled, but it is
// still not time to perform the flush ; it is actual interval
// time to wait until the flush has to happen
// - 0 when it is time to do the flush
PRIntervalTime TimeUntilFlush();
// - TimeDuration::Forever() when no pending tasks are scheduled
// - Non-zero TimeDuration when tasks have been scheduled, but it
// is still not time to perform the flush ; it is actual time to
// wait until the flush has to happen.
// - 0 TimeDuration when it is time to do the flush
TimeDuration TimeUntilFlush();
// Notifies to the main thread that flush has completed
void NotifyFlushCompletion();

Просмотреть файл

@ -3592,7 +3592,7 @@ WorkerPrivate::InterruptCallback(JSContext* aCx)
break;
}
WaitForWorkerEvents(PR_MillisecondsToInterval(UINT32_MAX));
WaitForWorkerEvents();
}
}
@ -3713,13 +3713,13 @@ WorkerPrivate::DisableMemoryReporter()
}
void
WorkerPrivate::WaitForWorkerEvents(PRIntervalTime aInterval)
WorkerPrivate::WaitForWorkerEvents()
{
AssertIsOnWorkerThread();
mMutex.AssertCurrentThreadOwns();
// Wait for a worker event.
mCondVar.Wait(aInterval);
mCondVar.Wait();
}
WorkerPrivate::ProcessAllControlRunnablesResult

Просмотреть файл

@ -1284,7 +1284,7 @@ private:
DisableMemoryReporter();
void
WaitForWorkerEvents(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT);
WaitForWorkerEvents();
void
PostMessageToParentInternal(JSContext* aCx,

Просмотреть файл

@ -49,8 +49,7 @@ public:
{ // scope lock
MonitorAutoLock lock(mVsyncMonitor);
PRIntervalTime timeout = PR_MillisecondsToInterval(kVsyncTimeoutMS);
lock.Wait(timeout);
lock.Wait(TimeDuration::FromMilliseconds(kVsyncTimeoutMS));
}
}

Просмотреть файл

@ -10,6 +10,7 @@
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Monitor.h"
#include "mozilla/TimeStamp.h"
#include "nsCOMPtr.h"
#include "nsIObserverService.h"
#include "nsIThreadPool.h"
@ -58,7 +59,7 @@ public:
DecodePoolImpl(uint8_t aMaxThreads,
uint8_t aMaxIdleThreads,
PRIntervalTime aIdleTimeout)
TimeDuration aIdleTimeout)
: mMonitor("DecodePoolImpl")
, mThreads(aMaxThreads)
, mIdleTimeout(aIdleTimeout)
@ -178,7 +179,7 @@ private:
{
mMonitor.AssertCurrentThreadOwns();
PRIntervalTime timeout = mIdleTimeout;
TimeDuration timeout = mIdleTimeout;
do {
if (!mHighPriorityQueue.IsEmpty()) {
return PopWorkFromQueue(mHighPriorityQueue);
@ -203,19 +204,19 @@ private:
// This thread should shutdown if it is idle. If we have waited longer
// than the timeout period without having done any work, then we should
// shutdown the thread.
if (timeout == 0) {
if (timeout.IsZero()) {
return CreateShutdownWork();
}
++mIdleThreads;
MOZ_ASSERT(mIdleThreads <= mThreads.Capacity());
PRIntervalTime now = PR_IntervalNow();
TimeStamp now = TimeStamp::Now();
mMonitor.Wait(timeout);
PRIntervalTime delta = PR_IntervalNow() - now;
TimeDuration delta = TimeStamp::Now() - now;
if (delta > timeout) {
timeout = 0;
} else {
} else if (timeout != TimeDuration::Forever()) {
timeout -= delta;
}
}
@ -252,7 +253,7 @@ private:
nsTArray<RefPtr<IDecodingTask>> mHighPriorityQueue;
nsTArray<RefPtr<IDecodingTask>> mLowPriorityQueue;
nsTArray<nsCOMPtr<nsIThread>> mThreads;
PRIntervalTime mIdleTimeout;
TimeDuration mIdleTimeout;
uint8_t mMaxIdleThreads; // Maximum number of workers when idle.
uint8_t mAvailableThreads; // How many new threads can be created.
uint8_t mIdleThreads; // How many created threads are waiting.
@ -389,12 +390,12 @@ DecodePool::DecodePool()
// The timeout period before shutting down idle threads.
int32_t prefIdleTimeout = gfxPrefs::ImageMTDecodingIdleTimeout();
PRIntervalTime idleTimeout;
TimeDuration idleTimeout;
if (prefIdleTimeout <= 0) {
idleTimeout = PR_INTERVAL_NO_TIMEOUT;
idleTimeout = TimeDuration::Forever();
idleLimit = limit;
} else {
idleTimeout = PR_MillisecondsToInterval(static_cast<uint32_t>(prefIdleTimeout));
idleTimeout = TimeDuration::FromMilliseconds(prefIdleTimeout);
idleLimit = (limit + 1) / 2;
}

Просмотреть файл

@ -374,12 +374,12 @@ GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs)
// NB: this uses a different mechanism than the chromium parent
// class.
PRIntervalTime timeoutTicks = (aTimeoutMs > 0) ?
PR_MillisecondsToInterval(aTimeoutMs) : PR_INTERVAL_NO_TIMEOUT;
TimeDuration timeout = (aTimeoutMs > 0) ?
TimeDuration::FromMilliseconds(aTimeoutMs) : TimeDuration::Forever();
MonitorAutoLock lock(mMonitor);
PRIntervalTime waitStart = PR_IntervalNow();
PRIntervalTime current;
TimeStamp waitStart = TimeStamp::Now();
TimeStamp current;
// We'll receive several notifications, we need to exit when we
// have either successfully launched or have timed out.
@ -389,15 +389,14 @@ GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs)
break;
}
lock.Wait(timeoutTicks);
CVStatus status = lock.Wait(timeout);
if (status == CVStatus::Timeout) {
break;
}
if (timeoutTicks != PR_INTERVAL_NO_TIMEOUT) {
current = PR_IntervalNow();
PRIntervalTime elapsed = current - waitStart;
if (elapsed > timeoutTicks) {
break;
}
timeoutTicks = timeoutTicks - elapsed;
if (timeout != TimeDuration::Forever()) {
current = TimeStamp::Now();
timeout -= current - waitStart;
waitStart = current;
}
}

Просмотреть файл

@ -2318,13 +2318,6 @@ MessageChannel::EnqueuePendingMessages()
RepostAllMessages();
}
static inline bool
IsTimeoutExpired(PRIntervalTime aStart, PRIntervalTime aTimeout)
{
return (aTimeout != PR_INTERVAL_NO_TIMEOUT) &&
(aTimeout <= (PR_IntervalNow() - aStart));
}
bool
MessageChannel::WaitResponse(bool aWaitTimedOut)
{
@ -2354,17 +2347,14 @@ MessageChannel::WaitForSyncNotify(bool /* aHandleWindowsMessages */)
}
#endif
PRIntervalTime timeout = (kNoTimeout == mTimeoutMs) ?
PR_INTERVAL_NO_TIMEOUT :
PR_MillisecondsToInterval(mTimeoutMs);
// XXX could optimize away this syscall for "no timeout" case if desired
PRIntervalTime waitStart = PR_IntervalNow();
mMonitor->Wait(timeout);
TimeDuration timeout = (kNoTimeout == mTimeoutMs) ?
TimeDuration::Forever() :
TimeDuration::FromMilliseconds(mTimeoutMs);
CVStatus status = mMonitor->Wait(timeout);
// If the timeout didn't expire, we know we received an event. The
// converse is not true.
return WaitResponse(IsTimeoutExpired(waitStart, timeout));
return WaitResponse(status == CVStatus::Timeout);
}
bool

Просмотреть файл

@ -857,13 +857,6 @@ MessageChannel::SpinInternalEventLoop()
} while (true);
}
static inline bool
IsTimeoutExpired(PRIntervalTime aStart, PRIntervalTime aTimeout)
{
return (aTimeout != PR_INTERVAL_NO_TIMEOUT) &&
(aTimeout <= (PR_IntervalNow() - aStart));
}
static HHOOK gWindowHook;
static inline void
@ -1041,27 +1034,21 @@ MessageChannel::WaitForSyncNotify(bool aHandleWindowsMessages)
// Use a blocking wait if this channel does not require
// Windows message deferral behavior.
if (!(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION) || !aHandleWindowsMessages) {
PRIntervalTime timeout = (kNoTimeout == mTimeoutMs) ?
PR_INTERVAL_NO_TIMEOUT :
PR_MillisecondsToInterval(mTimeoutMs);
PRIntervalTime waitStart = 0;
if (timeout != PR_INTERVAL_NO_TIMEOUT) {
waitStart = PR_IntervalNow();
}
TimeDuration timeout = (kNoTimeout == mTimeoutMs) ?
TimeDuration::Forever() :
TimeDuration::FromMilliseconds(mTimeoutMs);
MOZ_ASSERT(!mIsSyncWaitingOnNonMainThread);
mIsSyncWaitingOnNonMainThread = true;
mMonitor->Wait(timeout);
CVStatus status = mMonitor->Wait(timeout);
MOZ_ASSERT(mIsSyncWaitingOnNonMainThread);
mIsSyncWaitingOnNonMainThread = false;
// If the timeout didn't expire, we know we received an event. The
// converse is not true.
return WaitResponse(timeout == PR_INTERVAL_NO_TIMEOUT ?
false : IsTimeoutExpired(waitStart, timeout));
return WaitResponse(status == CVStatus::Timeout);
}
NS_ASSERTION(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION,

Просмотреть файл

@ -98,7 +98,7 @@ public:
// encounter substantially longer delays, depending on system load.
CVStatus wait_for(UniqueLock<Mutex>& lock,
const mozilla::TimeDuration& rel_time) {
return impl_.wait_for(lock.lock, rel_time) == mozilla::detail::CVStatus::Timeout
return impl_.wait_for(lock.lock, rel_time) == mozilla::CVStatus::Timeout
? CVStatus::Timeout : CVStatus::NoTimeout;
}

Просмотреть файл

@ -724,7 +724,7 @@ ScriptPreloader::Run()
// since that can trigger a new write during shutdown, and we don't want to
// cause shutdown hangs.
if (!mCacheInvalidated) {
mal.Wait(10000);
mal.Wait(TimeDuration::FromSeconds(10));
}
auto result = URLPreloader::GetSingleton().WriteCache();

Просмотреть файл

@ -119,7 +119,7 @@ mozilla::detail::ConditionVariableImpl::wait(MutexImpl& lock)
MOZ_RELEASE_ASSERT(r == 0);
}
mozilla::detail::CVStatus
mozilla::CVStatus
mozilla::detail::ConditionVariableImpl::wait_for(MutexImpl& lock,
const TimeDuration& a_rel_time)
{

Просмотреть файл

@ -59,7 +59,7 @@ mozilla::detail::ConditionVariableImpl::wait(MutexImpl& lock)
MOZ_RELEASE_ASSERT(r);
}
mozilla::detail::CVStatus
mozilla::CVStatus
mozilla::detail::ConditionVariableImpl::wait_for(MutexImpl& lock,
const mozilla::TimeDuration& rel_time)
{

Просмотреть файл

@ -19,13 +19,13 @@
namespace mozilla {
namespace detail {
enum class CVStatus {
NoTimeout,
Timeout
};
namespace detail {
class ConditionVariableImpl {
public:
struct PlatformData;

Просмотреть файл

@ -77,6 +77,8 @@
#include "nsIRedirectHistoryEntry.h"
#include "nsICertBlocklist.h"
#include "nsICertOverrideService.h"
#include "nsQueryObject.h"
#include "mozIThirdPartyUtil.h"
#include <limits>
@ -1659,8 +1661,7 @@ private:
nsresult rv = mTaskQueue->Dispatch(runnable.forget());
NS_ENSURE_SUCCESS(rv, rv);
rv = lock.Wait();
NS_ENSURE_SUCCESS(rv, rv);
lock.Wait();
mCompleted = true;
return mAsyncResult;

Просмотреть файл

@ -1612,7 +1612,7 @@ class nsAsyncBridgeRequest final : public nsPACManCallback
void Lock() { mMutex.Lock(); }
void Unlock() { mMutex.Unlock(); }
void Wait() { mCondVar.Wait(PR_SecondsToInterval(3)); }
void Wait() { mCondVar.Wait(TimeDuration::FromSeconds(3)); }
private:
~nsAsyncBridgeRequest()

Просмотреть файл

@ -578,7 +578,7 @@ public:
this, CacheIOThread::WRITE); // When writes and closing of handles is done
MOZ_ASSERT(NS_SUCCEEDED(rv));
PRIntervalTime const waitTime = PR_MillisecondsToInterval(1000);
TimeDuration waitTime = TimeDuration::FromSeconds(1);
while (!mNotified) {
mon.Wait(waitTime);
if (!mNotified) {

Просмотреть файл

@ -519,7 +519,7 @@ loopStart:
break;
}
lock.Wait(PR_INTERVAL_NO_TIMEOUT);
lock.Wait();
} while (true);

Просмотреть файл

@ -530,8 +530,8 @@ nsHostResolver::nsHostResolver(uint32_t maxCacheEntries,
{
mCreationTime = PR_Now();
mLongIdleTimeout = PR_SecondsToInterval(LongIdleTimeoutSeconds);
mShortIdleTimeout = PR_SecondsToInterval(ShortIdleTimeoutSeconds);
mLongIdleTimeout = TimeDuration::FromSeconds(LongIdleTimeoutSeconds);
mShortIdleTimeout = TimeDuration::FromSeconds(ShortIdleTimeoutSeconds);
}
nsHostResolver::~nsHostResolver() = default;
@ -1313,12 +1313,13 @@ bool
nsHostResolver::GetHostToLookup(nsHostRecord **result)
{
bool timedOut = false;
PRIntervalTime epoch, now, timeout;
TimeDuration timeout;
TimeStamp epoch, now;
MutexAutoLock lock(mLock);
timeout = (mNumIdleThreads >= HighThreadThreshold) ? mShortIdleTimeout : mLongIdleTimeout;
epoch = PR_IntervalNow();
epoch = TimeStamp::Now();
while (!mShutdown) {
// remove next record from Q; hand over owning reference. Check high, then med, then low
@ -1363,15 +1364,16 @@ nsHostResolver::GetHostToLookup(nsHostRecord **result)
mIdleThreadCV.Wait(timeout);
mNumIdleThreads--;
now = PR_IntervalNow();
now = TimeStamp::Now();
if ((PRIntervalTime)(now - epoch) >= timeout)
if (now - epoch >= timeout) {
timedOut = true;
else {
// It is possible that PR_WaitCondVar() was interrupted and returned early,
// in which case we will loop back and re-enter it. In that case we want to
// do so with the new timeout reduced to reflect time already spent waiting.
timeout -= (PRIntervalTime)(now - epoch);
} else {
// It is possible that CondVar::Wait() was interrupted and returned
// early, in which case we will loop back and re-enter it. In that
// case we want to do so with the new timeout reduced to reflect
// time already spent waiting.
timeout -= now - epoch;
epoch = now;
}
}

Просмотреть файл

@ -455,8 +455,8 @@ private:
mozilla::LinkedList<RefPtr<nsHostRecord>> mEvictionQ;
uint32_t mEvictionQSize;
PRTime mCreationTime;
PRIntervalTime mLongIdleTimeout;
PRIntervalTime mShortIdleTimeout;
mozilla::TimeDuration mLongIdleTimeout;
mozilla::TimeDuration mShortIdleTimeout;
mozilla::Atomic<bool> mShutdown;
mozilla::Atomic<uint32_t> mNumIdleThreads;

Просмотреть файл

@ -591,10 +591,7 @@ DataStorage::WaitForReady()
MonitorAutoLock readyLock(mReadyMonitor);
while (!mReady) {
nsresult rv = readyLock.Wait();
if (NS_WARN_IF(NS_FAILED(rv))) {
break;
}
readyLock.Wait();
}
MOZ_ASSERT(mReady);
}

Просмотреть файл

@ -427,7 +427,7 @@ nsNSSHttpRequestSession::internal_send_receive_attempt(bool &retryable_error,
MutexAutoLock locker(waitLock);
const TimeStamp startTime = TimeStamp::NowLoRes();
PRIntervalTime wait_interval;
TimeDuration wait_interval;
bool running_on_main_thread = NS_IsMainThread();
if (running_on_main_thread)
@ -440,13 +440,13 @@ nsNSSHttpRequestSession::internal_send_receive_attempt(bool &retryable_error,
NS_WARNING("Security network blocking I/O on Main Thread");
// let's process events quickly
wait_interval = PR_MicrosecondsToInterval(50);
wait_interval = TimeDuration::FromMicroseconds(50);
}
else
{
// On a secondary thread, it's fine to wait some more for
// for the condition variable.
wait_interval = PR_MillisecondsToInterval(250);
wait_interval = TimeDuration::FromMilliseconds(250);
}
while (waitFlag)

Просмотреть файл

@ -1108,10 +1108,7 @@ nsNSSComponent::BlockUntilLoadableRootsLoaded()
{
MonitorAutoLock rootsLoadedLock(mLoadableRootsLoadedMonitor);
while (!mLoadableRootsLoaded) {
nsresult rv = rootsLoadedLock.Wait();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rootsLoadedLock.Wait();
}
MOZ_ASSERT(mLoadableRootsLoaded);

Просмотреть файл

@ -97,7 +97,7 @@ public:
// Lock for access to members of this class
Monitor mLock;
// Current time as seen by hang monitors
PRIntervalTime mIntervalNow;
TimeStamp mNow;
// List of BackgroundHangThread instances associated with each thread
LinkedList<BackgroundHangThread> mHangThreads;
@ -181,14 +181,14 @@ public:
sTlsKeyInitialized = sTlsKey.init();
}
// Hang timeout in ticks
const PRIntervalTime mTimeout;
// PermaHang timeout in ticks
const PRIntervalTime mMaxTimeout;
// Hang timeout
const TimeDuration mTimeout;
// PermaHang timeout
const TimeDuration mMaxTimeout;
// Time at last activity
PRIntervalTime mInterval;
TimeStamp mLastActivity;
// Time when a hang started
PRIntervalTime mHangStart;
TimeStamp mHangStart;
// Is the thread in a hang
bool mHanging;
// Is the thread in a waiting state
@ -217,7 +217,7 @@ public:
// Report a hang; aManager->mLock IS locked. The hang will be processed
// off-main-thread, and will then be submitted back.
void ReportHang(PRIntervalTime aHangTime);
void ReportHang(TimeDuration aHangTime);
// Report a permanent hang; aManager->mLock IS locked
void ReportPermaHang();
// Called by BackgroundHangMonitor::NotifyActivity
@ -240,7 +240,7 @@ public:
// We were hanging! We're done with that now, so let's report it.
// ReportHang() doesn't do much work on the current thread, and is
// safe to call from any thread as long as we're holding the lock.
ReportHang(mInterval - mHangStart);
ReportHang(mLastActivity - mHangStart);
mHanging = false;
}
mWaiting = true;
@ -262,7 +262,6 @@ bool BackgroundHangThread::sTlsKeyInitialized;
BackgroundHangManager::BackgroundHangManager()
: mShutdown(false)
, mLock("BackgroundHangManager")
, mIntervalNow(0)
{
// Lock so we don't race against the new monitor thread
MonitorAutoLock autoLock(mLock);
@ -305,25 +304,25 @@ BackgroundHangManager::RunMonitorThread()
// Keep us locked except when waiting
MonitorAutoLock autoLock(mLock);
/* mIntervalNow is updated at various intervals determined by waitTime.
/* mNow is updated at various intervals determined by waitTime.
However, if an update latency is too long (due to CPU scheduling, system
sleep, etc.), we don't update mIntervalNow at all. This is done so that
sleep, etc.), we don't update mNow at all. This is done so that
long latencies in our timing are not detected as hangs. systemTime is
used to track PR_IntervalNow() and determine our latency. */
used to track TimeStamp::Now() and determine our latency. */
PRIntervalTime systemTime = PR_IntervalNow();
TimeStamp systemTime = TimeStamp::Now();
// Default values for the first iteration of thread loop
PRIntervalTime waitTime = PR_INTERVAL_NO_WAIT;
PRIntervalTime recheckTimeout = PR_INTERVAL_NO_WAIT;
PRIntervalTime lastCheckedCPUUsage = systemTime;
PRIntervalTime checkCPUUsageInterval =
PR_MillisecondsToInterval(kCheckCPUIntervalMilliseconds);
TimeDuration waitTime;
TimeDuration recheckTimeout;
TimeStamp lastCheckedCPUUsage = systemTime;
TimeDuration checkCPUUsageInterval =
TimeDuration::FromMilliseconds(kCheckCPUIntervalMilliseconds);
while (!mShutdown) {
nsresult rv = autoLock.Wait(waitTime);
autoLock.Wait(waitTime);
PRIntervalTime newTime = PR_IntervalNow();
PRIntervalTime systemInterval = newTime - systemTime;
TimeStamp newTime = TimeStamp::Now();
TimeDuration systemInterval = newTime - systemTime;
systemTime = newTime;
if (systemTime - lastCheckedCPUUsage > checkCPUUsageInterval) {
@ -333,18 +332,17 @@ BackgroundHangManager::RunMonitorThread()
/* waitTime is a quarter of the shortest timeout value; If our timing
latency is low enough (less than half the shortest timeout value),
we can update mIntervalNow. */
if (MOZ_LIKELY(waitTime != PR_INTERVAL_NO_TIMEOUT &&
systemInterval < 2 * waitTime)) {
mIntervalNow += systemInterval;
we can update mNow. */
if (MOZ_LIKELY(waitTime != TimeDuration::Forever() &&
systemInterval < waitTime * 2)) {
mNow += systemInterval;
}
/* If it's before the next recheck timeout, and our wait did not get
interrupted, we can keep the current waitTime and skip iterating
through hang monitors. */
if (MOZ_LIKELY(systemInterval < recheckTimeout &&
systemInterval >= waitTime &&
rv == NS_OK)) {
systemInterval >= waitTime)) {
recheckTimeout -= systemInterval;
continue;
}
@ -355,11 +353,11 @@ BackgroundHangManager::RunMonitorThread()
- Thread wait or hang ended
In all cases, we want to go through our list of hang
monitors and update waitTime and recheckTimeout. */
waitTime = PR_INTERVAL_NO_TIMEOUT;
recheckTimeout = PR_INTERVAL_NO_TIMEOUT;
waitTime = TimeDuration::Forever();
recheckTimeout = TimeDuration::Forever();
// Locally hold mIntervalNow
PRIntervalTime intervalNow = mIntervalNow;
// Locally hold mNow
TimeStamp now = mNow;
// iterate through hang monitors
for (BackgroundHangThread* currentThread = mHangThreads.getFirst();
@ -369,8 +367,8 @@ BackgroundHangManager::RunMonitorThread()
// Thread is waiting, not hanging
continue;
}
PRIntervalTime interval = currentThread->mInterval;
PRIntervalTime hangTime = intervalNow - interval;
TimeStamp lastActivity = currentThread->mLastActivity;
TimeDuration hangTime = now - lastActivity;
if (MOZ_UNLIKELY(hangTime >= currentThread->mMaxTimeout)) {
// A permahang started
// Skip subsequent iterations and tolerate a race on mWaiting here
@ -399,15 +397,15 @@ BackgroundHangManager::RunMonitorThread()
lastCheckedCPUUsage = systemTime;
}
currentThread->mHangStart = interval;
currentThread->mHangStart = lastActivity;
currentThread->mHanging = true;
currentThread->mAnnotations =
currentThread->mAnnotators.GatherAnnotations();
}
} else {
if (MOZ_LIKELY(interval != currentThread->mHangStart)) {
if (MOZ_LIKELY(lastActivity != currentThread->mHangStart)) {
// A hang ended
currentThread->ReportHang(intervalNow - currentThread->mHangStart);
currentThread->ReportHang(now - currentThread->mHangStart);
currentThread->mHanging = false;
}
}
@ -415,18 +413,18 @@ BackgroundHangManager::RunMonitorThread()
/* If we are hanging, the next time we check for hang status is when
the hang turns into a permahang. If we're not hanging, the next
recheck timeout is when we may be entering a hang. */
PRIntervalTime nextRecheck;
TimeDuration nextRecheck;
if (currentThread->mHanging) {
nextRecheck = currentThread->mMaxTimeout;
} else {
nextRecheck = currentThread->mTimeout;
}
recheckTimeout = std::min(recheckTimeout, nextRecheck - hangTime);
recheckTimeout = TimeDuration::Min(recheckTimeout, nextRecheck - hangTime);
if (currentThread->mTimeout != PR_INTERVAL_NO_TIMEOUT) {
if (currentThread->mTimeout != TimeDuration::Forever()) {
/* We wait for a quarter of the shortest timeout
value to give mIntervalNow enough granularity. */
waitTime = std::min(waitTime, currentThread->mTimeout / 4);
value to give mNow enough granularity. */
waitTime = TimeDuration::Min(waitTime, currentThread->mTimeout / (int64_t) 4);
}
}
}
@ -434,7 +432,7 @@ BackgroundHangManager::RunMonitorThread()
/* We are shutting down now.
Wait for all outstanding monitors to unregister. */
while (!mHangThreads.isEmpty()) {
autoLock.Wait(PR_INTERVAL_NO_TIMEOUT);
autoLock.Wait();
}
}
@ -446,13 +444,13 @@ BackgroundHangThread::BackgroundHangThread(const char* aName,
: mManager(BackgroundHangManager::sInstance)
, mThreadID(PR_GetCurrentThread())
, mTimeout(aTimeoutMs == BackgroundHangMonitor::kNoTimeout
? PR_INTERVAL_NO_TIMEOUT
: PR_MillisecondsToInterval(aTimeoutMs))
? TimeDuration::Forever()
: TimeDuration::FromMilliseconds(aTimeoutMs))
, mMaxTimeout(aMaxTimeoutMs == BackgroundHangMonitor::kNoTimeout
? PR_INTERVAL_NO_TIMEOUT
: PR_MillisecondsToInterval(aMaxTimeoutMs))
, mInterval(mManager->mIntervalNow)
, mHangStart(mInterval)
? TimeDuration::Forever()
: TimeDuration::FromMilliseconds(aMaxTimeoutMs))
, mLastActivity(mManager->mNow)
, mHangStart(mLastActivity)
, mHanging(false)
, mWaiting(true)
, mThreadType(aThreadType)
@ -485,7 +483,7 @@ BackgroundHangThread::~BackgroundHangThread()
}
void
BackgroundHangThread::ReportHang(PRIntervalTime aHangTime)
BackgroundHangThread::ReportHang(TimeDuration aHangTime)
{
// Recovered from a hang; called on the monitor thread
// mManager->mLock IS locked
@ -524,7 +522,7 @@ BackgroundHangThread::ReportHang(PRIntervalTime aHangTime)
#ifdef MOZ_GECKO_PROFILER
if (profiler_is_active()) {
TimeStamp endTime = TimeStamp::Now();
TimeStamp startTime = endTime - TimeDuration::FromMilliseconds(aHangTime);
TimeStamp startTime = endTime - aHangTime;
profiler_add_marker_for_thread(
mStackHelper.GetThreadId(),
"BHR-detected hang",
@ -551,20 +549,20 @@ BackgroundHangThread::ReportPermaHang()
MOZ_ALWAYS_INLINE void
BackgroundHangThread::Update()
{
PRIntervalTime intervalNow = mManager->mIntervalNow;
TimeStamp now = mManager->mNow;
if (mWaiting) {
mInterval = intervalNow;
mLastActivity = now;
mWaiting = false;
/* We have to wake up the manager thread because when all threads
are waiting, the manager thread waits indefinitely as well. */
mManager->Wakeup();
} else {
PRIntervalTime duration = intervalNow - mInterval;
TimeDuration duration = now - mLastActivity;
if (MOZ_UNLIKELY(duration >= mTimeout)) {
/* Wake up the manager thread to tell it that a hang ended */
mManager->Wakeup();
}
mInterval = intervalNow;
mLastActivity = now;
}
}

Просмотреть файл

@ -13,9 +13,9 @@
namespace mozilla {
NS_IMETHODIMP
nsHangDetails::GetDuration(uint32_t* aDuration)
nsHangDetails::GetDuration(double* aDuration)
{
*aDuration = mDetails.duration();
*aDuration = mDetails.duration().ToMilliseconds();
return NS_OK;
}

Просмотреть файл

@ -69,23 +69,4 @@ private:
} // namespace mozilla
// We implement the ability to send the HangDetails object over IPC. We need to
// do this rather than rely on StructuredClone of the objects created by the
// XPCOM getters on nsHangDetails because we want to run BHR in the GPU process
// which doesn't run any JS.
namespace IPC {
template<>
class ParamTraits<mozilla::HangDetails>
{
public:
typedef mozilla::HangDetails paramType;
static void Write(Message* aMsg, const paramType& aParam);
static bool Read(const Message* aMsg,
PickleIterator* aIter,
paramType* aResult);
};
} // namespace IPC
#endif // mozilla_HangDetails_h

Просмотреть файл

@ -4,6 +4,8 @@
* 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/. */
using class mozilla::TimeDuration from "mozilla/TimeStamp.h";
namespace mozilla {
// The different kinds of hang entries which we're going to need to handle in
@ -81,7 +83,7 @@ struct HangAnnotation
// The information about an individual hang which is sent over IPC.
struct HangDetails
{
uint32_t duration;
TimeDuration duration;
nsCString process;
nsString remoteType;
nsCString threadName;

Просмотреть файл

@ -21,9 +21,9 @@ class HangDetails;
interface nsIHangDetails : nsISupports
{
/**
* The detected duration of the hang.
* The detected duration of the hang in milliseconds.
*/
readonly attribute uint32_t duration;
readonly attribute double duration;
/**
* The name of the thread which hung.

Просмотреть файл

@ -97,9 +97,9 @@ UpdateDriverSetupMacCommandLine(int& argc, char**& argv, bool restart)
// The length of this wait is arbitrary, but should be long enough that having
// it expire means something is seriously wrong.
rv = MonitorAutoLock(monitor).Wait(PR_SecondsToInterval(60));
if (NS_FAILED(rv)) {
LOG(("Update driver timed out waiting for SetupMacCommandLine: %d\n", rv));
CVStatus status = MonitorAutoLock(monitor).Wait(TimeDuration::FromSeconds(60));
if (status == CVStatus::Timeout) {
LOG(("Update driver timed out waiting for SetupMacCommandLine\n"));
}
}
#endif

Просмотреть файл

@ -87,7 +87,7 @@ TEST(ThreadPool, Parallelism)
if (!mDone) {
// Wait for a reasonable timeout since we don't want to block gtests
// forever should any regression happen.
mon.Wait(PR_SecondsToInterval(300));
mon.Wait(TimeDuration::FromSeconds(300));
}
EXPECT_TRUE(mDone);
return NS_OK;

Просмотреть файл

@ -586,8 +586,16 @@ RecursiveMutex::AssertCurrentThreadIn()
//
// Debug implementation of CondVar
nsresult
CondVar::Wait(PRIntervalTime aInterval)
void
CondVar::Wait()
{
// Forward to the timed version of CondVar::Wait to avoid code duplication.
CVStatus status = Wait(TimeDuration::Forever());
MOZ_ASSERT(status == CVStatus::NoTimeout);
}
CVStatus
CondVar::Wait(TimeDuration aDuration)
{
AssertCurrentThreadOwnsMutex();
@ -600,18 +608,14 @@ CondVar::Wait(PRIntervalTime aInterval)
mLock->mOwningThread = nullptr;
// give up mutex until we're back from Wait()
if (aInterval == PR_INTERVAL_NO_TIMEOUT) {
mImpl.wait(*mLock);
} else {
mImpl.wait_for(*mLock, TimeDuration::FromMilliseconds(double(aInterval)));
}
CVStatus status = mImpl.wait_for(*mLock, aDuration);
// restore saved state
mLock->SetAcquisitionState(savedAcquisitionState);
mLock->mChainPrev = savedChainPrev;
mLock->mOwningThread = savedOwningThread;
return NS_OK;
return status;
}
#endif // ifdef DEBUG

Просмотреть файл

@ -53,27 +53,31 @@ public:
MOZ_COUNT_DTOR(CondVar);
}
#ifndef DEBUG
/**
* Wait
* @see prcvar.h
**/
nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
#ifndef DEBUG
void Wait()
{
#ifdef MOZILLA_INTERNAL_API
AUTO_PROFILER_THREAD_SLEEP;
#endif //MOZILLA_INTERNAL_API
if (aInterval == PR_INTERVAL_NO_TIMEOUT) {
mImpl.wait(*mLock);
} else {
mImpl.wait_for(*mLock, TimeDuration::FromMilliseconds(double(aInterval)));
}
return NS_OK;
mImpl.wait(*mLock);
}
CVStatus Wait(TimeDuration aDuration)
{
#ifdef MOZILLA_INTERNAL_API
AUTO_PROFILER_THREAD_SLEEP;
#endif //MOZILLA_INTERNAL_API
return mImpl.wait_for(*mLock, aDuration);
}
#else
nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT);
#endif // ifndef DEBUG
// NOTE: debug impl is in BlockingResourceBase.cpp
void Wait();
CVStatus Wait(TimeDuration aDuration);
#endif
/**
* Notify
@ -129,7 +133,6 @@ private:
detail::ConditionVariableImpl mImpl;
};
} // namespace mozilla

Просмотреть файл

@ -262,11 +262,11 @@ ThreadMain(void*)
waitCount = 0;
}
PRIntervalTime timeout;
TimeDuration timeout;
if (gTimeout <= 0) {
timeout = PR_INTERVAL_NO_TIMEOUT;
timeout = TimeDuration::Forever();
} else {
timeout = PR_MillisecondsToInterval(gTimeout * 500);
timeout = TimeDuration::FromMilliseconds(gTimeout * 500);
}
lock.Wait(timeout);
}

Просмотреть файл

@ -35,10 +35,8 @@ public:
void Lock() { mMutex.Lock(); }
void Unlock() { mMutex.Unlock(); }
nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
{
return mCondVar.Wait(aInterval);
}
void Wait() { mCondVar.Wait(); }
CVStatus Wait(TimeDuration aDuration) { return mCondVar.Wait(aDuration); }
nsresult Notify() { return mCondVar.Notify(); }
nsresult NotifyAll() { return mCondVar.NotifyAll(); }
@ -83,10 +81,8 @@ public:
mMonitor->Unlock();
}
nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
{
return mMonitor->Wait(aInterval);
}
void Wait() { mMonitor->Wait(); }
CVStatus Wait(TimeDuration aDuration) { return mMonitor->Wait(aDuration); }
nsresult Notify() { return mMonitor->Notify(); }
nsresult NotifyAll() { return mMonitor->NotifyAll(); }

Просмотреть файл

@ -443,7 +443,7 @@ SchedulerImpl::Switcher()
}
}
mShutdownCondVar.Wait(PR_MicrosecondsToInterval(50));
mShutdownCondVar.Wait(TimeDuration::FromMicroseconds(50));
}
}

Просмотреть файл

@ -421,7 +421,7 @@ TimerThread::Run()
while (!mShutdown) {
// Have to use PRIntervalTime here, since PR_WaitCondVar takes it
PRIntervalTime waitFor;
TimeDuration waitFor;
bool forceRunThisTimer = forceRunNextTimer;
forceRunNextTimer = false;
@ -431,9 +431,9 @@ TimerThread::Run()
if (ChaosMode::isActive(ChaosFeature::TimerScheduling)) {
milliseconds = ChaosMode::randomUint32LessThan(200);
}
waitFor = PR_MillisecondsToInterval(milliseconds);
waitFor = TimeDuration::FromMilliseconds(milliseconds);
} else {
waitFor = PR_INTERVAL_NO_TIMEOUT;
waitFor = TimeDuration::Forever();
TimeStamp now = TimeStamp::Now();
RemoveLeadingCanceledTimersInternal();
@ -520,20 +520,20 @@ 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 = TimeDuration::FromMicroseconds(microseconds);
if (waitFor.IsZero()) {
// round up, wait the minimum time we can wait
waitFor = TimeDuration::FromMicroseconds(1);
}
}
if (MOZ_LOG_TEST(GetTimerLog(), LogLevel::Debug)) {
if (waitFor == PR_INTERVAL_NO_TIMEOUT)
if (waitFor == TimeDuration::Forever())
MOZ_LOG(GetTimerLog(), LogLevel::Debug,
("waiting for PR_INTERVAL_NO_TIMEOUT\n"));
("waiting forever\n"));
else
MOZ_LOG(GetTimerLog(), LogLevel::Debug,
("waiting for %u\n", PR_IntervalToMilliseconds(waitFor)));
("waiting for %f\n", waitFor.ToMilliseconds()));
}
}

Просмотреть файл

@ -163,7 +163,7 @@ nsThreadPool::Run()
bool shutdownThreadOnExit = false;
bool exitThread = false;
bool wasIdle = false;
PRIntervalTime idleSince;
TimeStamp idleSince;
nsCOMPtr<nsIThreadPoolListener> listener;
{
@ -182,8 +182,8 @@ nsThreadPool::Run()
event = mEvents.GetEvent(nullptr, lock);
if (!event) {
PRIntervalTime now = PR_IntervalNow();
PRIntervalTime timeout = PR_MillisecondsToInterval(mIdleThreadTimeout);
TimeStamp now = TimeStamp::Now();
TimeDuration timeout = TimeDuration::FromMilliseconds(mIdleThreadTimeout);
// If we are shutting down, then don't keep any idle threads
if (mShutdown) {
@ -213,8 +213,9 @@ nsThreadPool::Run()
}
shutdownThreadOnExit = mThreads.RemoveObject(current);
} else {
PRIntervalTime delta = timeout - (now - idleSince);
LOG(("THRD-P(%p) %s waiting [%d]\n", this, mName.BeginReading(), delta));
TimeDuration delta = timeout - (now - idleSince);
LOG(("THRD-P(%p) %s waiting [%f]\n", this, mName.BeginReading(),
delta.ToMilliseconds()));
mEventsAvailable.Wait(delta);
LOG(("THRD-P(%p) done waiting\n", this));
}