1 /* 2 * Copyright 2020 Google LLC 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "include/private/SkIDChangeListener.h" 9 10 /** 11 * Used to be notified when a gen/unique ID is invalidated, typically to preemptively purge 12 * associated items from a cache that are no longer reachable. The listener can 13 * be marked for deregistration if the cached item is remove before the listener is 14 * triggered. This prevents unbounded listener growth when cache items are routinely 15 * removed before the gen ID/unique ID is invalidated. 16 */ 17 SkIDChangeListener()18SkIDChangeListener::SkIDChangeListener() : fShouldDeregister(false) {} 19 20 SkIDChangeListener::~SkIDChangeListener() = default; 21 22 using List = SkIDChangeListener::List; 23 24 List::List() = default; 25 ~List()26List::~List() { 27 // We don't need the mutex. No other thread should have this list while it's being 28 // destroyed. 29 for (int i = 0; i < fListeners.count(); ++i) { 30 if (!fListeners[i]->shouldDeregister()) { 31 fListeners[i]->changed(); 32 } 33 fListeners[i]->unref(); 34 } 35 } 36 add(sk_sp<SkIDChangeListener> listener)37void List::add(sk_sp<SkIDChangeListener> listener) { 38 if (!listener) { 39 return; 40 } 41 SkASSERT(!listener->shouldDeregister()); 42 43 SkAutoMutexExclusive lock(fMutex); 44 // Clean out any stale listeners before we append the new one. 45 for (int i = 0; i < fListeners.count(); ++i) { 46 if (fListeners[i]->shouldDeregister()) { 47 fListeners[i]->unref(); 48 fListeners.removeShuffle(i--); // No need to preserve the order after i. 49 } 50 } 51 *fListeners.append() = listener.release(); 52 } 53 count() const54int List::count() const { 55 SkAutoMutexExclusive lock(fMutex); 56 return fListeners.count(); 57 } 58 changed()59void List::changed() { 60 SkAutoMutexExclusive lock(fMutex); 61 for (SkIDChangeListener* listener : fListeners) { 62 if (!listener->shouldDeregister()) { 63 listener->changed(); 64 } 65 // Listeners get at most one shot, so whether these triggered or not, blow them away. 66 listener->unref(); 67 } 68 fListeners.reset(); 69 } 70 reset()71void List::reset() { 72 SkAutoMutexExclusive lock(fMutex); 73 fListeners.unrefAll(); 74 } 75