blob: fc78da3977d94d59816595f550459d58aba736e7 [file] [log] [blame]
Kevin DuBoise4f27a82019-11-12 11:41:41 -08001/*
2 * Copyright 2019 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 <android-base/thread_annotations.h>
20#include <functional>
21#include <memory>
22#include <mutex>
23#include <string>
24#include <string_view>
25#include <unordered_map>
26
27#include "VSyncDispatch.h"
28
29namespace android::scheduler {
30
31// VSyncDispatchTimerQueueEntry is a helper class representing internal state for each entry in
32// VSyncDispatchTimerQueue hoisted to public for unit testing.
33class VSyncDispatchTimerQueueEntry {
34public:
35 // This is the state of the entry. There are 3 states, armed, running, disarmed.
36 // Valid transition: disarmed -> armed ( when scheduled )
37 // Valid transition: armed -> running -> disarmed ( when timer is called)
38 // Valid transition: armed -> disarmed ( when cancelled )
39 VSyncDispatchTimerQueueEntry(std::string const& name, std::function<void(nsecs_t)> const& fn);
40 std::string_view name() const;
41
42 // Start: functions that are not threadsafe.
43 // Return the last vsync time this callback was invoked.
44 std::optional<nsecs_t> lastExecutedVsyncTarget() const;
45
46 // This moves the state from disarmed->armed and will calculate the wakeupTime.
Kevin DuBois2311b1a2019-11-18 16:19:08 -080047 ScheduleResult schedule(nsecs_t workDuration, nsecs_t earliestVsync, VSyncTracker& tracker,
48 nsecs_t now);
Kevin DuBoise4f27a82019-11-12 11:41:41 -080049 // This will update armed entries with the latest vsync information. Entry remains armed.
50 void update(VSyncTracker& tracker, nsecs_t now);
51
52 // This will return empty if not armed, or the next calculated wakeup time if armed.
53 // It will not update the wakeupTime.
54 std::optional<nsecs_t> wakeupTime() const;
55
56 // This moves state from armed->disarmed.
57 void disarm();
58
59 // This moves the state from armed->running.
60 // Store the timestamp that this was intended for as the last called timestamp.
61 nsecs_t executing();
62 // End: functions that are not threadsafe.
63
64 // Invoke the callback with the timestamp, moving the state from running->disarmed.
65 void callback(nsecs_t timestamp);
66 // Block calling thread while the callback is executing.
67 void ensureNotRunning();
68
69private:
Kevin DuBoise4f27a82019-11-12 11:41:41 -080070 std::string const mName;
71 std::function<void(nsecs_t)> const mCallback;
72
73 nsecs_t mWorkDuration;
74 nsecs_t mEarliestVsync;
75
76 struct ArmingInfo {
77 nsecs_t mActualWakeupTime;
78 nsecs_t mActualVsyncTime;
79 };
80 std::optional<ArmingInfo> mArmedInfo;
81 std::optional<nsecs_t> mLastDispatchTime;
82
83 std::mutex mRunningMutex;
84 std::condition_variable mCv;
85 bool mRunning GUARDED_BY(mRunningMutex) = false;
86};
87
88/*
89 * VSyncDispatchTimerQueue is a class that will dispatch callbacks as per VSyncDispatch interface
90 * using a single timer queue.
91 */
92class VSyncDispatchTimerQueue : public VSyncDispatch {
93public:
94 explicit VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk, VSyncTracker& tracker,
95 nsecs_t timerSlack);
96 ~VSyncDispatchTimerQueue();
97
98 CallbackToken registerCallback(std::function<void(nsecs_t)> const& callbackFn,
99 std::string callbackName) final;
100 void unregisterCallback(CallbackToken token) final;
101 ScheduleResult schedule(CallbackToken token, nsecs_t workDuration, nsecs_t earliestVsync) final;
102 CancelResult cancel(CallbackToken token) final;
103
104private:
105 VSyncDispatchTimerQueue(VSyncDispatchTimerQueue const&) = delete;
106 VSyncDispatchTimerQueue& operator=(VSyncDispatchTimerQueue const&) = delete;
107
Ady Abraham2139f732019-11-13 18:56:40 -0800108 using CallbackMap =
109 std::unordered_map<CallbackToken, std::shared_ptr<VSyncDispatchTimerQueueEntry>>;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800110
111 void timerCallback();
112 void setTimer(nsecs_t, nsecs_t) REQUIRES(mMutex);
113 void rearmTimer(nsecs_t now) REQUIRES(mMutex);
114 void rearmTimerSkippingUpdateFor(nsecs_t now, CallbackMap::iterator const& skipUpdate)
115 REQUIRES(mMutex);
116 void cancelTimer() REQUIRES(mMutex);
117
118 static constexpr nsecs_t kInvalidTime = std::numeric_limits<int64_t>::max();
119 std::unique_ptr<TimeKeeper> const mTimeKeeper;
120 VSyncTracker& mTracker;
121 nsecs_t const mTimerSlack;
122
123 std::mutex mutable mMutex;
124 size_t mCallbackToken GUARDED_BY(mMutex) = 0;
125
126 CallbackMap mCallbacks GUARDED_BY(mMutex);
127 nsecs_t mIntendedWakeupTime GUARDED_BY(mMutex) = kInvalidTime;
128};
129
130} // namespace android::scheduler