Loading services/surfaceflinger/Scheduler/OneShotTimer.cpp +23 −8 Original line number Original line Diff line number Diff line Loading @@ -47,6 +47,7 @@ OneShotTimer::OneShotTimer(std::string name, const Interval& interval, mInterval(interval), mInterval(interval), mResetCallback(resetCallback), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) { mTimeoutCallback(timeoutCallback) { mLastResetTime = std::chrono::steady_clock::time_point::min(); LOG_ALWAYS_FATAL_IF(!mClock, "Clock must not be provided"); LOG_ALWAYS_FATAL_IF(!mClock, "Clock must not be provided"); } } Loading Loading @@ -116,9 +117,10 @@ void OneShotTimer::loop() { auto triggerTime = mClock->now() + mInterval; auto triggerTime = mClock->now() + mInterval; state = TimerState::WAITING; state = TimerState::WAITING; while (state == TimerState::WAITING) { while (true) { mWaiting = true; constexpr auto zero = std::chrono::steady_clock::duration::zero(); constexpr auto zero = std::chrono::steady_clock::duration::zero(); // Wait for mInterval time for semaphore signal. // Wait for mInterval time to check if we need to reset or drop into the idle state. struct timespec ts; struct timespec ts; calculateTimeoutTime(std::chrono::nanoseconds(mInterval), &ts); calculateTimeoutTime(std::chrono::nanoseconds(mInterval), &ts); int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts); int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts); Loading @@ -128,13 +130,21 @@ void OneShotTimer::loop() { LOG_ALWAYS_FATAL("%s", ss.str().c_str()); LOG_ALWAYS_FATAL("%s", ss.str().c_str()); } } mWaiting = false; state = checkForResetAndStop(state); state = checkForResetAndStop(state); if (state == TimerState::RESET) { if (state == TimerState::STOPPED) { triggerTime = mClock->now() + mInterval; break; state = TimerState::WAITING; } } else if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= zero) { if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= zero) { triggerTimeout = true; triggerTimeout = true; state = TimerState::IDLE; state = TimerState::IDLE; break; } if (state == TimerState::RESET) { triggerTime = mLastResetTime.load() + mInterval; state = TimerState::WAITING; } } } } Loading @@ -158,9 +168,14 @@ OneShotTimer::TimerState OneShotTimer::checkForResetAndStop(TimerState state) { } } void OneShotTimer::reset() { void OneShotTimer::reset() { mLastResetTime = mClock->now(); mResetTriggered = true; mResetTriggered = true; int result = sem_post(&mSemaphore); // If mWaiting is true, then we are guaranteed to be in a block where we are waiting on LOG_ALWAYS_FATAL_IF(result, "sem_post failed"); // mSemaphore for a timeout, rather than idling. So we can avoid a sem_post call since we can // just check that we triggered a reset on timeout. if (!mWaiting) { LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed"); } } } std::string OneShotTimer::dump() const { std::string OneShotTimer::dump() const { Loading services/surfaceflinger/Scheduler/OneShotTimer.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -103,6 +103,8 @@ private: // check in the main loop if they were. // check in the main loop if they were. std::atomic<bool> mResetTriggered = false; std::atomic<bool> mResetTriggered = false; std::atomic<bool> mStopTriggered = false; std::atomic<bool> mStopTriggered = false; std::atomic<bool> mWaiting = false; std::atomic<std::chrono::steady_clock::time_point> mLastResetTime; }; }; } // namespace scheduler } // namespace scheduler Loading Loading
services/surfaceflinger/Scheduler/OneShotTimer.cpp +23 −8 Original line number Original line Diff line number Diff line Loading @@ -47,6 +47,7 @@ OneShotTimer::OneShotTimer(std::string name, const Interval& interval, mInterval(interval), mInterval(interval), mResetCallback(resetCallback), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) { mTimeoutCallback(timeoutCallback) { mLastResetTime = std::chrono::steady_clock::time_point::min(); LOG_ALWAYS_FATAL_IF(!mClock, "Clock must not be provided"); LOG_ALWAYS_FATAL_IF(!mClock, "Clock must not be provided"); } } Loading Loading @@ -116,9 +117,10 @@ void OneShotTimer::loop() { auto triggerTime = mClock->now() + mInterval; auto triggerTime = mClock->now() + mInterval; state = TimerState::WAITING; state = TimerState::WAITING; while (state == TimerState::WAITING) { while (true) { mWaiting = true; constexpr auto zero = std::chrono::steady_clock::duration::zero(); constexpr auto zero = std::chrono::steady_clock::duration::zero(); // Wait for mInterval time for semaphore signal. // Wait for mInterval time to check if we need to reset or drop into the idle state. struct timespec ts; struct timespec ts; calculateTimeoutTime(std::chrono::nanoseconds(mInterval), &ts); calculateTimeoutTime(std::chrono::nanoseconds(mInterval), &ts); int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts); int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts); Loading @@ -128,13 +130,21 @@ void OneShotTimer::loop() { LOG_ALWAYS_FATAL("%s", ss.str().c_str()); LOG_ALWAYS_FATAL("%s", ss.str().c_str()); } } mWaiting = false; state = checkForResetAndStop(state); state = checkForResetAndStop(state); if (state == TimerState::RESET) { if (state == TimerState::STOPPED) { triggerTime = mClock->now() + mInterval; break; state = TimerState::WAITING; } } else if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= zero) { if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= zero) { triggerTimeout = true; triggerTimeout = true; state = TimerState::IDLE; state = TimerState::IDLE; break; } if (state == TimerState::RESET) { triggerTime = mLastResetTime.load() + mInterval; state = TimerState::WAITING; } } } } Loading @@ -158,9 +168,14 @@ OneShotTimer::TimerState OneShotTimer::checkForResetAndStop(TimerState state) { } } void OneShotTimer::reset() { void OneShotTimer::reset() { mLastResetTime = mClock->now(); mResetTriggered = true; mResetTriggered = true; int result = sem_post(&mSemaphore); // If mWaiting is true, then we are guaranteed to be in a block where we are waiting on LOG_ALWAYS_FATAL_IF(result, "sem_post failed"); // mSemaphore for a timeout, rather than idling. So we can avoid a sem_post call since we can // just check that we triggered a reset on timeout. if (!mWaiting) { LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed"); } } } std::string OneShotTimer::dump() const { std::string OneShotTimer::dump() const { Loading
services/surfaceflinger/Scheduler/OneShotTimer.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -103,6 +103,8 @@ private: // check in the main loop if they were. // check in the main loop if they were. std::atomic<bool> mResetTriggered = false; std::atomic<bool> mResetTriggered = false; std::atomic<bool> mStopTriggered = false; std::atomic<bool> mStopTriggered = false; std::atomic<bool> mWaiting = false; std::atomic<std::chrono::steady_clock::time_point> mLastResetTime; }; }; } // namespace scheduler } // namespace scheduler Loading