blob: 954b4688ff40be1639b12dff228226ff510f55e6 [file] [log] [blame]
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/private/SkIDChangeListener.h"
/**
* Used to be notified when a gen/unique ID is invalidated, typically to preemptively purge
* associated items from a cache that are no longer reachable. The listener can
* be marked for deregistration if the cached item is remove before the listener is
* triggered. This prevents unbounded listener growth when cache items are routinely
* removed before the gen ID/unique ID is invalidated.
*/
SkIDChangeListener::SkIDChangeListener() : fShouldDeregister(false) {}
SkIDChangeListener::~SkIDChangeListener() = default;
using List = SkIDChangeListener::List;
List::List() = default;
List::~List() {
// We don't need the mutex. No other thread should have this list while it's being
// destroyed.
for (int i = 0; i < fListeners.count(); ++i) {
if (!fListeners[i]->shouldDeregister()) {
fListeners[i]->changed();
}
fListeners[i]->unref();
}
}
void List::add(sk_sp<SkIDChangeListener> listener, bool singleThreaded) {
if (!listener) {
return;
}
SkASSERT(!listener->shouldDeregister());
auto add = [&] {
// Clean out any stale listeners before we append the new one.
for (int i = 0; i < fListeners.count(); ++i) {
if (fListeners[i]->shouldDeregister()) {
fListeners[i]->unref();
fListeners.removeShuffle(i--); // No need to preserve the order after i.
}
}
*fListeners.append() = listener.release();
};
if (singleThreaded) {
add();
} else {
SkAutoMutexExclusive lock(fMutex);
add();
}
}
int List::count() {
SkAutoMutexExclusive lock(fMutex);
return fListeners.count();
}
void List::changed(bool singleThreaded) {
auto visit = [this]() {
for (SkIDChangeListener* listener : fListeners) {
if (!listener->shouldDeregister()) {
listener->changed();
}
// Listeners get at most one shot, so whether these triggered or not, blow them away.
listener->unref();
}
fListeners.reset();
};
if (singleThreaded) {
visit();
} else {
SkAutoMutexExclusive lock(fMutex);
visit();
}
}
void List::reset(bool singleThreaded) {
if (singleThreaded) {
fListeners.unrefAll();
} else {
SkAutoMutexExclusive lock(fMutex);
fListeners.unrefAll();
}
}