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 1431 : void Provider::RegisterAttributeChangeListener(AttributeChangeListener & listener)
23 : {
24 1431 : assertChipStackLockedByCurrentThread();
25 :
26 1431 : listener.SetNextAttributeChangeListener(mAttributeChangeListenersHead);
27 1431 : mAttributeChangeListenersHead = &listener;
28 1431 : }
29 :
30 394 : void Provider::UnregisterAttributeChangeListener(AttributeChangeListener & listener)
31 : {
32 394 : 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 394 : ActiveIterator * active = mActiveIterators;
37 406 : 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 394 : if (mAttributeChangeListenersHead == &listener)
47 : {
48 386 : mAttributeChangeListenersHead = listener.GetNextAttributeChangeListener();
49 386 : listener.SetNextAttributeChangeListener(nullptr);
50 386 : 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 7185 : void Provider::NotifyAttributeChanged(const ConcreteAttributePath & path, AttributeChangeType type)
67 : {
68 7185 : 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 7185 : iter.expectedNext = mAttributeChangeListenersHead;
74 7185 : iter.nextIterator = mActiveIterators;
75 7185 : mActiveIterators = &iter;
76 :
77 14373 : while (iter.expectedNext)
78 : {
79 7188 : AttributeChangeListener * current = iter.expectedNext;
80 7188 : iter.expectedNext = current->GetNextAttributeChangeListener();
81 7188 : current->OnAttributeChanged(path, type);
82 : }
83 :
84 7185 : mActiveIterators = iter.nextIterator;
85 7185 : }
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
|