FenceTime.cpp revision 221de2a33d456738f7f64db0b015a960211d4834
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 <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
283