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 | |
18 | SkIDChangeListener::SkIDChangeListener() : fShouldDeregister(false) {} |
19 | |
20 | SkIDChangeListener::~SkIDChangeListener() = default; |
21 | |
22 | using List = SkIDChangeListener::List; |
23 | |
24 | List::List() = default; |
25 | |
26 | List::~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 | |
37 | void List::add(sk_sp<SkIDChangeListener> listener, bool singleThreaded) { |
38 | if (!listener) { |
39 | return; |
40 | } |
41 | SkASSERT(!listener->shouldDeregister()); |
42 | |
43 | auto add = [&] { |
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 | |
54 | if (singleThreaded) { |
55 | add(); |
56 | } else { |
57 | SkAutoMutexExclusive lock(fMutex); |
58 | add(); |
59 | } |
60 | } |
61 | |
62 | int List::count() { |
63 | SkAutoMutexExclusive lock(fMutex); |
64 | return fListeners.count(); |
65 | } |
66 | |
67 | void List::changed(bool singleThreaded) { |
68 | auto visit = [this]() { |
69 | for (SkIDChangeListener* listener : fListeners) { |
70 | if (!listener->shouldDeregister()) { |
71 | listener->changed(); |
72 | } |
73 | // Listeners get at most one shot, so whether these triggered or not, blow them away. |
74 | listener->unref(); |
75 | } |
76 | fListeners.reset(); |
77 | }; |
78 | |
79 | if (singleThreaded) { |
80 | visit(); |
81 | } else { |
82 | SkAutoMutexExclusive lock(fMutex); |
83 | visit(); |
84 | } |
85 | } |
86 | |
87 | void List::reset(bool singleThreaded) { |
88 | if (singleThreaded) { |
89 | fListeners.unrefAll(); |
90 | } else { |
91 | SkAutoMutexExclusive lock(fMutex); |
92 | fListeners.unrefAll(); |
93 | } |
94 | } |
95 |