Line data Source code
1 : /*
2 : * Copyright (c) 2026 Project CHIP Authors
3 : * All rights reserved.
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 : #include "platform/LockTracker.h"
18 : #include <app/data-model-provider/Provider.h>
19 :
20 : namespace chip::app::DataModel {
21 :
22 1545 : void Provider::RegisterAttributeChangeListener(AttributeChangeListener & listener)
23 : {
24 1545 : assertChipStackLockedByCurrentThread();
25 :
26 1545 : listener.SetNextAttributeChangeListener(mAttributeChangeListenersHead);
27 1545 : mAttributeChangeListenersHead = &listener;
28 1545 : }
29 :
30 395 : void Provider::UnregisterAttributeChangeListener(AttributeChangeListener & listener)
31 : {
32 395 : assertChipStackLockedByCurrentThread();
33 :
34 : // If any active iterator is about to process this listener, advance it
35 : // to the next one to avoid processing a removed listener.
36 395 : ActiveIterator * active = mActiveIterators;
37 407 : while (active)
38 : {
39 12 : if (active->expectedNext == &listener)
40 : {
41 2 : active->expectedNext = listener.GetNextAttributeChangeListener();
42 : }
43 12 : active = active->nextIterator;
44 : }
45 :
46 395 : if (mAttributeChangeListenersHead == &listener)
47 : {
48 387 : mAttributeChangeListenersHead = listener.GetNextAttributeChangeListener();
49 387 : listener.SetNextAttributeChangeListener(nullptr);
50 387 : return;
51 : }
52 :
53 8 : AttributeChangeListener * current = mAttributeChangeListenersHead;
54 15 : while (current && (current->GetNextAttributeChangeListener() != &listener))
55 : {
56 7 : current = current->GetNextAttributeChangeListener();
57 : }
58 :
59 8 : if (current)
60 : {
61 5 : current->SetNextAttributeChangeListener(listener.GetNextAttributeChangeListener());
62 5 : listener.SetNextAttributeChangeListener(nullptr);
63 : }
64 : }
65 :
66 7641 : void Provider::NotifyAttributeChanged(const ConcreteAttributePath & path, AttributeChangeType type)
67 : {
68 7641 : assertChipStackLockedByCurrentThread();
69 :
70 : // Register this iteration on the stack of active iterators.
71 : // This allows UnregisterAttributeChangeListener to update us if needed.
72 : ActiveIterator iter;
73 7641 : iter.expectedNext = mAttributeChangeListenersHead;
74 7641 : iter.nextIterator = mActiveIterators;
75 7641 : mActiveIterators = &iter;
76 :
77 15285 : while (iter.expectedNext)
78 : {
79 7644 : AttributeChangeListener * current = iter.expectedNext;
80 7644 : iter.expectedNext = current->GetNextAttributeChangeListener();
81 7644 : current->OnAttributeChanged(path, type);
82 : }
83 :
84 7641 : mActiveIterators = iter.nextIterator;
85 7641 : }
86 :
87 57 : void Provider::NotifyEndpointChanged(EndpointId endpointId, EndpointChangeType type)
88 : {
89 57 : assertChipStackLockedByCurrentThread();
90 :
91 : // Register this iteration on the stack of active iterators.
92 : // This allows UnregisterAttributeChangeListener to update us if needed.
93 : ActiveIterator iter;
94 57 : iter.expectedNext = mAttributeChangeListenersHead;
95 57 : iter.nextIterator = mActiveIterators;
96 57 : mActiveIterators = &iter;
97 :
98 102 : while (iter.expectedNext)
99 : {
100 45 : AttributeChangeListener * current = iter.expectedNext;
101 45 : iter.expectedNext = current->GetNextAttributeChangeListener();
102 45 : current->OnEndpointChanged(endpointId, type);
103 : }
104 :
105 57 : mActiveIterators = iter.nextIterator;
106 57 : }
107 :
108 : } // namespace chip::app::DataModel
|