Backed out 4 changesets (bug 1437167) for build bustages on nsUpdateDriver.cpp and WindowsMessageLoop.cpp on a CLOSED TREE.

Backed out changeset b98740e7c639 (bug 1437167)
Backed out changeset 4476e8f51fa6 (bug 1437167)
Backed out changeset c79dc40faa41 (bug 1437167)
Backed out changeset b608d2dcbb86 (bug 1437167)
This commit is contained in:
Cosmin Sabou 2018-03-06 00:09:46 +02:00
parent 6731fbe8de
commit ed1b2a8736
38 changed files with 255 additions and 222 deletions

View File

@ -365,7 +365,7 @@ SystemClockDriver::WaitForNextIteration()
{
mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
TimeDuration timeout = TimeDuration::Forever();
PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
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 = TimeDuration::FromMilliseconds(timeoutMS);
timeout = PR_MillisecondsToInterval(uint32_t(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.IsZero()) {
if (timeout > 0) {
mGraphImpl->GetMonitor().Wait(timeout);
LOG(LogLevel::Verbose,
("Resuming after timeout; at %f, elapsed=%f",

View File

@ -181,6 +181,7 @@ StorageDBThread::StorageDBThread()
, mStatus(NS_OK)
, mWorkerStatements(mWorkerConnection)
, mReaderStatements(mReaderConnection)
, mDirtyEpoch(0)
, mFlushImmediately(false)
, mPriorityCounter(0)
{
@ -530,8 +531,7 @@ StorageDBThread::ThreadFunc()
} while (NS_SUCCEEDED(rv) && processedEvent);
}
TimeDuration timeUntilFlush = TimeUntilFlush();
if (MOZ_UNLIKELY(timeUntilFlush.IsZero())) {
if (MOZ_UNLIKELY(TimeUntilFlush() == 0)) {
// 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 = TimeStamp::Now();
mDirtyEpoch = PR_IntervalNow() | 1;
// Wake the monitor from indefinite sleep...
(mThreadObserver->GetMonitor()).Notify();
@ -836,28 +836,32 @@ StorageDBThread::UnscheduleFlush()
{
// We are just about to do the flush, drop flags
mFlushImmediately = false;
mDirtyEpoch = TimeStamp();
mDirtyEpoch = 0;
}
TimeDuration
PRIntervalTime
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 TimeDuration::Forever(); // No pending task...
return PR_INTERVAL_NO_TIMEOUT; // No pending task...
}
TimeStamp now = TimeStamp::Now();
TimeDuration age = now - mDirtyEpoch;
static const TimeDuration kMaxAge = TimeDuration::FromMilliseconds(FLUSHING_INTERVAL_MS);
static const PRIntervalTime kMaxAge = PR_MillisecondsToInterval(FLUSHING_INTERVAL_MS);
PRIntervalTime now = PR_IntervalNow() | 1;
PRIntervalTime age = now - mDirtyEpoch;
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

View File

@ -14,7 +14,6 @@
#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"
@ -441,7 +440,7 @@ private:
// Time the first pending operation has been added to the pending operations
// list
TimeStamp mDirtyEpoch;
PRIntervalTime mDirtyEpoch;
// Flag to force immediate flush of all pending operations
bool mFlushImmediately;
@ -487,12 +486,12 @@ private:
// 2. as in indicator that flush has to be performed
//
// Return:
// - 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();
// - 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();
// Notifies to the main thread that flush has completed
void NotifyFlushCompletion();

View File

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

View File

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

View File

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

View File

@ -10,7 +10,6 @@
#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"
@ -59,7 +58,7 @@ public:
DecodePoolImpl(uint8_t aMaxThreads,
uint8_t aMaxIdleThreads,
TimeDuration aIdleTimeout)
PRIntervalTime aIdleTimeout)
: mMonitor("DecodePoolImpl")
, mThreads(aMaxThreads)
, mIdleTimeout(aIdleTimeout)
@ -173,7 +172,7 @@ private:
{
mMonitor.AssertCurrentThreadOwns();
TimeDuration timeout = mIdleTimeout;
PRIntervalTime timeout = mIdleTimeout;
do {
if (!mHighPriorityQueue.IsEmpty()) {
return PopWorkFromQueue(mHighPriorityQueue);
@ -198,19 +197,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.IsZero()) {
if (timeout == 0) {
return CreateShutdownWork();
}
++mIdleThreads;
MOZ_ASSERT(mIdleThreads <= mThreads.Capacity());
TimeStamp now = TimeStamp::Now();
PRIntervalTime now = PR_IntervalNow();
mMonitor.Wait(timeout);
TimeDuration delta = TimeStamp::Now() - now;
PRIntervalTime delta = PR_IntervalNow() - now;
if (delta > timeout) {
timeout = 0;
} else if (timeout != TimeDuration::Forever()) {
} else {
timeout -= delta;
}
}
@ -248,7 +247,7 @@ private:
nsTArray<RefPtr<IDecodingTask>> mHighPriorityQueue;
nsTArray<RefPtr<IDecodingTask>> mLowPriorityQueue;
nsTArray<nsCOMPtr<nsIThread>> mThreads;
TimeDuration mIdleTimeout;
PRIntervalTime 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.
@ -384,12 +383,12 @@ DecodePool::DecodePool()
// The timeout period before shutting down idle threads.
int32_t prefIdleTimeout = gfxPrefs::ImageMTDecodingIdleTimeout();
TimeDuration idleTimeout;
PRIntervalTime idleTimeout;
if (prefIdleTimeout <= 0) {
idleTimeout = TimeDuration::Forever();
idleTimeout = PR_INTERVAL_NO_TIMEOUT;
idleLimit = limit;
} else {
idleTimeout = TimeDuration::FromMilliseconds(prefIdleTimeout);
idleTimeout = PR_MillisecondsToInterval(static_cast<uint32_t>(prefIdleTimeout));
idleLimit = (limit + 1) / 2;
}

View File

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

View File

@ -2316,6 +2316,13 @@ 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)
{
@ -2345,14 +2352,17 @@ MessageChannel::WaitForSyncNotify(bool /* aHandleWindowsMessages */)
}
#endif
TimeDuration timeout = (kNoTimeout == mTimeoutMs) ?
TimeDuration::Forever() :
TimeDuration::FromMilliseconds(mTimeoutMs);
CVStatus status = mMonitor->Wait(timeout);
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);
// If the timeout didn't expire, we know we received an event. The
// converse is not true.
return WaitResponse(status == CVStatus::Timeout);
return WaitResponse(IsTimeoutExpired(waitStart, timeout));
}
bool

View File

@ -846,6 +846,13 @@ 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
@ -1023,21 +1030,27 @@ 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) {
TimeDuration timeout = (kNoTimeout == mTimeoutMs) ?
TimeDuration::Forever() :
TimeDuration::FromMilliseconds(mTimeoutMs);
PRIntervalTime timeout = (kNoTimeout == mTimeoutMs) ?
PR_INTERVAL_NO_TIMEOUT :
PR_MillisecondsToInterval(mTimeoutMs);
PRIntervalTime waitStart = 0;
if (timeout != PR_INTERVAL_NO_TIMEOUT) {
waitStart = PR_IntervalNow();
}
MOZ_ASSERT(!mIsSyncWaitingOnNonMainThread);
mIsSyncWaitingOnNonMainThread = true;
CVStatus status = mMonitor->Wait(timeout);
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(status == CVStatus::Timeout);
return WaitResponse(timeout == PR_INTERVAL_NO_TIMEOUT ?
false : IsTimeoutExpired(waitStart, timeout));
}
NS_ASSERTION(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION,

View File

@ -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::CVStatus::Timeout
return impl_.wait_for(lock.lock, rel_time) == mozilla::detail::CVStatus::Timeout
? CVStatus::Timeout : CVStatus::NoTimeout;
}

View File

@ -695,7 +695,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(TimeDuration::FromSeconds(10));
mal.Wait(10000);
}
auto result = URLPreloader::GetSingleton().WriteCache();

View File

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

View File

@ -59,35 +59,21 @@ mozilla::detail::ConditionVariableImpl::wait(MutexImpl& lock)
MOZ_RELEASE_ASSERT(r);
}
mozilla::CVStatus
mozilla::detail::CVStatus
mozilla::detail::ConditionVariableImpl::wait_for(MutexImpl& lock,
const mozilla::TimeDuration& rel_time)
{
if (rel_time == mozilla::TimeDuration::Forever()) {
wait(lock);
return CVStatus::NoTimeout;
}
CRITICAL_SECTION* cs = &lock.platformData()->criticalSection;
// Note that DWORD is unsigned, so we have to be careful to clamp at 0. If
// rel_time is Forever, then ToMilliseconds is +inf, which evaluates as
// greater than UINT32_MAX, resulting in the correct INFINITE wait. We also
// don't want to round sub-millisecond waits to 0, as that wastes energy (see
// bug 1437167 comment 6), so we instead round submillisecond waits to 1ms.
// Note that DWORD is unsigned, so we have to be careful to clamp at 0.
// If rel_time is Forever, then ToMilliseconds is +inf, which evaluates as
// greater than UINT32_MAX, resulting in the correct INFINITE wait.
double msecd = rel_time.ToMilliseconds();
DWORD msec;
if (msecd < 0.0) {
msec = 0;
} else if (msecd > UINT32_MAX) {
msec = INFINITE;
} else {
msec = static_cast<DWORD>(msecd);
// Round submillisecond waits to 1ms.
if (msec == 0 && !rel_time.IsZero()) {
msec = 1;
}
}
DWORD msec = msecd < 0.0
? 0
: msecd > UINT32_MAX
? INFINITE
: static_cast<DWORD>(msecd);
BOOL r = SleepConditionVariableCS(&platformData()->cv_, cs, msec);
if (r)

View File

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

View File

@ -1677,7 +1677,8 @@ private:
nsresult rv = mTaskQueue->Dispatch(runnable.forget());
NS_ENSURE_SUCCESS(rv, rv);
lock.Wait();
rv = lock.Wait();
NS_ENSURE_SUCCESS(rv, rv);
mCompleted = true;
return mAsyncResult;

View File

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

View File

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

View File

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

View File

@ -524,8 +524,8 @@ nsHostResolver::nsHostResolver(uint32_t maxCacheEntries,
{
mCreationTime = PR_Now();
mLongIdleTimeout = TimeDuration::FromSeconds(LongIdleTimeoutSeconds);
mShortIdleTimeout = TimeDuration::FromSeconds(ShortIdleTimeoutSeconds);
mLongIdleTimeout = PR_SecondsToInterval(LongIdleTimeoutSeconds);
mShortIdleTimeout = PR_SecondsToInterval(ShortIdleTimeoutSeconds);
}
nsHostResolver::~nsHostResolver() = default;
@ -1297,13 +1297,12 @@ bool
nsHostResolver::GetHostToLookup(nsHostRecord **result)
{
bool timedOut = false;
TimeDuration timeout;
TimeStamp epoch, now;
PRIntervalTime epoch, now, timeout;
MutexAutoLock lock(mLock);
timeout = (mNumIdleThreads >= HighThreadThreshold) ? mShortIdleTimeout : mLongIdleTimeout;
epoch = TimeStamp::Now();
epoch = PR_IntervalNow();
while (!mShutdown) {
// remove next record from Q; hand over owning reference. Check high, then med, then low
@ -1348,16 +1347,15 @@ nsHostResolver::GetHostToLookup(nsHostRecord **result)
mIdleThreadCV.Wait(timeout);
mNumIdleThreads--;
now = TimeStamp::Now();
now = PR_IntervalNow();
if (now - epoch >= timeout) {
if ((PRIntervalTime)(now - epoch) >= timeout)
timedOut = true;
} 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;
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);
epoch = now;
}
}

View File

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

View File

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

View File

@ -427,7 +427,7 @@ nsNSSHttpRequestSession::internal_send_receive_attempt(bool &retryable_error,
MutexAutoLock locker(waitLock);
const TimeStamp startTime = TimeStamp::NowLoRes();
TimeDuration wait_interval;
PRIntervalTime 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 = TimeDuration::FromMicroseconds(50);
wait_interval = PR_MicrosecondsToInterval(50);
}
else
{
// On a secondary thread, it's fine to wait some more for
// for the condition variable.
wait_interval = TimeDuration::FromMilliseconds(250);
wait_interval = PR_MillisecondsToInterval(250);
}
while (waitFlag)

View File

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

View File

@ -98,7 +98,7 @@ public:
// Lock for access to members of this class
Monitor mLock;
// Current time as seen by hang monitors
TimeStamp mNow;
PRIntervalTime mIntervalNow;
// List of BackgroundHangThread instances associated with each thread
LinkedList<BackgroundHangThread> mHangThreads;
// A reference to the StreamTransportService. This is gotten on the main
@ -182,14 +182,14 @@ public:
sTlsKeyInitialized = sTlsKey.init();
}
// Hang timeout
const TimeDuration mTimeout;
// PermaHang timeout
const TimeDuration mMaxTimeout;
// Hang timeout in ticks
const PRIntervalTime mTimeout;
// PermaHang timeout in ticks
const PRIntervalTime mMaxTimeout;
// Time at last activity
TimeStamp mLastActivity;
PRIntervalTime mInterval;
// Time when a hang started
TimeStamp mHangStart;
PRIntervalTime mHangStart;
// Is the thread in a hang
bool mHanging;
// Is the thread in a waiting state
@ -218,7 +218,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(TimeDuration aHangTime);
void ReportHang(PRIntervalTime aHangTime);
// Report a permanent hang; aManager->mLock IS locked
void ReportPermaHang();
// Called by BackgroundHangMonitor::NotifyActivity
@ -256,6 +256,7 @@ bool BackgroundHangThread::sTlsKeyInitialized;
BackgroundHangManager::BackgroundHangManager()
: mShutdown(false)
, mLock("BackgroundHangManager")
, mIntervalNow(0)
, mSTS(do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID))
{
// Lock so we don't race against the new monitor thread
@ -287,25 +288,25 @@ BackgroundHangManager::RunMonitorThread()
// Keep us locked except when waiting
MonitorAutoLock autoLock(mLock);
/* mNow is updated at various intervals determined by waitTime.
/* mIntervalNow 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 mNow at all. This is done so that
sleep, etc.), we don't update mIntervalNow at all. This is done so that
long latencies in our timing are not detected as hangs. systemTime is
used to track TimeStamp::Now() and determine our latency. */
used to track PR_IntervalNow() and determine our latency. */
TimeStamp systemTime = TimeStamp::Now();
PRIntervalTime systemTime = PR_IntervalNow();
// Default values for the first iteration of thread loop
TimeDuration waitTime;
TimeDuration recheckTimeout;
TimeStamp lastCheckedCPUUsage = systemTime;
TimeDuration checkCPUUsageInterval =
TimeDuration::FromMilliseconds(kCheckCPUIntervalMilliseconds);
PRIntervalTime waitTime = PR_INTERVAL_NO_WAIT;
PRIntervalTime recheckTimeout = PR_INTERVAL_NO_WAIT;
PRIntervalTime lastCheckedCPUUsage = systemTime;
PRIntervalTime checkCPUUsageInterval =
PR_MillisecondsToInterval(kCheckCPUIntervalMilliseconds);
while (!mShutdown) {
autoLock.Wait(waitTime);
nsresult rv = autoLock.Wait(waitTime);
TimeStamp newTime = TimeStamp::Now();
TimeDuration systemInterval = newTime - systemTime;
PRIntervalTime newTime = PR_IntervalNow();
PRIntervalTime systemInterval = newTime - systemTime;
systemTime = newTime;
if (systemTime - lastCheckedCPUUsage > checkCPUUsageInterval) {
@ -315,17 +316,18 @@ 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 mNow. */
if (MOZ_LIKELY(waitTime != TimeDuration::Forever() &&
systemInterval < waitTime * 2)) {
mNow += systemInterval;
we can update mIntervalNow. */
if (MOZ_LIKELY(waitTime != PR_INTERVAL_NO_TIMEOUT &&
systemInterval < 2 * waitTime)) {
mIntervalNow += 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)) {
systemInterval >= waitTime &&
rv == NS_OK)) {
recheckTimeout -= systemInterval;
continue;
}
@ -336,11 +338,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 = TimeDuration::Forever();
recheckTimeout = TimeDuration::Forever();
waitTime = PR_INTERVAL_NO_TIMEOUT;
recheckTimeout = PR_INTERVAL_NO_TIMEOUT;
// Locally hold mNow
TimeStamp now = mNow;
// Locally hold mIntervalNow
PRIntervalTime intervalNow = mIntervalNow;
// iterate through hang monitors
for (BackgroundHangThread* currentThread = mHangThreads.getFirst();
@ -350,8 +352,8 @@ BackgroundHangManager::RunMonitorThread()
// Thread is waiting, not hanging
continue;
}
TimeStamp lastActivity = currentThread->mLastActivity;
TimeDuration hangTime = now - lastActivity;
PRIntervalTime interval = currentThread->mInterval;
PRIntervalTime hangTime = intervalNow - interval;
if (MOZ_UNLIKELY(hangTime >= currentThread->mMaxTimeout)) {
// A permahang started
// Skip subsequent iterations and tolerate a race on mWaiting here
@ -380,15 +382,15 @@ BackgroundHangManager::RunMonitorThread()
lastCheckedCPUUsage = systemTime;
}
currentThread->mHangStart = lastActivity;
currentThread->mHangStart = interval;
currentThread->mHanging = true;
currentThread->mAnnotations =
currentThread->mAnnotators.GatherAnnotations();
}
} else {
if (MOZ_LIKELY(lastActivity != currentThread->mHangStart)) {
if (MOZ_LIKELY(interval != currentThread->mHangStart)) {
// A hang ended
currentThread->ReportHang(now - currentThread->mHangStart);
currentThread->ReportHang(intervalNow - currentThread->mHangStart);
currentThread->mHanging = false;
}
}
@ -396,18 +398,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. */
TimeDuration nextRecheck;
PRIntervalTime nextRecheck;
if (currentThread->mHanging) {
nextRecheck = currentThread->mMaxTimeout;
} else {
nextRecheck = currentThread->mTimeout;
}
recheckTimeout = TimeDuration::Min(recheckTimeout, nextRecheck - hangTime);
recheckTimeout = std::min(recheckTimeout, nextRecheck - hangTime);
if (currentThread->mTimeout != TimeDuration::Forever()) {
if (currentThread->mTimeout != PR_INTERVAL_NO_TIMEOUT) {
/* We wait for a quarter of the shortest timeout
value to give mNow enough granularity. */
waitTime = TimeDuration::Min(waitTime, currentThread->mTimeout / (int64_t) 4);
value to give mIntervalNow enough granularity. */
waitTime = std::min(waitTime, currentThread->mTimeout / 4);
}
}
}
@ -415,7 +417,7 @@ BackgroundHangManager::RunMonitorThread()
/* We are shutting down now.
Wait for all outstanding monitors to unregister. */
while (!mHangThreads.isEmpty()) {
autoLock.Wait();
autoLock.Wait(PR_INTERVAL_NO_TIMEOUT);
}
}
@ -427,13 +429,13 @@ BackgroundHangThread::BackgroundHangThread(const char* aName,
: mManager(BackgroundHangManager::sInstance)
, mThreadID(PR_GetCurrentThread())
, mTimeout(aTimeoutMs == BackgroundHangMonitor::kNoTimeout
? TimeDuration::Forever()
: TimeDuration::FromMilliseconds(aTimeoutMs))
? PR_INTERVAL_NO_TIMEOUT
: PR_MillisecondsToInterval(aTimeoutMs))
, mMaxTimeout(aMaxTimeoutMs == BackgroundHangMonitor::kNoTimeout
? TimeDuration::Forever()
: TimeDuration::FromMilliseconds(aMaxTimeoutMs))
, mLastActivity(mManager->mNow)
, mHangStart(mLastActivity)
? PR_INTERVAL_NO_TIMEOUT
: PR_MillisecondsToInterval(aMaxTimeoutMs))
, mInterval(mManager->mIntervalNow)
, mHangStart(mInterval)
, mHanging(false)
, mWaiting(true)
, mThreadType(aThreadType)
@ -466,7 +468,7 @@ BackgroundHangThread::~BackgroundHangThread()
}
void
BackgroundHangThread::ReportHang(TimeDuration aHangTime)
BackgroundHangThread::ReportHang(PRIntervalTime aHangTime)
{
// Recovered from a hang; called on the monitor thread
// mManager->mLock IS locked
@ -504,7 +506,7 @@ BackgroundHangThread::ReportHang(TimeDuration aHangTime)
#ifdef MOZ_GECKO_PROFILER
if (profiler_is_active()) {
TimeStamp endTime = TimeStamp::Now();
TimeStamp startTime = endTime - aHangTime;
TimeStamp startTime = endTime - TimeDuration::FromMilliseconds(aHangTime);
profiler_add_marker_for_thread(
mStackHelper.GetThreadId(),
"BHR-detected hang",
@ -531,20 +533,20 @@ BackgroundHangThread::ReportPermaHang()
MOZ_ALWAYS_INLINE void
BackgroundHangThread::Update()
{
TimeStamp now = mManager->mNow;
PRIntervalTime intervalNow = mManager->mIntervalNow;
if (mWaiting) {
mLastActivity = now;
mInterval = intervalNow;
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 {
TimeDuration duration = now - mLastActivity;
PRIntervalTime duration = intervalNow - mInterval;
if (MOZ_UNLIKELY(duration >= mTimeout)) {
/* Wake up the manager thread to tell it that a hang ended */
mManager->Wakeup();
}
mLastActivity = now;
mInterval = intervalNow;
}
}

View File

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

View File

@ -69,4 +69,23 @@ 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

View File

@ -4,8 +4,6 @@
* 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
@ -83,7 +81,7 @@ struct HangAnnotation
// The information about an individual hang which is sent over IPC.
struct HangDetails
{
TimeDuration duration;
uint32_t duration;
nsCString process;
nsString remoteType;
nsCString threadName;

View File

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

View File

@ -97,7 +97,7 @@ 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(TimeDuration::FromSeconds(60));
rv = MonitorAutoLock(monitor).Wait(PR_SecondsToInterval(60));
if (NS_FAILED(rv)) {
LOG(("Update driver timed out waiting for SetupMacCommandLine: %d\n", rv));
}

View File

@ -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(TimeDuration::FromSeconds(300));
mon.Wait(PR_SecondsToInterval(300));
}
EXPECT_TRUE(mDone);
return NS_OK;

View File

@ -586,16 +586,8 @@ RecursiveMutex::AssertCurrentThreadIn()
//
// Debug implementation of CondVar
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)
nsresult
CondVar::Wait(PRIntervalTime aInterval)
{
AssertCurrentThreadOwnsMutex();
@ -608,14 +600,18 @@ CondVar::Wait(TimeDuration aDuration)
mLock->mOwningThread = nullptr;
// give up mutex until we're back from Wait()
CVStatus status = mImpl.wait_for(*mLock, aDuration);
if (aInterval == PR_INTERVAL_NO_TIMEOUT) {
mImpl.wait(*mLock);
} else {
mImpl.wait_for(*mLock, TimeDuration::FromMilliseconds(double(aInterval)));
}
// restore saved state
mLock->SetAcquisitionState(savedAcquisitionState);
mLock->mChainPrev = savedChainPrev;
mLock->mOwningThread = savedOwningThread;
return status;
return NS_OK;
}
#endif // ifdef DEBUG

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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