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