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