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