diff options
Diffstat (limited to 'services/surfaceflinger/Scheduler/OneShotTimer.cpp')
-rw-r--r-- | services/surfaceflinger/Scheduler/OneShotTimer.cpp | 148 |
1 files changed, 47 insertions, 101 deletions
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp index 16f041ae31..a90d05e17c 100644 --- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp +++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp @@ -15,152 +15,98 @@ */ #include "OneShotTimer.h" -#include <utils/Log.h> -#include <utils/Timers.h> + #include <chrono> #include <sstream> #include <thread> -namespace { -using namespace std::chrono_literals; - -constexpr int64_t kNsToSeconds = std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count(); - -// The syscall interface uses a pair of integers for the timestamp. The first -// (tv_sec) is the whole count of seconds. The second (tv_nsec) is the -// nanosecond part of the count. This function takes care of translation. -void calculateTimeoutTime(std::chrono::nanoseconds timestamp, timespec* spec) { - const nsecs_t timeout = systemTime(CLOCK_MONOTONIC) + timestamp.count(); - spec->tv_sec = static_cast<__kernel_time_t>(timeout / kNsToSeconds); - spec->tv_nsec = timeout % kNsToSeconds; -} -} // namespace - namespace android { namespace scheduler { -OneShotTimer::OneShotTimer(std::string name, const Interval& interval, - const ResetCallback& resetCallback, - const TimeoutCallback& timeoutCallback, std::unique_ptr<Clock> clock) - : mClock(std::move(clock)), - mName(std::move(name)), - mInterval(interval), - mResetCallback(resetCallback), - mTimeoutCallback(timeoutCallback) { - LOG_ALWAYS_FATAL_IF(!mClock, "Clock must not be provided"); -} +OneShotTimer::OneShotTimer(const Interval& interval, const ResetCallback& resetCallback, + const TimeoutCallback& timeoutCallback) + : mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {} OneShotTimer::~OneShotTimer() { stop(); } void OneShotTimer::start() { - int result = sem_init(&mSemaphore, 0, 0); - LOG_ALWAYS_FATAL_IF(result, "sem_init failed"); - - if (!mThread.joinable()) { - // Only create thread if it has not been created. - mThread = std::thread(&OneShotTimer::loop, this); + { + std::lock_guard<std::mutex> lock(mMutex); + mState = TimerState::RESET; } + mThread = std::thread(&OneShotTimer::loop, this); } void OneShotTimer::stop() { - mStopTriggered = true; - int result = sem_post(&mSemaphore); - LOG_ALWAYS_FATAL_IF(result, "sem_post failed"); - + { + std::lock_guard<std::mutex> lock(mMutex); + mState = TimerState::STOPPED; + } + mCondition.notify_all(); if (mThread.joinable()) { mThread.join(); - result = sem_destroy(&mSemaphore); - LOG_ALWAYS_FATAL_IF(result, "sem_destroy failed"); } } void OneShotTimer::loop() { - if (pthread_setname_np(pthread_self(), mName.c_str())) { - ALOGW("Failed to set thread name on dispatch thread"); - } - - TimerState state = TimerState::RESET; while (true) { bool triggerReset = false; bool triggerTimeout = false; + { + std::lock_guard<std::mutex> lock(mMutex); + if (mState == TimerState::STOPPED) { + break; + } - state = checkForResetAndStop(state); - if (state == TimerState::STOPPED) { - break; - } - - if (state == TimerState::IDLE) { - int result = sem_wait(&mSemaphore); - if (result && errno != EINTR) { - std::stringstream ss; - ss << "sem_wait failed (" << errno << ")"; - LOG_ALWAYS_FATAL("%s", ss.str().c_str()); + if (mState == TimerState::IDLE) { + mCondition.wait(mMutex); + continue; } - continue; - } - if (state == TimerState::RESET) { - triggerReset = true; + if (mState == TimerState::RESET) { + triggerReset = true; + } } - if (triggerReset && mResetCallback) { mResetCallback(); } - state = checkForResetAndStop(state); - if (state == TimerState::STOPPED) { - break; - } - - auto triggerTime = mClock->now() + mInterval; - state = TimerState::WAITING; - while (state == TimerState::WAITING) { - constexpr auto zero = std::chrono::steady_clock::duration::zero(); - // Wait for mInterval time for semaphore signal. - struct timespec ts; - calculateTimeoutTime(std::chrono::nanoseconds(mInterval), &ts); - int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts); - if (result && errno != ETIMEDOUT && errno != EINTR) { - std::stringstream ss; - ss << "sem_clockwait failed (" << errno << ")"; - LOG_ALWAYS_FATAL("%s", ss.str().c_str()); + { // lock the mutex again. someone might have called stop meanwhile + std::lock_guard<std::mutex> lock(mMutex); + if (mState == TimerState::STOPPED) { + break; } - state = checkForResetAndStop(state); - if (state == TimerState::RESET) { - triggerTime = mClock->now() + mInterval; - state = TimerState::WAITING; - } else if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= zero) { - triggerTimeout = true; - state = TimerState::IDLE; + auto triggerTime = std::chrono::steady_clock::now() + mInterval; + mState = TimerState::WAITING; + while (mState == TimerState::WAITING) { + constexpr auto zero = std::chrono::steady_clock::duration::zero(); + auto waitTime = triggerTime - std::chrono::steady_clock::now(); + if (waitTime > zero) mCondition.wait_for(mMutex, waitTime); + if (mState == TimerState::RESET) { + triggerTime = std::chrono::steady_clock::now() + mInterval; + mState = TimerState::WAITING; + } else if (mState == TimerState::WAITING && + (triggerTime - std::chrono::steady_clock::now()) <= zero) { + triggerTimeout = true; + mState = TimerState::IDLE; + } } } - if (triggerTimeout && mTimeoutCallback) { mTimeoutCallback(); } } } -OneShotTimer::TimerState OneShotTimer::checkForResetAndStop(TimerState state) { - // Stop takes precedence of the reset. - if (mStopTriggered.exchange(false)) { - return TimerState::STOPPED; - } - // If the state was stopped, the thread was joined, and we cannot reset - // the timer anymore. - if (state != TimerState::STOPPED && mResetTriggered.exchange(false)) { - return TimerState::RESET; - } - return state; -} - void OneShotTimer::reset() { - mResetTriggered = true; - int result = sem_post(&mSemaphore); - LOG_ALWAYS_FATAL_IF(result, "sem_post failed"); + { + std::lock_guard<std::mutex> lock(mMutex); + mState = TimerState::RESET; + } + mCondition.notify_all(); } std::string OneShotTimer::dump() const { |