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 80 : StaticAllocatorBitmap::StaticAllocatorBitmap(void * storage, std::atomic<tBitChunkType> * usage, size_t capacity, 55 80 : size_t elementSize) : 56 : StaticAllocatorBase(capacity), 57 80 : mElements(storage), mElementSize(elementSize), mUsage(usage) 58 : { 59 152 : for (size_t word = 0; word * kBitChunkSize < Capacity(); ++word) 60 : { 61 72 : mUsage[word].store(0); 62 : } 63 80 : } 64 : 65 956 : void * StaticAllocatorBitmap::Allocate() 66 : { 67 1212 : for (size_t word = 0; word * kBitChunkSize < Capacity(); ++word) 68 : { 69 1208 : auto & usage = mUsage[word]; 70 1208 : auto value = usage.load(std::memory_order_relaxed); 71 38207 : for (size_t offset = 0; offset < kBitChunkSize && offset + word * kBitChunkSize < Capacity(); ++offset) 72 : { 73 37951 : if ((value & (kBit1 << offset)) == 0) 74 : { 75 1904 : if (usage.compare_exchange_strong(value, value | (kBit1 << offset))) 76 : { 77 952 : IncreaseUsage(); 78 952 : 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 952 : void StaticAllocatorBitmap::Deallocate(void * element) 89 : { 90 952 : size_t index = IndexOf(element); 91 952 : size_t word = index / kBitChunkSize; 92 952 : size_t offset = index - (word * kBitChunkSize); 93 : 94 : // ensure the element is in the pool 95 952 : VerifyOrDie(index < Capacity()); 96 : 97 952 : auto value = mUsage[word].fetch_and(~(kBit1 << offset)); 98 952 : VerifyOrDie((value & (kBit1 << offset)) != 0); // assert fail when free an unused slot 99 952 : DecreaseUsage(); 100 952 : } 101 : 102 952 : size_t StaticAllocatorBitmap::IndexOf(void * element) 103 : { 104 952 : std::ptrdiff_t diff = static_cast<uint8_t *>(element) - static_cast<uint8_t *>(mElements); 105 952 : VerifyOrDie(diff >= 0); 106 952 : VerifyOrDie(static_cast<size_t>(diff) % mElementSize == 0); 107 952 : auto index = static_cast<size_t>(diff) / mElementSize; 108 952 : VerifyOrDie(index < Capacity()); 109 952 : return index; 110 : } 111 : 112 3904 : Loop StaticAllocatorBitmap::ForEachActiveObjectInner(void * context, Lambda lambda) 113 : { 114 8508 : for (size_t word = 0; word * kBitChunkSize < Capacity(); ++word) 115 : { 116 4969 : auto & usage = mUsage[word]; 117 4969 : auto value = usage.load(std::memory_order_relaxed); 118 139431 : for (size_t offset = 0; offset < kBitChunkSize && offset + word * kBitChunkSize < Capacity(); ++offset) 119 : { 120 134827 : if ((value & (kBit1 << offset)) != 0) 121 : { 122 59346 : if (lambda(context, At(word * kBitChunkSize + offset)) == Loop::Break) 123 365 : return Loop::Break; 124 : } 125 : } 126 : } 127 3539 : return Loop::Finish; 128 : } 129 : 130 : #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP 131 : 132 4283102 : HeapObjectListNode * HeapObjectList::FindNode(void * object) const 133 : { 134 12237735 : for (HeapObjectListNode * p = mNext; p != this; p = p->mNext) 135 : { 136 12237735 : if (p->mObject == object) 137 : { 138 4283102 : return p; 139 : } 140 : } 141 0 : return nullptr; 142 : } 143 : 144 251813 : Loop HeapObjectList::ForEachNode(void * context, Lambda lambda) 145 : { 146 251813 : ++mIterationDepth; 147 251813 : Loop result = Loop::Finish; 148 251813 : HeapObjectListNode * p = mNext; 149 3903474 : while (p != this) 150 : { 151 3681661 : if (p->mObject != nullptr) 152 : { 153 3673602 : if (lambda(context, p->mObject) == Loop::Break) 154 : { 155 30000 : result = Loop::Break; 156 30000 : break; 157 : } 158 : } 159 3651661 : p = p->mNext; 160 : } 161 251813 : --mIterationDepth; 162 251813 : if (mIterationDepth == 0 && mHaveDeferredNodeRemovals) 163 : { 164 : // Remove nodes for released objects. 165 11267 : p = mNext; 166 68541 : while (p != this) 167 : { 168 57274 : HeapObjectListNode * next = p->mNext; 169 57274 : if (p->mObject == nullptr) 170 : { 171 12658 : p->Remove(); 172 12658 : Platform::Delete(p); 173 : } 174 57274 : p = next; 175 : } 176 : 177 11267 : mHaveDeferredNodeRemovals = false; 178 : } 179 251813 : return result; 180 : } 181 : 182 : #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP 183 : 184 : } // namespace internal 185 : } // namespace chip