1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "mempool.h"
17 #include "securec.h"
18
19 namespace maple {
20 MemPoolCtrler memPoolCtrler;
21 bool MemPoolCtrler::freeMemInTime = false;
22
FreeMemBlocks(const MemPool & pool,MemBlock * fixedMemHead,MemBlock * bigMemHead)23 void MemPoolCtrler::FreeMemBlocks(const MemPool &pool, MemBlock *fixedMemHead, MemBlock *bigMemHead)
24 {
25 (void)(pool);
26
27 MemBlock *fixedTail = nullptr;
28
29 if (fixedMemHead != nullptr) {
30 fixedTail = fixedMemHead;
31 while (fixedTail->nextMemBlock != nullptr) {
32 fixedTail = fixedTail->nextMemBlock;
33 }
34 }
35
36 while (bigMemHead != nullptr) {
37 auto *cur = bigMemHead;
38 bigMemHead = bigMemHead->nextMemBlock;
39 free(cur->startPtr);
40 delete cur;
41 }
42
43 if (fixedTail != nullptr) {
44 fixedTail->nextMemBlock = fixedFreeMemBlocks;
45 DEBUG_ASSERT(fixedTail->nextMemBlock != fixedTail, "error");
46 fixedFreeMemBlocks = fixedMemHead;
47 }
48 }
49
50 // Destructor, free all allocated memories
~MemPoolCtrler()51 MemPoolCtrler::~MemPoolCtrler()
52 {
53 FreeMem();
54 }
55
FreeFixedSizeMemBlockMemory()56 void MemPoolCtrler::FreeFixedSizeMemBlockMemory()
57 {
58 FreeMem();
59 sysMemoryMgr->ReleaseMemory();
60 }
61
62 // Allocate a new memory pool and register it in controller
NewMemPool(const std::string & name,bool isLocalPool)63 MemPool *MemPoolCtrler::NewMemPool(const std::string &name, bool isLocalPool)
64 {
65 MemPool *memPool = nullptr;
66
67 if (isLocalPool) {
68 memPool = new ThreadLocalMemPool(*this, name);
69 } else {
70 memPool = new ThreadShareMemPool(*this, name);
71 }
72
73 return memPool;
74 }
75
76 // This function will be removed soon, DO NOT call it, just use delete memPool
DeleteMemPool(MemPool * memPool) const77 void MemPoolCtrler::DeleteMemPool(MemPool *memPool) const
78 {
79 delete memPool;
80 }
81
FreeMem()82 void MemPoolCtrler::FreeMem()
83 {
84 while (fixedFreeMemBlocks != nullptr) {
85 MemBlock *arena = fixedFreeMemBlocks;
86 fixedFreeMemBlocks = fixedFreeMemBlocks->nextMemBlock;
87 delete arena;
88 }
89 }
90
AllocMemBlock(const MemPool & pool,size_t size)91 MemBlock *MemPoolCtrler::AllocMemBlock(const MemPool &pool, size_t size)
92 {
93 if (size <= kMemBlockSizeMin) {
94 return AllocFixMemBlock(pool);
95 } else {
96 return AllocBigMemBlock(pool, size);
97 }
98 }
99
AllocFixMemBlock(const MemPool & pool)100 MemBlock *MemPoolCtrler::AllocFixMemBlock(const MemPool &pool)
101 {
102 (void)(pool);
103 MemBlock *ret = nullptr;
104
105 if (fixedFreeMemBlocks != nullptr) {
106 ret = fixedFreeMemBlocks;
107 fixedFreeMemBlocks = fixedFreeMemBlocks->nextMemBlock;
108 return ret;
109 }
110
111 uint8_t *ptr = sysMemoryMgr->RealAllocMemory(kMemBlockMalloc);
112 // leave one MemBlock to return
113 for (size_t i = 0; i < kMemBlockMalloc / kMemBlockSizeMin - 1; ++i) {
114 auto *block = new MemBlock(ptr, kMemBlockSizeMin);
115 ptr += kMemBlockSizeMin;
116 block->nextMemBlock = fixedFreeMemBlocks;
117 fixedFreeMemBlocks = block;
118 }
119
120 return new MemBlock(ptr, kMemBlockSizeMin);
121 }
122
AllocBigMemBlock(const MemPool & pool,size_t size) const123 MemBlock *MemPoolCtrler::AllocBigMemBlock(const MemPool &pool, size_t size) const
124 {
125 DEBUG_ASSERT(size > kMemBlockSizeMin, "Big memory block must be bigger than fixed memory block");
126 (void)(pool);
127
128 uint8_t *block = reinterpret_cast<uint8_t *>(malloc(size));
129 CHECK_FATAL(block != nullptr, "malloc failed");
130 return new MemBlock(block, size);
131 }
132
~MemPool()133 MemPool::~MemPool()
134 {
135 ctrler.FreeMemBlocks(*this, fixedMemHead, bigMemHead);
136 }
137
Malloc(size_t size)138 void *MemPool::Malloc(size_t size)
139 {
140 size = BITS_ALIGN(size);
141 DEBUG_ASSERT(endPtr >= curPtr, "endPtr should >= curPtr");
142 if (size > static_cast<size_t>(endPtr - curPtr)) {
143 return AllocNewMemBlock(size);
144 }
145 uint8_t *retPtr = curPtr;
146 curPtr += size;
147 return retPtr;
148 }
149
ReleaseContainingMem()150 void MemPool::ReleaseContainingMem()
151 {
152 ctrler.FreeMemBlocks(*this, fixedMemHead, bigMemHead);
153
154 fixedMemHead = nullptr;
155 bigMemHead = nullptr;
156 endPtr = nullptr;
157 curPtr = nullptr;
158 }
159
160 // Malloc size of memory from memory pool, then set 0
Calloc(size_t size)161 void *MemPool::Calloc(size_t size)
162 {
163 void *p = Malloc(BITS_ALIGN(size));
164 DEBUG_ASSERT(p != nullptr, "ERROR: Calloc error");
165 errno_t eNum = memset_s(p, BITS_ALIGN(size), 0, BITS_ALIGN(size));
166 CHECK_FATAL(eNum == EOK, "memset_s failed");
167 return p;
168 }
169
170 // Realloc new size of memory
Realloc(const void * ptr,size_t oldSize,size_t newSize)171 void *MemPool::Realloc(const void *ptr, size_t oldSize, size_t newSize)
172 {
173 void *result = Malloc(newSize);
174 DEBUG_ASSERT(result != nullptr, "ERROR: Realloc error");
175 size_t copySize = ((newSize > oldSize) ? oldSize : newSize);
176 if (copySize != 0 && ptr != nullptr) {
177 errno_t eNum = memcpy_s(result, copySize, ptr, copySize);
178 CHECK_FATAL(eNum == EOK, "memcpy_s failed");
179 }
180 return result;
181 }
182
AllocNewMemBlock(size_t size)183 uint8_t *MemPool::AllocNewMemBlock(size_t size)
184 {
185 MemBlock **head = nullptr;
186 MemBlock *newMemBlock = ctrler.AllocMemBlock(*this, size);
187 if (newMemBlock->memSize <= kMemBlockSizeMin) {
188 head = &fixedMemHead;
189 } else {
190 head = &bigMemHead;
191 }
192
193 newMemBlock->nextMemBlock = *head;
194 *head = newMemBlock;
195 CHECK_FATAL(newMemBlock->nextMemBlock != newMemBlock, "error");
196
197 curPtr = newMemBlock->startPtr + size;
198 endPtr = newMemBlock->startPtr + newMemBlock->memSize;
199 DEBUG_ASSERT(curPtr <= endPtr, "must be");
200
201 return newMemBlock->startPtr;
202 }
203
Malloc(size_t size)204 void *StackMemPool::Malloc(size_t size)
205 {
206 size = BITS_ALIGN(size);
207 uint8_t **curPtrPtr = nullptr;
208 uint8_t *curEndPtr = nullptr;
209 if (size <= kMemBlockSizeMin) {
210 curPtrPtr = &curPtr;
211 curEndPtr = endPtr;
212 } else {
213 curPtrPtr = &bigCurPtr;
214 curEndPtr = bigEndPtr;
215 }
216 uint8_t *retPtr = *curPtrPtr;
217 DEBUG_ASSERT(curEndPtr >= *curPtrPtr, "endPtr should >= curPtr");
218 if (size > static_cast<size_t>(curEndPtr - *curPtrPtr)) {
219 retPtr = AllocTailMemBlock(size);
220 }
221 *curPtrPtr = retPtr + size;
222 return retPtr;
223 }
224
225 // scoped mem pool don't use big mem block for small size, different with normal mempool
AllocMemBlockBySize(size_t size)226 MemBlock *StackMemPool::AllocMemBlockBySize(size_t size)
227 {
228 if (size <= kMemBlockSizeMin) {
229 return ctrler.AllocFixMemBlock(*this);
230 } else {
231 return ctrler.AllocBigMemBlock(*this, size);
232 }
233 }
234
ResetStackTop(const LocalMapleAllocator * alloc,uint8_t * fixedCurPtrMark,MemBlock * fixedStackTopMark,uint8_t * bigCurPtrMark,MemBlock * bigStackTopMark)235 void StackMemPool::ResetStackTop(const LocalMapleAllocator *alloc, uint8_t *fixedCurPtrMark,
236 MemBlock *fixedStackTopMark, uint8_t *bigCurPtrMark,
237 MemBlock *bigStackTopMark) noexcept
238 {
239 CheckTopAllocator(alloc);
240 PopAllocator();
241
242 if (fixedStackTopMark != nullptr) {
243 fixedMemStackTop = fixedStackTopMark;
244 curPtr = fixedCurPtrMark;
245 endPtr = fixedMemStackTop->EndPtr();
246 } else if (fixedMemHead != nullptr) {
247 fixedMemStackTop = fixedMemHead;
248 curPtr = fixedMemStackTop->startPtr;
249 endPtr = fixedMemStackTop->EndPtr();
250 }
251
252 if (bigStackTopMark != nullptr) {
253 bigMemStackTop = bigStackTopMark;
254 bigCurPtr = bigCurPtrMark;
255 bigEndPtr = bigMemStackTop->EndPtr();
256 } else if (bigMemHead != nullptr) {
257 bigMemStackTop = bigMemHead;
258 bigCurPtr = bigMemStackTop->startPtr;
259 bigEndPtr = bigMemStackTop->EndPtr();
260 }
261 }
262
AllocTailMemBlock(size_t size)263 uint8_t *StackMemPool::AllocTailMemBlock(size_t size)
264 {
265 MemBlock **head = nullptr;
266 MemBlock **stackTop = nullptr;
267 uint8_t **endPtrPtr = nullptr;
268
269 if (size <= kMemBlockSizeMin) {
270 head = &fixedMemHead;
271 stackTop = &fixedMemStackTop;
272 endPtrPtr = &endPtr;
273 } else {
274 head = &bigMemHead;
275 stackTop = &bigMemStackTop;
276 endPtrPtr = &bigEndPtr;
277 }
278
279 if (*stackTop == nullptr) {
280 MemBlock *newMemBlock = AllocMemBlockBySize(size);
281 *stackTop = newMemBlock;
282 *head = newMemBlock;
283 (*stackTop)->nextMemBlock = nullptr;
284 } else {
285 if ((*stackTop)->nextMemBlock != nullptr && (*stackTop)->nextMemBlock->memSize >= size) {
286 *stackTop = (*stackTop)->nextMemBlock;
287 } else {
288 MemBlock *newMemBlock = AllocMemBlockBySize(size);
289 auto *tmp = (*stackTop)->nextMemBlock;
290 (*stackTop)->nextMemBlock = newMemBlock;
291 *stackTop = newMemBlock;
292 newMemBlock->nextMemBlock = tmp;
293 }
294 }
295 *endPtrPtr = (*stackTop)->EndPtr();
296 return (*stackTop)->startPtr;
297 }
298 } // namespace maple
299