summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/Scheduler/OneShotTimer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger/Scheduler/OneShotTimer.cpp')
-rw-r--r--services/surfaceflinger/Scheduler/OneShotTimer.cpp148
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 {