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