Skip to content

Commit

Permalink
Bug 1437167 - Part 1: Stop using PRIntervalTime as the argument to Co…
Browse files Browse the repository at this point in the history
…ndVar::Wait and Monitor::Wait, r=mstange, r=froydnj
  • Loading branch information
mystor authored and rainemak committed Jul 24, 2020
1 parent 3d77d86 commit 0f51907
Show file tree
Hide file tree
Showing 38 changed files with 249 additions and 285 deletions.
6 changes: 3 additions & 3 deletions dom/media/GraphDriver.cpp
Expand Up @@ -309,7 +309,7 @@ TimeStamp OfflineClockDriver::GetCurrentTimeStamp() {
void 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
Expand All @@ -328,7 +328,7 @@ void 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(), timeoutMS / 1000.0));
Expand All @@ -337,7 +337,7 @@ void 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",
(TimeStamp::Now() - mInitialTimeStamp).ToSeconds(),
Expand Down
49 changes: 23 additions & 26 deletions dom/storage/StorageDBThread.cpp
Expand Up @@ -163,17 +163,18 @@ class StorageDBThread::NoteBackgroundThreadRunnable final : public Runnable {
};

StorageDBThread::StorageDBThread()
: mThread(nullptr),
mThreadObserver(new ThreadObserver()),
mStopIOThread(false),
mWALModeEnabled(false),
mDBReady(false),
mStatus(NS_OK),
mWorkerStatements(mWorkerConnection),
mReaderStatements(mReaderConnection),
mDirtyEpoch(0),
mFlushImmediately(false),
mPriorityCounter(0) {}
: mThread(nullptr)
, mThreadObserver(new ThreadObserver())
, mStopIOThread(false)
, mWALModeEnabled(false)
, mDBReady(false)
, mStatus(NS_OK)
, mWorkerStatements(mWorkerConnection)
, mReaderStatements(mReaderConnection)
, mFlushImmediately(false)
, mPriorityCounter(0)
{
}

// static
StorageDBThread* StorageDBThread::Get() {
Expand Down Expand Up @@ -499,7 +500,8 @@ void 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()) {
Expand All @@ -526,7 +528,7 @@ void StorageDBThread::ThreadFunc() {
SetDefaultPriority(); // urgent preload unscheduled
}
} else if (MOZ_UNLIKELY(!mStopIOThread)) {
lockMonitor.Wait(TimeUntilFlush());
lockMonitor.Wait(timeUntilFlush);
}
} // thread loop

Expand Down Expand Up @@ -777,7 +779,7 @@ void 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();
Expand All @@ -786,31 +788,26 @@ void StorageDBThread::ScheduleFlush() {
void StorageDBThread::UnscheduleFlush() {
// We are just about to do the flush, drop flags
mFlushImmediately = false;
mDirtyEpoch = 0;
mDirtyEpoch = TimeStamp();
}

PRIntervalTime StorageDBThread::TimeUntilFlush() {
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 StorageDBThread::NotifyFlushCompletion() {
Expand Down
15 changes: 8 additions & 7 deletions dom/storage/StorageDBThread.h
Expand Up @@ -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"
Expand Down Expand Up @@ -415,7 +416,7 @@ class StorageDBThread final {

// 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;
Expand Down Expand Up @@ -461,12 +462,12 @@ class StorageDBThread final {
// 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();
Expand Down
6 changes: 3 additions & 3 deletions dom/workers/WorkerPrivate.cpp
Expand Up @@ -3296,7 +3296,7 @@ bool WorkerPrivate::InterruptCallback(JSContext* aCx) {
break;
}

WaitForWorkerEvents(PR_MillisecondsToInterval(UINT32_MAX));
WaitForWorkerEvents();
}
}

Expand Down Expand Up @@ -3405,12 +3405,12 @@ void WorkerPrivate::DisableMemoryReporter() {
}
}

void WorkerPrivate::WaitForWorkerEvents(PRIntervalTime aInterval) {
void WorkerPrivate::WaitForWorkerEvents() {
AssertIsOnWorkerThread();
mMutex.AssertCurrentThreadOwns();

// Wait for a worker event.
mCondVar.Wait(aInterval);
mCondVar.Wait();
}

WorkerPrivate::ProcessAllControlRunnablesResult
Expand Down
2 changes: 1 addition & 1 deletion dom/workers/WorkerPrivate.h
Expand Up @@ -889,7 +889,7 @@ class WorkerPrivate : public RelativeTimeline {

void DisableMemoryReporter();

void WaitForWorkerEvents(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT);
void WaitForWorkerEvents();

void PostMessageToParentInternal(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
Expand Down
3 changes: 1 addition & 2 deletions gfx/tests/gtest/TestVsync.cpp
Expand Up @@ -45,8 +45,7 @@ class TestVsyncObserver : public VsyncObserver {

{ // scope lock
MonitorAutoLock lock(mVsyncMonitor);
PRIntervalTime timeout = PR_MillisecondsToInterval(kVsyncTimeoutMS);
lock.Wait(timeout);
lock.Wait(TimeDuration::FromMilliseconds(kVsyncTimeoutMS));
}
}

Expand Down
42 changes: 22 additions & 20 deletions image/DecodePool.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -51,15 +52,17 @@ class DecodePoolImpl {
MOZ_DECLARE_REFCOUNTED_TYPENAME(DecodePoolImpl)
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodePoolImpl)

DecodePoolImpl(uint8_t aMaxThreads, uint8_t aMaxIdleThreads,
PRIntervalTime aIdleTimeout)
: mMonitor("DecodePoolImpl"),
mThreads(aMaxThreads),
mIdleTimeout(aIdleTimeout),
mMaxIdleThreads(aMaxIdleThreads),
mAvailableThreads(aMaxThreads),
mIdleThreads(0),
mShuttingDown(false) {
DecodePoolImpl(uint8_t aMaxThreads,
uint8_t aMaxIdleThreads,
TimeDuration aIdleTimeout)
: mMonitor("DecodePoolImpl")
, mThreads(aMaxThreads)
, mIdleTimeout(aIdleTimeout)
, mMaxIdleThreads(aMaxIdleThreads)
, mAvailableThreads(aMaxThreads)
, mIdleThreads(0)
, mShuttingDown(false)
{
MonitorAutoLock lock(mMonitor);
bool success = CreateThread();
MOZ_RELEASE_ASSERT(success, "Must create first image decoder thread!");
Expand Down Expand Up @@ -159,12 +162,12 @@ class DecodePoolImpl {
return PopWorkLocked(aShutdownIdle);
}

private:
private:
/// Pops a new work item, blocking if necessary.
Work PopWorkLocked(bool aShutdownIdle) {
mMonitor.AssertCurrentThreadOwns();

PRIntervalTime timeout = mIdleTimeout;
TimeDuration timeout = mIdleTimeout;
do {
if (!mHighPriorityQueue.IsEmpty()) {
return PopWorkFromQueue(mHighPriorityQueue);
Expand All @@ -189,19 +192,19 @@ class DecodePoolImpl {
// 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;
}
}
Expand Down Expand Up @@ -237,7 +240,7 @@ class DecodePoolImpl {
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.
Expand Down Expand Up @@ -359,13 +362,12 @@ DecodePool::DecodePool() : mMutex("image::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;
}

Expand Down
24 changes: 11 additions & 13 deletions ipc/glue/GeckoChildProcessHost.cpp
Expand Up @@ -352,13 +352,12 @@ bool 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.
Expand All @@ -368,15 +367,14 @@ bool 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;
}
}
Expand Down
19 changes: 5 additions & 14 deletions ipc/glue/MessageChannel.cpp
Expand Up @@ -2167,12 +2167,6 @@ void 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) {
if (aWaitTimedOut) {
if (mInTimeoutSecondHalf) {
Expand All @@ -2198,17 +2192,14 @@ bool 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 MessageChannel::WaitForInterruptNotify() {
Expand Down

0 comments on commit 0f51907

Please sign in to comment.