• 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 #pragma once
18 
19 #include <semaphore.h>
20 #include <chrono>
21 #include <condition_variable>
22 #include <thread>
23 #include "../Clock.h"
24 
25 #include <android-base/thread_annotations.h>
26 #include <scheduler/Time.h>
27 
28 namespace android {
29 namespace scheduler {
30 
31 /*
32  * Class that sets off a timer for a given interval, and fires a callback when the
33  * interval expires.
34  */
35 class OneShotTimer {
36 public:
37     using Interval = std::chrono::milliseconds;
38     using ResetCallback = std::function<void()>;
39     using TimeoutCallback = std::function<void()>;
40 
41     OneShotTimer(std::string name, const Interval& interval, const ResetCallback& resetCallback,
42                  const TimeoutCallback& timeoutCallback,
43                  std::unique_ptr<android::Clock> clock = std::make_unique<SteadyClock>());
44     ~OneShotTimer();
45 
interval()46     Duration interval() const { return mInterval; }
47 
48     // Initializes and turns on the idle timer.
49     void start();
50     // Stops the idle timer and any held resources.
51     void stop();
52     // Resets the wakeup time and fires the reset callback.
53     void reset();
54 
55 private:
56     // Enum to track in what state is the timer.
57     enum class TimerState {
58         // The internal timer thread has been destroyed, and no state is
59         // tracked.
60         // Possible state transitions: RESET
61         STOPPED = 0,
62         // An external thread has just reset this timer.
63         // If there is a reset callback, then that callback is fired.
64         // Possible state transitions: STOPPED, WAITING
65         RESET = 1,
66         // This timer is waiting for the timeout interval to expire.
67         // Possible state transaitions: STOPPED, RESET, IDLE
68         WAITING = 2,
69         // The timeout interval has expired, so we are sleeping now.
70         // Possible state transaitions: STOPPED, RESET
71         IDLE = 3
72     };
73 
74     // Function that loops until the condition for stopping is met.
75     void loop();
76 
77     // Checks whether mResetTriggered and mStopTriggered were set and updates
78     // mState if so.
79     TimerState checkForResetAndStop(TimerState state);
80 
81     // Thread waiting for timer to expire.
82     std::thread mThread;
83 
84     // Clock object for the timer. Mocked in unit tests.
85     std::unique_ptr<android::Clock> mClock;
86 
87     // Semaphore to keep mThread synchronized.
88     sem_t mSemaphore;
89 
90     // Timer's name.
91     std::string mName;
92 
93     // Interval after which timer expires.
94     const Interval mInterval;
95 
96     // Callback that happens when timer resets.
97     const ResetCallback mResetCallback;
98 
99     // Callback that happens when timer expires.
100     const TimeoutCallback mTimeoutCallback;
101 
102     // After removing lock guarding mState, the state can be now accessed at
103     // any time. Keep a bool if the reset or stop were requested, and occasionally
104     // check in the main loop if they were.
105     std::atomic<bool> mResetTriggered = false;
106     std::atomic<bool> mStopTriggered = false;
107     std::atomic<bool> mWaiting = false;
108     std::atomic<std::chrono::steady_clock::time_point> mLastResetTime;
109 };
110 
111 } // namespace scheduler
112 } // namespace android
113