blob: 8106b16009f19750892ef824be3d73050d73db4f [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
Brian Anderson175a7202016-10-10 16:52:56 -070020#include <utils/Log.h>
Brian Anderson221de2a2016-09-21 16:53:28 -070021#include <inttypes.h>
22#include <stdlib.h>
23
24#include <memory>
25
26namespace android {
27
28// ============================================================================
29// FenceTime
30// ============================================================================
31
32const auto FenceTime::NO_FENCE = std::make_shared<FenceTime>(Fence::NO_FENCE);
33
34void* FenceTime::operator new(size_t byteCount) noexcept {
35 void *p = nullptr;
36 if (posix_memalign(&p, alignof(FenceTime), byteCount)) {
37 return nullptr;
38 }
39 return p;
40}
41
42void FenceTime::operator delete(void *p) {
43 free(p);
44}
45
46FenceTime::FenceTime(const sp<Fence>& fence)
47 : mState(((fence.get() != nullptr) && fence->isValid()) ?
48 State::VALID : State::INVALID),
49 mFence(fence),
50 mSignalTime(mState == State::INVALID ?
51 Fence::SIGNAL_TIME_INVALID : Fence::SIGNAL_TIME_PENDING) {
52}
53
54FenceTime::FenceTime(sp<Fence>&& fence)
55 : mState(((fence.get() != nullptr) && fence->isValid()) ?
56 State::VALID : State::INVALID),
57 mFence(std::move(fence)),
58 mSignalTime(mState == State::INVALID ?
59 Fence::SIGNAL_TIME_INVALID : Fence::SIGNAL_TIME_PENDING) {
60}
61
62FenceTime::FenceTime(nsecs_t signalTime)
63 : mState(Fence::isValidTimestamp(signalTime) ? State::VALID : State::INVALID),
64 mFence(nullptr),
65 mSignalTime(signalTime == Fence::SIGNAL_TIME_PENDING ?
66 Fence::SIGNAL_TIME_INVALID : signalTime) {
67}
68
69void FenceTime::applyTrustedSnapshot(const Snapshot& src) {
70 if (CC_UNLIKELY(src.state != Snapshot::State::SIGNAL_TIME)) {
71 // Applying Snapshot::State::FENCE, could change the valid state of the
72 // FenceTime, which is not allowed. Callers should create a new
73 // FenceTime from the snapshot instead.
74 ALOGE("FenceTime::applyTrustedSnapshot: Unexpected fence.");
75 return;
76 }
77
78 if (src.state == Snapshot::State::EMPTY) {
79 return;
80 }
81
82 nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed);
83 if (signalTime != Fence::SIGNAL_TIME_PENDING) {
84 // We should always get the same signalTime here that we did in
85 // getSignalTime(). This check races with getSignalTime(), but it is
86 // only a sanity check so that's okay.
87 if (CC_UNLIKELY(signalTime != src.signalTime)) {
88 ALOGE("FenceTime::applyTrustedSnapshot: signalTime mismatch. "
89 "(%" PRId64 " (old) != %" PRId64 " (new))",
90 signalTime, src.signalTime);
91 }
92 return;
93 }
94
95 std::lock_guard<std::mutex> lock(mMutex);
96 mFence.clear();
97 mSignalTime.store(src.signalTime, std::memory_order_relaxed);
98}
99
100bool FenceTime::isValid() const {
101 // We store the valid state in the constructors and return it here.
102 // This lets release code remember the valid state even after the
103 // underlying fence is destroyed.
104 return mState != State::INVALID;
105}
106
107nsecs_t FenceTime::getSignalTime() {
108 // See if we already have a cached value we can return.
109 nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed);
110 if (signalTime != Fence::SIGNAL_TIME_PENDING) {
111 return signalTime;
112 }
113
114 // Hold a reference to the fence on the stack in case the class'
115 // reference is removed by another thread. This prevents the
116 // fence from being destroyed until the end of this method, where
117 // we conveniently do not have the lock held.
118 sp<Fence> fence;
119 {
120 // With the lock acquired this time, see if we have the cached
121 // value or if we need to poll the fence.
122 std::lock_guard<std::mutex> lock(mMutex);
123 if (!mFence.get()) {
124 // Another thread set the signal time just before we added the
125 // reference to mFence.
126 return mSignalTime.load(std::memory_order_relaxed);
127 }
128 fence = mFence;
129 }
130
131 // Make the system call without the lock held.
132 signalTime = fence->getSignalTime();
133
Brian Anderson3da8d272016-07-28 16:20:47 -0700134 // Allow tests to override SIGNAL_TIME_INVALID behavior, since tests
135 // use invalid underlying Fences without real file descriptors.
136 if (CC_UNLIKELY(mState == State::FORCED_VALID_FOR_TEST)) {
137 if (signalTime == Fence::SIGNAL_TIME_INVALID) {
138 signalTime = Fence::SIGNAL_TIME_PENDING;
139 }
140 }
141
Brian Anderson221de2a2016-09-21 16:53:28 -0700142 // Make the signal time visible to everyone if it is no longer pending
143 // and remove the class' reference to the fence.
144 if (signalTime != Fence::SIGNAL_TIME_PENDING) {
145 std::lock_guard<std::mutex> lock(mMutex);
146 mFence.clear();
147 mSignalTime.store(signalTime, std::memory_order_relaxed);
148 }
149
150 return signalTime;
151}
152
153nsecs_t FenceTime::getCachedSignalTime() const {
154 // memory_order_acquire since we don't have a lock fallback path
155 // that will do an acquire.
156 return mSignalTime.load(std::memory_order_acquire);
157}
158
159FenceTime::Snapshot FenceTime::getSnapshot() const {
160 // Quick check without the lock.
161 nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed);
162 if (signalTime != Fence::SIGNAL_TIME_PENDING) {
163 return Snapshot(signalTime);
164 }
165
166 // Do the full check with the lock.
167 std::lock_guard<std::mutex> lock(mMutex);
168 signalTime = mSignalTime.load(std::memory_order_relaxed);
169 if (signalTime != Fence::SIGNAL_TIME_PENDING) {
170 return Snapshot(signalTime);
171 }
172 return Snapshot(mFence);
173}
174
Brian Anderson3da8d272016-07-28 16:20:47 -0700175// For tests only. If forceValidForTest is true, then getSignalTime will
176// never return SIGNAL_TIME_INVALID and isValid will always return true.
177FenceTime::FenceTime(const sp<Fence>& fence, bool forceValidForTest)
178 : mState(forceValidForTest ?
179 State::FORCED_VALID_FOR_TEST : State::INVALID),
180 mFence(fence),
181 mSignalTime(mState == State::INVALID ?
182 Fence::SIGNAL_TIME_INVALID : Fence::SIGNAL_TIME_PENDING) {
183}
184
185void FenceTime::signalForTest(nsecs_t signalTime) {
186 // To be realistic, this should really set a hidden value that
187 // gets picked up in the next call to getSignalTime, but this should
188 // be good enough.
189 std::lock_guard<std::mutex> lock(mMutex);
190 mFence.clear();
191 mSignalTime.store(signalTime, std::memory_order_relaxed);
192}
193
Brian Anderson221de2a2016-09-21 16:53:28 -0700194// ============================================================================
195// FenceTime::Snapshot
196// ============================================================================
Brian Anderson221de2a2016-09-21 16:53:28 -0700197FenceTime::Snapshot::Snapshot(const sp<Fence>& srcFence)
198 : state(State::FENCE), fence(srcFence) {
199}
200
201FenceTime::Snapshot::Snapshot(nsecs_t srcSignalTime)
202 : state(State::SIGNAL_TIME), signalTime(srcSignalTime) {
203}
204
205size_t FenceTime::Snapshot::getFlattenedSize() const {
206 constexpr size_t min = sizeof(state);
207 switch (state) {
208 case State::EMPTY:
209 return min;
210 case State::FENCE:
211 return min + fence->getFlattenedSize();
212 case State::SIGNAL_TIME:
213 return min + sizeof(signalTime);
214 }
215 return 0;
216}
217
218size_t FenceTime::Snapshot::getFdCount() const {
219 return state == State::FENCE ? fence->getFdCount() : 0u;
220}
221
222status_t FenceTime::Snapshot::flatten(
223 void*& buffer, size_t& size, int*& fds, size_t& count) const {
224 if (size < getFlattenedSize()) {
225 return NO_MEMORY;
226 }
227
228 FlattenableUtils::write(buffer, size, state);
229 switch (state) {
230 case State::EMPTY:
231 return NO_ERROR;
232 case State::FENCE:
233 return fence->flatten(buffer, size, fds, count);
234 case State::SIGNAL_TIME:
235 FlattenableUtils::write(buffer, size, signalTime);
236 return NO_ERROR;
237 }
238
239 return NO_ERROR;
240}
241
242status_t FenceTime::Snapshot::unflatten(
243 void const*& buffer, size_t& size, int const*& fds, size_t& count) {
244 if (size < sizeof(state)) {
245 return NO_MEMORY;
246 }
247
248 FlattenableUtils::read(buffer, size, state);
249 switch (state) {
250 case State::EMPTY:
251 return NO_ERROR;
252 case State::FENCE:
253 fence = new Fence;
254 return fence->unflatten(buffer, size, fds, count);
255 case State::SIGNAL_TIME:
256 if (size < sizeof(signalTime)) {
257 return NO_MEMORY;
258 }
259 FlattenableUtils::read(buffer, size, signalTime);
260 return NO_ERROR;
261 }
262
263 return NO_ERROR;
264}
265
266// ============================================================================
267// FenceTimeline
268// ============================================================================
269void FenceTimeline::push(const std::shared_ptr<FenceTime>& fence) {
270 std::lock_guard<std::mutex> lock(mMutex);
271 while (mQueue.size() >= MAX_ENTRIES) {
272 // This is a sanity check to make sure the queue doesn't grow unbounded.
273 // MAX_ENTRIES should be big enough not to trigger this path.
274 // In case this path is taken though, users of FenceTime must make sure
275 // not to rely solely on FenceTimeline to get the final timestamp and
276 // should eventually call Fence::getSignalTime on their own.
277 std::shared_ptr<FenceTime> front = mQueue.front().lock();
278 if (front) {
279 // Make a last ditch effort to get the signalTime here since
280 // we are removing it from the timeline.
281 front->getSignalTime();
282 }
283 mQueue.pop();
284 }
285 mQueue.push(fence);
286}
287
288void FenceTimeline::updateSignalTimes() {
289 while (!mQueue.empty()) {
290 std::lock_guard<std::mutex> lock(mMutex);
291 std::shared_ptr<FenceTime> fence = mQueue.front().lock();
292 if (!fence) {
293 // The shared_ptr no longer exists and no one cares about the
294 // timestamp anymore.
295 mQueue.pop();
296 continue;
297 } else if (fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) {
298 // The fence has signaled and we've removed the sp<Fence> ref.
299 mQueue.pop();
300 continue;
301 } else {
302 // The fence didn't signal yet. Break since the later ones
303 // shouldn't have signaled either.
304 break;
305 }
306 }
307}
308
Brian Anderson3da8d272016-07-28 16:20:47 -0700309// ============================================================================
310// FenceToFenceTimeMap
311// ============================================================================
312std::shared_ptr<FenceTime> FenceToFenceTimeMap::createFenceTimeForTest(
313 const sp<Fence>& fence) {
314 std::lock_guard<std::mutex> lock(mMutex);
315 // Always garbage collecting isn't efficient, but this is only for testing.
316 garbageCollectLocked();
317 std::shared_ptr<FenceTime> fenceTime(new FenceTime(fence, true));
318 mMap[fence.get()].push_back(fenceTime);
319 return fenceTime;
320}
321
322void FenceToFenceTimeMap::signalAllForTest(
323 const sp<Fence>& fence, nsecs_t signalTime) {
324 bool signaled = false;
325
326 std::lock_guard<std::mutex> lock(mMutex);
327 auto it = mMap.find(fence.get());
328 if (it != mMap.end()) {
329 for (auto& weakFenceTime : it->second) {
330 std::shared_ptr<FenceTime> fenceTime = weakFenceTime.lock();
331 if (!fenceTime) {
332 continue;
333 }
334 ALOGE_IF(!fenceTime->isValid(),
335 "FenceToFenceTimeMap::signalAllForTest: "
336 "Signaling invalid fence.");
337 fenceTime->signalForTest(signalTime);
338 signaled = true;
339 }
340 }
341
342 if (!signaled) {
343 ALOGE("FenceToFenceTimeMap::signalAllForTest: Nothing to signal.");
344 }
345}
346
347void FenceToFenceTimeMap::garbageCollectLocked() {
348 for (auto& it : mMap) {
349 // Erase all expired weak pointers from the vector.
350 auto& vect = it.second;
351 vect.erase(
352 std::remove_if(vect.begin(), vect.end(),
353 [](const std::weak_ptr<FenceTime>& ft) {
354 return ft.expired();
355 }),
356 vect.end());
357
358 // Also erase the map entry if the vector is now empty.
359 if (vect.empty()) {
360 mMap.erase(it.first);
361 }
362 }
363}
364
Brian Anderson221de2a2016-09-21 16:53:28 -0700365} // namespace android