blob: edcec99a23837b8985d4adc85801c4177e2f3c1e [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
Brian Anderson3da8d272016-07-28 16:20:47 -0700133 // Allow tests to override SIGNAL_TIME_INVALID behavior, since tests
134 // use invalid underlying Fences without real file descriptors.
135 if (CC_UNLIKELY(mState == State::FORCED_VALID_FOR_TEST)) {
136 if (signalTime == Fence::SIGNAL_TIME_INVALID) {
137 signalTime = Fence::SIGNAL_TIME_PENDING;
138 }
139 }
140
Brian Anderson221de2a2016-09-21 16:53:28 -0700141 // Make the signal time visible to everyone if it is no longer pending
142 // and remove the class' reference to the fence.
143 if (signalTime != Fence::SIGNAL_TIME_PENDING) {
144 std::lock_guard<std::mutex> lock(mMutex);
145 mFence.clear();
146 mSignalTime.store(signalTime, std::memory_order_relaxed);
147 }
148
149 return signalTime;
150}
151
152nsecs_t FenceTime::getCachedSignalTime() const {
153 // memory_order_acquire since we don't have a lock fallback path
154 // that will do an acquire.
155 return mSignalTime.load(std::memory_order_acquire);
156}
157
158FenceTime::Snapshot FenceTime::getSnapshot() const {
159 // Quick check without the lock.
160 nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed);
161 if (signalTime != Fence::SIGNAL_TIME_PENDING) {
162 return Snapshot(signalTime);
163 }
164
165 // Do the full check with the lock.
166 std::lock_guard<std::mutex> lock(mMutex);
167 signalTime = mSignalTime.load(std::memory_order_relaxed);
168 if (signalTime != Fence::SIGNAL_TIME_PENDING) {
169 return Snapshot(signalTime);
170 }
171 return Snapshot(mFence);
172}
173
Brian Anderson3da8d272016-07-28 16:20:47 -0700174// For tests only. If forceValidForTest is true, then getSignalTime will
175// never return SIGNAL_TIME_INVALID and isValid will always return true.
176FenceTime::FenceTime(const sp<Fence>& fence, bool forceValidForTest)
177 : mState(forceValidForTest ?
178 State::FORCED_VALID_FOR_TEST : State::INVALID),
179 mFence(fence),
180 mSignalTime(mState == State::INVALID ?
181 Fence::SIGNAL_TIME_INVALID : Fence::SIGNAL_TIME_PENDING) {
182}
183
184void FenceTime::signalForTest(nsecs_t signalTime) {
185 // To be realistic, this should really set a hidden value that
186 // gets picked up in the next call to getSignalTime, but this should
187 // be good enough.
188 std::lock_guard<std::mutex> lock(mMutex);
189 mFence.clear();
190 mSignalTime.store(signalTime, std::memory_order_relaxed);
191}
192
Brian Anderson221de2a2016-09-21 16:53:28 -0700193// ============================================================================
194// FenceTime::Snapshot
195// ============================================================================
Brian Anderson221de2a2016-09-21 16:53:28 -0700196FenceTime::Snapshot::Snapshot(const sp<Fence>& srcFence)
197 : state(State::FENCE), fence(srcFence) {
198}
199
200FenceTime::Snapshot::Snapshot(nsecs_t srcSignalTime)
201 : state(State::SIGNAL_TIME), signalTime(srcSignalTime) {
202}
203
204size_t FenceTime::Snapshot::getFlattenedSize() const {
205 constexpr size_t min = sizeof(state);
206 switch (state) {
207 case State::EMPTY:
208 return min;
209 case State::FENCE:
210 return min + fence->getFlattenedSize();
211 case State::SIGNAL_TIME:
212 return min + sizeof(signalTime);
213 }
214 return 0;
215}
216
217size_t FenceTime::Snapshot::getFdCount() const {
218 return state == State::FENCE ? fence->getFdCount() : 0u;
219}
220
221status_t FenceTime::Snapshot::flatten(
222 void*& buffer, size_t& size, int*& fds, size_t& count) const {
223 if (size < getFlattenedSize()) {
224 return NO_MEMORY;
225 }
226
227 FlattenableUtils::write(buffer, size, state);
228 switch (state) {
229 case State::EMPTY:
230 return NO_ERROR;
231 case State::FENCE:
232 return fence->flatten(buffer, size, fds, count);
233 case State::SIGNAL_TIME:
234 FlattenableUtils::write(buffer, size, signalTime);
235 return NO_ERROR;
236 }
237
238 return NO_ERROR;
239}
240
241status_t FenceTime::Snapshot::unflatten(
242 void const*& buffer, size_t& size, int const*& fds, size_t& count) {
243 if (size < sizeof(state)) {
244 return NO_MEMORY;
245 }
246
247 FlattenableUtils::read(buffer, size, state);
248 switch (state) {
249 case State::EMPTY:
250 return NO_ERROR;
251 case State::FENCE:
252 fence = new Fence;
253 return fence->unflatten(buffer, size, fds, count);
254 case State::SIGNAL_TIME:
255 if (size < sizeof(signalTime)) {
256 return NO_MEMORY;
257 }
258 FlattenableUtils::read(buffer, size, signalTime);
259 return NO_ERROR;
260 }
261
262 return NO_ERROR;
263}
264
265// ============================================================================
266// FenceTimeline
267// ============================================================================
268void FenceTimeline::push(const std::shared_ptr<FenceTime>& fence) {
269 std::lock_guard<std::mutex> lock(mMutex);
270 while (mQueue.size() >= MAX_ENTRIES) {
271 // This is a sanity check to make sure the queue doesn't grow unbounded.
272 // MAX_ENTRIES should be big enough not to trigger this path.
273 // In case this path is taken though, users of FenceTime must make sure
274 // not to rely solely on FenceTimeline to get the final timestamp and
275 // should eventually call Fence::getSignalTime on their own.
276 std::shared_ptr<FenceTime> front = mQueue.front().lock();
277 if (front) {
278 // Make a last ditch effort to get the signalTime here since
279 // we are removing it from the timeline.
280 front->getSignalTime();
281 }
282 mQueue.pop();
283 }
284 mQueue.push(fence);
285}
286
287void FenceTimeline::updateSignalTimes() {
288 while (!mQueue.empty()) {
289 std::lock_guard<std::mutex> lock(mMutex);
290 std::shared_ptr<FenceTime> fence = mQueue.front().lock();
291 if (!fence) {
292 // The shared_ptr no longer exists and no one cares about the
293 // timestamp anymore.
294 mQueue.pop();
295 continue;
296 } else if (fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) {
297 // The fence has signaled and we've removed the sp<Fence> ref.
298 mQueue.pop();
299 continue;
300 } else {
301 // The fence didn't signal yet. Break since the later ones
302 // shouldn't have signaled either.
303 break;
304 }
305 }
306}
307
Brian Anderson3da8d272016-07-28 16:20:47 -0700308// ============================================================================
309// FenceToFenceTimeMap
310// ============================================================================
311std::shared_ptr<FenceTime> FenceToFenceTimeMap::createFenceTimeForTest(
312 const sp<Fence>& fence) {
313 std::lock_guard<std::mutex> lock(mMutex);
314 // Always garbage collecting isn't efficient, but this is only for testing.
315 garbageCollectLocked();
316 std::shared_ptr<FenceTime> fenceTime(new FenceTime(fence, true));
317 mMap[fence.get()].push_back(fenceTime);
318 return fenceTime;
319}
320
321void FenceToFenceTimeMap::signalAllForTest(
322 const sp<Fence>& fence, nsecs_t signalTime) {
323 bool signaled = false;
324
325 std::lock_guard<std::mutex> lock(mMutex);
326 auto it = mMap.find(fence.get());
327 if (it != mMap.end()) {
328 for (auto& weakFenceTime : it->second) {
329 std::shared_ptr<FenceTime> fenceTime = weakFenceTime.lock();
330 if (!fenceTime) {
331 continue;
332 }
333 ALOGE_IF(!fenceTime->isValid(),
334 "FenceToFenceTimeMap::signalAllForTest: "
335 "Signaling invalid fence.");
336 fenceTime->signalForTest(signalTime);
337 signaled = true;
338 }
339 }
340
341 if (!signaled) {
342 ALOGE("FenceToFenceTimeMap::signalAllForTest: Nothing to signal.");
343 }
344}
345
346void FenceToFenceTimeMap::garbageCollectLocked() {
347 for (auto& it : mMap) {
348 // Erase all expired weak pointers from the vector.
349 auto& vect = it.second;
350 vect.erase(
351 std::remove_if(vect.begin(), vect.end(),
352 [](const std::weak_ptr<FenceTime>& ft) {
353 return ft.expired();
354 }),
355 vect.end());
356
357 // Also erase the map entry if the vector is now empty.
358 if (vect.empty()) {
359 mMap.erase(it.first);
360 }
361 }
362}
363
Brian Anderson221de2a2016-09-21 16:53:28 -0700364} // namespace android