• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "OneShotTimer.h"
18 
19 #include <chrono>
20 #include <sstream>
21 #include <thread>
22 
23 namespace android {
24 namespace scheduler {
25 
OneShotTimer(const Interval & interval,const ResetCallback & resetCallback,const TimeoutCallback & timeoutCallback)26 OneShotTimer::OneShotTimer(const Interval& interval, const ResetCallback& resetCallback,
27                            const TimeoutCallback& timeoutCallback)
28       : mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {}
29 
~OneShotTimer()30 OneShotTimer::~OneShotTimer() {
31     stop();
32 }
33 
start()34 void OneShotTimer::start() {
35     {
36         std::lock_guard<std::mutex> lock(mMutex);
37         mState = TimerState::RESET;
38     }
39     mThread = std::thread(&OneShotTimer::loop, this);
40 }
41 
stop()42 void OneShotTimer::stop() {
43     {
44         std::lock_guard<std::mutex> lock(mMutex);
45         mState = TimerState::STOPPED;
46     }
47     mCondition.notify_all();
48     if (mThread.joinable()) {
49         mThread.join();
50     }
51 }
52 
loop()53 void OneShotTimer::loop() {
54     while (true) {
55         bool triggerReset = false;
56         bool triggerTimeout = false;
57         {
58             std::lock_guard<std::mutex> lock(mMutex);
59             if (mState == TimerState::STOPPED) {
60                 break;
61             }
62 
63             if (mState == TimerState::IDLE) {
64                 mCondition.wait(mMutex);
65                 continue;
66             }
67 
68             if (mState == TimerState::RESET) {
69                 triggerReset = true;
70             }
71         }
72         if (triggerReset && mResetCallback) {
73             mResetCallback();
74         }
75 
76         { // lock the mutex again. someone might have called stop meanwhile
77             std::lock_guard<std::mutex> lock(mMutex);
78             if (mState == TimerState::STOPPED) {
79                 break;
80             }
81 
82             auto triggerTime = std::chrono::steady_clock::now() + mInterval;
83             mState = TimerState::WAITING;
84             while (mState == TimerState::WAITING) {
85                 constexpr auto zero = std::chrono::steady_clock::duration::zero();
86                 auto waitTime = triggerTime - std::chrono::steady_clock::now();
87                 if (waitTime > zero) mCondition.wait_for(mMutex, waitTime);
88                 if (mState == TimerState::RESET) {
89                     triggerTime = std::chrono::steady_clock::now() + mInterval;
90                     mState = TimerState::WAITING;
91                 } else if (mState == TimerState::WAITING &&
92                            (triggerTime - std::chrono::steady_clock::now()) <= zero) {
93                     triggerTimeout = true;
94                     mState = TimerState::IDLE;
95                 }
96             }
97         }
98         if (triggerTimeout && mTimeoutCallback) {
99             mTimeoutCallback();
100         }
101     }
102 }
103 
reset()104 void OneShotTimer::reset() {
105     {
106         std::lock_guard<std::mutex> lock(mMutex);
107         mState = TimerState::RESET;
108     }
109     mCondition.notify_all();
110 }
111 
dump() const112 std::string OneShotTimer::dump() const {
113     std::ostringstream stream;
114     stream << mInterval.count() << " ms";
115     return stream.str();
116 }
117 
118 } // namespace scheduler
119 } // namespace android
120