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