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