blob: c0245ebb89674a972a1a6490a8d83d15a0c06567 [file] [log] [blame]
Brian Anderson221de2a2016-09-21 16:53:28 -07001/*
2* Copyright 2016 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 <ui/FenceTime.h>
18
19#include <cutils/compiler.h> // For CC_[UN]LIKELY
20#include <inttypes.h>
21#include <stdlib.h>
22
23#include <memory>
24
25namespace android {
26
27// ============================================================================
28// FenceTime
29// ============================================================================
30
31const auto FenceTime::NO_FENCE = std::make_shared<FenceTime>(Fence::NO_FENCE);
32
33void* FenceTime::operator new(size_t byteCount) noexcept {
34 void *p = nullptr;
35 if (posix_memalign(&p, alignof(FenceTime), byteCount)) {
36 return nullptr;
37 }
38 return p;
39}
40
41void FenceTime::operator delete(void *p) {
42 free(p);
43}
44
45FenceTime::FenceTime(const sp<Fence>& fence)
46 : mState(((fence.get() != nullptr) && fence->isValid()) ?
47 State::VALID : State::INVALID),
48 mFence(fence),
49 mSignalTime(mState == State::INVALID ?
50 Fence::SIGNAL_TIME_INVALID : Fence::SIGNAL_TIME_PENDING) {
51}
52
53FenceTime::FenceTime(sp<Fence>&& fence)
54 : mState(((fence.get() != nullptr) && fence->isValid()) ?
55 State::VALID : State::INVALID),
56 mFence(std::move(fence)),
57 mSignalTime(mState == State::INVALID ?
58 Fence::SIGNAL_TIME_INVALID : Fence::SIGNAL_TIME_PENDING) {
59}
60
61FenceTime::FenceTime(nsecs_t signalTime)
62 : mState(Fence::isValidTimestamp(signalTime) ? State::VALID : State::INVALID),
63 mFence(nullptr),
64 mSignalTime(signalTime == Fence::SIGNAL_TIME_PENDING ?
65 Fence::SIGNAL_TIME_INVALID : signalTime) {
66}
67
68void FenceTime::applyTrustedSnapshot(const Snapshot& src) {
69 if (CC_UNLIKELY(src.state != Snapshot::State::SIGNAL_TIME)) {
70 // Applying Snapshot::State::FENCE, could change the valid state of the
71 // FenceTime, which is not allowed. Callers should create a new
72 // FenceTime from the snapshot instead.
73 ALOGE("FenceTime::applyTrustedSnapshot: Unexpected fence.");
74 return;
75 }
76
77 if (src.state == Snapshot::State::EMPTY) {
78 return;
79 }
80
81 nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed);
82 if (signalTime != Fence::SIGNAL_TIME_PENDING) {
83 // We should always get the same signalTime here that we did in
84 // getSignalTime(). This check races with getSignalTime(), but it is
85 // only a sanity check so that's okay.
86 if (CC_UNLIKELY(signalTime != src.signalTime)) {
87 ALOGE("FenceTime::applyTrustedSnapshot: signalTime mismatch. "
88 "(%" PRId64 " (old) != %" PRId64 " (new))",
89 signalTime, src.signalTime);
90 }
91 return;
92 }
93
94 std::lock_guard<std::mutex> lock(mMutex);
95 mFence.clear();
96 mSignalTime.store(src.signalTime, std::memory_order_relaxed);
97}
98
99bool FenceTime::isValid() const {
100 // We store the valid state in the constructors and return it here.
101 // This lets release code remember the valid state even after the
102 // underlying fence is destroyed.
103 return mState != State::INVALID;
104}
105
106nsecs_t FenceTime::getSignalTime() {
107 // See if we already have a cached value we can return.
108 nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed);
109 if (signalTime != Fence::SIGNAL_TIME_PENDING) {
110 return signalTime;
111 }
112
113 // Hold a reference to the fence on the stack in case the class'
114 // reference is removed by another thread. This prevents the
115 // fence from being destroyed until the end of this method, where
116 // we conveniently do not have the lock held.
117 sp<Fence> fence;
118 {
119 // With the lock acquired this time, see if we have the cached
120 // value or if we need to poll the fence.
121 std::lock_guard<std::mutex> lock(mMutex);
122 if (!mFence.get()) {
123 // Another thread set the signal time just before we added the
124 // reference to mFence.
125 return mSignalTime.load(std::memory_order_relaxed);
126 }
127 fence = mFence;
128 }
129
130 // Make the system call without the lock held.
131 signalTime = fence->getSignalTime();
132
133 // Make the signal time visible to everyone if it is no longer pending
134 // and remove the class' reference to the fence.
135 if (signalTime != Fence::SIGNAL_TIME_PENDING) {
136 std::lock_guard<std::mutex> lock(mMutex);
137 mFence.clear();
138 mSignalTime.store(signalTime, std::memory_order_relaxed);
139 }
140
141 return signalTime;
142}
143
144nsecs_t FenceTime::getCachedSignalTime() const {
145 // memory_order_acquire since we don't have a lock fallback path
146 // that will do an acquire.
147 return mSignalTime.load(std::memory_order_acquire);
148}
149
150FenceTime::Snapshot FenceTime::getSnapshot() const {
151 // Quick check without the lock.
152 nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed);
153 if (signalTime != Fence::SIGNAL_TIME_PENDING) {
154 return Snapshot(signalTime);
155 }
156
157 // Do the full check with the lock.
158 std::lock_guard<std::mutex> lock(mMutex);
159 signalTime = mSignalTime.load(std::memory_order_relaxed);
160 if (signalTime != Fence::SIGNAL_TIME_PENDING) {
161 return Snapshot(signalTime);
162 }
163 return Snapshot(mFence);
164}
165
166// ============================================================================
167// FenceTime::Snapshot
168// ============================================================================
169
170FenceTime::Snapshot::Snapshot(const sp<Fence>& srcFence)
171 : state(State::FENCE), fence(srcFence) {
172}
173
174FenceTime::Snapshot::Snapshot(nsecs_t srcSignalTime)
175 : state(State::SIGNAL_TIME), signalTime(srcSignalTime) {
176}
177
178size_t FenceTime::Snapshot::getFlattenedSize() const {
179 constexpr size_t min = sizeof(state);
180 switch (state) {
181 case State::EMPTY:
182 return min;
183 case State::FENCE:
184 return min + fence->getFlattenedSize();
185 case State::SIGNAL_TIME:
186 return min + sizeof(signalTime);
187 }
188 return 0;
189}
190
191size_t FenceTime::Snapshot::getFdCount() const {
192 return state == State::FENCE ? fence->getFdCount() : 0u;
193}
194
195status_t FenceTime::Snapshot::flatten(
196 void*& buffer, size_t& size, int*& fds, size_t& count) const {
197 if (size < getFlattenedSize()) {
198 return NO_MEMORY;
199 }
200
201 FlattenableUtils::write(buffer, size, state);
202 switch (state) {
203 case State::EMPTY:
204 return NO_ERROR;
205 case State::FENCE:
206 return fence->flatten(buffer, size, fds, count);
207 case State::SIGNAL_TIME:
208 FlattenableUtils::write(buffer, size, signalTime);
209 return NO_ERROR;
210 }
211
212 return NO_ERROR;
213}
214
215status_t FenceTime::Snapshot::unflatten(
216 void const*& buffer, size_t& size, int const*& fds, size_t& count) {
217 if (size < sizeof(state)) {
218 return NO_MEMORY;
219 }
220
221 FlattenableUtils::read(buffer, size, state);
222 switch (state) {
223 case State::EMPTY:
224 return NO_ERROR;
225 case State::FENCE:
226 fence = new Fence;
227 return fence->unflatten(buffer, size, fds, count);
228 case State::SIGNAL_TIME:
229 if (size < sizeof(signalTime)) {
230 return NO_MEMORY;
231 }
232 FlattenableUtils::read(buffer, size, signalTime);
233 return NO_ERROR;
234 }
235
236 return NO_ERROR;
237}
238
239// ============================================================================
240// FenceTimeline
241// ============================================================================
242void FenceTimeline::push(const std::shared_ptr<FenceTime>& fence) {
243 std::lock_guard<std::mutex> lock(mMutex);
244 while (mQueue.size() >= MAX_ENTRIES) {
245 // This is a sanity check to make sure the queue doesn't grow unbounded.
246 // MAX_ENTRIES should be big enough not to trigger this path.
247 // In case this path is taken though, users of FenceTime must make sure
248 // not to rely solely on FenceTimeline to get the final timestamp and
249 // should eventually call Fence::getSignalTime on their own.
250 std::shared_ptr<FenceTime> front = mQueue.front().lock();
251 if (front) {
252 // Make a last ditch effort to get the signalTime here since
253 // we are removing it from the timeline.
254 front->getSignalTime();
255 }
256 mQueue.pop();
257 }
258 mQueue.push(fence);
259}
260
261void FenceTimeline::updateSignalTimes() {
262 while (!mQueue.empty()) {
263 std::lock_guard<std::mutex> lock(mMutex);
264 std::shared_ptr<FenceTime> fence = mQueue.front().lock();
265 if (!fence) {
266 // The shared_ptr no longer exists and no one cares about the
267 // timestamp anymore.
268 mQueue.pop();
269 continue;
270 } else if (fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) {
271 // The fence has signaled and we've removed the sp<Fence> ref.
272 mQueue.pop();
273 continue;
274 } else {
275 // The fence didn't signal yet. Break since the later ones
276 // shouldn't have signaled either.
277 break;
278 }
279 }
280}
281
282} // namespace android