FenceTime.cpp revision 175a7206c5aea70236b916d7707ab25025eb9cd6
1/*
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 <utils/Log.h>
21#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
134    // 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
142    // 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
175// 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
194// ============================================================================
195// FenceTime::Snapshot
196// ============================================================================
197FenceTime::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
309// ============================================================================
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
365} // namespace android
366