1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "IdleTimer.h" 18 19 #include <chrono> 20 #include <thread> 21 22 namespace android { 23 namespace scheduler { 24 25 IdleTimer::IdleTimer(const Interval& interval, const ResetCallback& resetCallback, 26 const TimeoutCallback& timeoutCallback) 27 : mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {} 28 29 IdleTimer::~IdleTimer() { 30 stop(); 31 } 32 33 void IdleTimer::start() { 34 { 35 std::lock_guard<std::mutex> lock(mMutex); 36 mState = TimerState::RESET; 37 } 38 mThread = std::thread(&IdleTimer::loop, this); 39 } 40 41 void IdleTimer::stop() { 42 { 43 std::lock_guard<std::mutex> lock(mMutex); 44 mState = TimerState::STOPPED; 45 } 46 mCondition.notify_all(); 47 if (mThread.joinable()) { 48 mThread.join(); 49 } 50 } 51 52 void IdleTimer::loop() { 53 while (true) { 54 bool triggerReset = false; 55 bool triggerTimeout = false; 56 { 57 std::lock_guard<std::mutex> lock(mMutex); 58 if (mState == TimerState::STOPPED) { 59 break; 60 } 61 62 if (mState == TimerState::IDLE) { 63 mCondition.wait(mMutex); 64 continue; 65 } 66 67 if (mState == TimerState::RESET) { 68 triggerReset = true; 69 } 70 } 71 if (triggerReset && mResetCallback) { 72 mResetCallback(); 73 } 74 75 { // lock the mutex again. someone might have called stop meanwhile 76 std::lock_guard<std::mutex> lock(mMutex); 77 if (mState == TimerState::STOPPED) { 78 break; 79 } 80 81 auto triggerTime = std::chrono::steady_clock::now() + mInterval; 82 mState = TimerState::WAITING; 83 while (mState == TimerState::WAITING) { 84 constexpr auto zero = std::chrono::steady_clock::duration::zero(); 85 auto waitTime = triggerTime - std::chrono::steady_clock::now(); 86 if (waitTime > zero) mCondition.wait_for(mMutex, waitTime); 87 if (mState == TimerState::RESET) { 88 triggerTime = std::chrono::steady_clock::now() + mInterval; 89 mState = TimerState::WAITING; 90 } else if (mState == TimerState::WAITING && 91 (triggerTime - std::chrono::steady_clock::now()) <= zero) { 92 triggerTimeout = true; 93 mState = TimerState::IDLE; 94 } 95 } 96 } 97 if (triggerTimeout && mTimeoutCallback) { 98 mTimeoutCallback(); 99 } 100 } 101 } // namespace scheduler 102 103 void IdleTimer::reset() { 104 { 105 std::lock_guard<std::mutex> lock(mMutex); 106 mState = TimerState::RESET; 107 } 108 mCondition.notify_all(); 109 } 110 111 } // namespace scheduler 112 } // namespace android 113