Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : * Copyright (c) 2013 Nest Labs, Inc.
5 : * All rights reserved.
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : #include <lib/support/CodeUtils.h>
21 : #include <lib/support/Pool.h>
22 :
23 : namespace chip {
24 :
25 : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
26 :
27 : bool HeapObjectPoolExitHandling::sIgnoringLeaksOnExit = false;
28 : bool HeapObjectPoolExitHandling::sExitHandlerRegistered = false;
29 :
30 0 : void HeapObjectPoolExitHandling::IgnoreLeaksOnExit()
31 : {
32 0 : if (sExitHandlerRegistered)
33 : {
34 0 : return;
35 : }
36 :
37 0 : int ret = atexit(ExitHandler);
38 0 : if (ret != 0)
39 : {
40 0 : ChipLogError(Controller, "IgnoreLeaksOnExit: atexit failed: %d\n", ret);
41 : }
42 0 : sExitHandlerRegistered = true;
43 : }
44 :
45 0 : void HeapObjectPoolExitHandling::ExitHandler()
46 : {
47 0 : sIgnoringLeaksOnExit = true;
48 0 : }
49 :
50 : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
51 :
52 : namespace internal {
53 :
54 156 : StaticAllocatorBitmap::StaticAllocatorBitmap(void * storage, std::atomic<tBitChunkType> * usage, size_t capacity,
55 156 : size_t elementSize) :
56 : StaticAllocatorBase(capacity),
57 156 : mElements(storage), mElementSize(elementSize), mUsage(usage)
58 : {
59 304 : for (size_t word = 0; word * kBitChunkSize < Capacity(); ++word)
60 : {
61 148 : mUsage[word].store(0);
62 : }
63 156 : }
64 :
65 975 : void * StaticAllocatorBitmap::Allocate()
66 : {
67 1231 : for (size_t word = 0; word * kBitChunkSize < Capacity(); ++word)
68 : {
69 1227 : auto & usage = mUsage[word];
70 1227 : auto value = usage.load(std::memory_order_relaxed);
71 38823 : for (size_t offset = 0; offset < kBitChunkSize && offset + word * kBitChunkSize < Capacity(); ++offset)
72 : {
73 38567 : if ((value & (kBit1 << offset)) == 0)
74 : {
75 1942 : if (usage.compare_exchange_strong(value, value | (kBit1 << offset)))
76 : {
77 971 : IncreaseUsage();
78 971 : return At(word * kBitChunkSize + offset);
79 : }
80 :
81 0 : value = usage.load(std::memory_order_relaxed); // if there is a race, update new usage
82 : }
83 : }
84 : }
85 4 : return nullptr;
86 : }
87 :
88 971 : void StaticAllocatorBitmap::Deallocate(void * element)
89 : {
90 971 : size_t index = IndexOf(element);
91 971 : size_t word = index / kBitChunkSize;
92 971 : size_t offset = index - (word * kBitChunkSize);
93 :
94 : // ensure the element is in the pool
95 971 : VerifyOrDie(index < Capacity());
96 :
97 971 : auto value = mUsage[word].fetch_and(~(kBit1 << offset));
98 971 : VerifyOrDie((value & (kBit1 << offset)) != 0); // assert fail when free an unused slot
99 971 : DecreaseUsage();
100 971 : }
101 :
102 971 : size_t StaticAllocatorBitmap::IndexOf(void * element)
103 : {
104 971 : std::ptrdiff_t diff = static_cast<uint8_t *>(element) - static_cast<uint8_t *>(mElements);
105 971 : VerifyOrDie(diff >= 0);
106 971 : VerifyOrDie(static_cast<size_t>(diff) % mElementSize == 0);
107 971 : auto index = static_cast<size_t>(diff) / mElementSize;
108 971 : VerifyOrDie(index < Capacity());
109 971 : return index;
110 : }
111 :
112 3850 : Loop StaticAllocatorBitmap::ForEachActiveObjectInner(void * context, Lambda lambda)
113 : {
114 8400 : for (size_t word = 0; word * kBitChunkSize < Capacity(); ++word)
115 : {
116 4915 : auto & usage = mUsage[word];
117 4915 : auto value = usage.load(std::memory_order_relaxed);
118 139303 : for (size_t offset = 0; offset < kBitChunkSize && offset + word * kBitChunkSize < Capacity(); ++offset)
119 : {
120 134753 : if ((value & (kBit1 << offset)) != 0)
121 : {
122 59328 : if (lambda(context, At(word * kBitChunkSize + offset)) == Loop::Break)
123 365 : return Loop::Break;
124 : }
125 : }
126 : }
127 3485 : return Loop::Finish;
128 : }
129 :
130 31 : size_t StaticAllocatorBitmap::FirstActiveIndex()
131 : {
132 31 : size_t idx = 0;
133 31 : for (size_t word = 0; word * kBitChunkSize < Capacity(); ++word)
134 : {
135 31 : auto & usage = mUsage[word];
136 31 : auto value = usage.load(std::memory_order_relaxed);
137 33 : for (size_t offset = 0; offset < kBitChunkSize && offset + word * kBitChunkSize < Capacity(); ++offset)
138 : {
139 33 : if ((value & (kBit1 << offset)) != 0)
140 : {
141 31 : return idx;
142 : }
143 2 : idx++;
144 : }
145 : }
146 0 : VerifyOrDie(idx == mCapacity);
147 0 : return mCapacity;
148 : }
149 :
150 1474 : size_t StaticAllocatorBitmap::NextActiveIndexAfter(size_t start)
151 : {
152 1474 : size_t idx = 0;
153 1504 : for (size_t word = 0; word * kBitChunkSize < Capacity(); ++word)
154 : {
155 1474 : auto & usage = mUsage[word];
156 1474 : auto value = usage.load(std::memory_order_relaxed);
157 38822 : for (size_t offset = 0; offset < kBitChunkSize && offset + word * kBitChunkSize < Capacity(); ++offset)
158 : {
159 38792 : if (((value & (kBit1 << offset)) != 0) && (start < idx))
160 : {
161 1444 : return idx;
162 : }
163 37348 : idx++;
164 : }
165 : }
166 30 : VerifyOrDie(idx == mCapacity);
167 30 : return mCapacity;
168 : }
169 :
170 : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
171 :
172 6796174 : HeapObjectListNode * HeapObjectList::FindNode(void * object) const
173 : {
174 19488260 : for (HeapObjectListNode * p = mNext; p != this; p = p->mNext)
175 : {
176 19488260 : if (p->mObject == object)
177 : {
178 6796174 : return p;
179 : }
180 : }
181 0 : return nullptr;
182 : }
183 :
184 236444 : Loop HeapObjectList::ForEachNode(void * context, Lambda lambda)
185 : {
186 236444 : ++mIterationDepth;
187 236444 : Loop result = Loop::Finish;
188 236444 : HeapObjectListNode * p = mNext;
189 3873261 : while (p != this)
190 : {
191 3667471 : if (p->mObject != nullptr)
192 : {
193 3659254 : if (lambda(context, p->mObject) == Loop::Break)
194 : {
195 30654 : result = Loop::Break;
196 30654 : break;
197 : }
198 : }
199 3636817 : p = p->mNext;
200 : }
201 236444 : --mIterationDepth;
202 236444 : CleanupDeferredReleases();
203 236444 : return result;
204 : }
205 :
206 237541 : void HeapObjectList::CleanupDeferredReleases()
207 : {
208 237541 : if (mIterationDepth != 0 || !mHaveDeferredNodeRemovals)
209 : {
210 225901 : return;
211 : }
212 : // Remove nodes for released objects.
213 11640 : HeapObjectListNode * p = mNext;
214 69596 : while (p != this)
215 : {
216 57956 : HeapObjectListNode * next = p->mNext;
217 57956 : if (p->mObject == nullptr)
218 : {
219 13159 : p->Remove();
220 13159 : Platform::Delete(p);
221 : }
222 57956 : p = next;
223 : }
224 :
225 11640 : mHaveDeferredNodeRemovals = false;
226 : }
227 :
228 : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
229 :
230 : } // namespace internal
231 : } // namespace chip
|