1 /*
2  * Copyright (C) 2022 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 "dympool.h"
17 
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
DympCreatePool(int initSize,int maxSize,int itemSize,FILLP_BOOL autoExpand,DympoolItemOperaCbSt * itemOperaCb)21 DympoolType *DympCreatePool(int initSize, int maxSize, int itemSize, FILLP_BOOL autoExpand,
22                             DympoolItemOperaCbSt *itemOperaCb)
23 {
24     DympoolType *pool = FILLP_NULL_PTR;
25     if ((initSize <= 0) || (maxSize <= 0) || (itemSize <= 0)) {
26         FILLP_LOGERR("Error to create pool initSize:%d,maxSize:%d,itemSize:%d", initSize, maxSize, itemSize);
27         return FILLP_NULL_PTR;
28     }
29 
30     pool = SpungeAlloc(1, sizeof(DympoolType), SPUNGE_ALLOC_TYPE_MALLOC);
31     if (pool == FILLP_NULL_PTR) {
32         FILLP_LOGERR("Can't alloc dympool");
33         goto CREATE_FAIL;
34     }
35 
36     pool->maxSize = maxSize;
37     pool->itemSize = itemSize;
38     pool->currentSize = 0;
39     pool->itemOperaCb.createCb = itemOperaCb->createCb;
40     pool->itemOperaCb.destroyCb = itemOperaCb->destroyCb;
41     pool->autoExpand = autoExpand;
42     pool->initSize = initSize;
43 
44     HLIST_INIT(&pool->mlist);
45 
46     pool->mp = FillpQueueCreate("dymp_memory_pool", (FILLP_SIZE_T)(unsigned int)maxSize, SPUNGE_ALLOC_TYPE_MALLOC);
47     if (pool->mp == FILLP_NULL_PTR) {
48         FILLP_LOGERR("Can't alloc queue");
49         goto CREATE_FAIL;
50     }
51 
52     pool->currentSize = DympAskMoreMemory(pool, initSize, FILLP_FALSE);
53     if (pool->currentSize <= 0) {
54         FILLP_LOGERR("Initial memory fail");
55         goto CREATE_FAIL;
56     }
57 
58     FILLP_LOGINF("Create pool success, maxSize:%d, currentSize:%d, itemSize:%d",
59         maxSize, pool->currentSize, itemSize);
60 
61     return pool;
62 
63 CREATE_FAIL:
64     if (pool != FILLP_NULL_PTR) {
65         if (pool->mp != FILLP_NULL_PTR) {
66             FillpQueueDestroy(pool->mp);
67             pool->mp = FILLP_NULL_PTR;
68         }
69         SpungeFree(pool, SPUNGE_ALLOC_TYPE_MALLOC);
70     }
71 
72     return FILLP_NULL_PTR;
73 }
74 
DympDestroyPool(DympoolType * pool)75 void DympDestroyPool(DympoolType *pool)
76 {
77     struct HlistNode *node = FILLP_NULL_PTR;
78     DympMemory *mem = FILLP_NULL_PTR;
79 
80     if (pool == FILLP_NULL_PTR) {
81         return;
82     }
83 
84     node = HLIST_FIRST(&pool->mlist);
85     while (node != FILLP_NULL_PTR) {
86         mem = DympMemoryNodeEntry(node);
87         if (pool->itemOperaCb.destroyCb != FILLP_NULL_PTR) {
88             char *dataPointer = (char *)((char *)mem + sizeof(DympMemory));
89             int i;
90             for (i = 0; i < mem->itemCnt; i++) {
91                 DympItemType *item = (DympItemType *)(dataPointer);
92                 pool->itemOperaCb.destroyCb(item);
93                 item->mp = FILLP_NULL_PTR;
94                 int offset = (int)(pool->itemSize + ((int)sizeof(DympItemType)));
95                 dataPointer += offset;
96             }
97         }
98 
99         node = node->next;
100         SpungeFree(mem, SPUNGE_ALLOC_TYPE_MALLOC);
101     }
102 
103     if (pool->mp != FILLP_NULL_PTR) {
104         FillpQueueDestroy(pool->mp);
105     }
106 
107     SpungeFree(pool, SPUNGE_ALLOC_TYPE_MALLOC);
108 }
109 
DympSetConsSafe(DympoolType * pool,FILLP_BOOL safe)110 void DympSetConsSafe(DympoolType *pool, FILLP_BOOL safe)
111 {
112     FillpQueueSetConsSafe(pool->mp, safe);
113 }
114 
DympSetProdSafe(DympoolType * pool,FILLP_BOOL safe)115 void DympSetProdSafe(DympoolType *pool, FILLP_BOOL safe)
116 {
117     FillpQueueSetProdSafe(pool->mp, safe);
118 }
119 
DympExpandMemory(DympoolType * pool,int stepSizeWork)120 static int DympExpandMemory(DympoolType *pool, int stepSizeWork)
121 {
122     int i;
123     char *dataPointer = FILLP_NULL_PTR;
124     DympMemory *mem = FILLP_NULL_PTR;
125 
126     if (((FILLP_INT)((size_t)pool->itemSize + sizeof(DympItemType)) == 0) ||
127         ((FILLP_INT)(FILLP_MAX_INT_VALUE - sizeof(DympMemory)) /
128         (FILLP_INT)((size_t)pool->itemSize + sizeof(DympItemType))) < stepSizeWork) {
129         FILLP_LOGERR("Error to ask memory, because ask size too big");
130         return -1;
131     }
132     int askSize = (int)((size_t)stepSizeWork * ((size_t)pool->itemSize + sizeof(DympItemType)) + sizeof(DympMemory));
133     mem = (DympMemory *)SpungeAlloc(1, (FILLP_SIZE_T)((FILLP_UINT)askSize), (FILLP_INT)SPUNGE_ALLOC_TYPE_MALLOC);
134     if (mem == FILLP_NULL_PTR) {
135         FILLP_LOGERR("Fail to alloc memory");
136         return -1;
137     }
138 
139     dataPointer = (char *)((char *)mem + sizeof(DympMemory));
140 
141     HLIST_INIT_NODE(&mem->hnode);
142     HlistAddTail(&pool->mlist, &mem->hnode);
143     int itemCount = 0;
144     for (i = 0; i < stepSizeWork; i++) {
145         FILLP_INT err = 0;
146         DympItemType *item = (DympItemType *)(dataPointer);
147         int offset = (int)(pool->itemSize + ((int)sizeof(DympItemType)));
148         dataPointer += offset;
149 
150         item->mp = pool->mp;
151 
152         if (pool->itemOperaCb.createCb != FILLP_NULL_PTR) {
153             err = pool->itemOperaCb.createCb(item);
154         }
155 
156         if (err != FILLP_OK) {
157             continue;
158         }
159 
160         (void)FillpQueuePush(item->mp, (void *)&item, FILLP_FALSE, 1);
161         itemCount++;
162     }
163 
164     pool->currentSize += itemCount;
165     if (itemCount != 0) {
166         mem->itemCnt = itemCount;
167         FILLP_LOGINF("stepSize:%d, Current pool size:%d", itemCount, pool->currentSize);
168     } else {
169         HlistDelete(&pool->mlist, &mem->hnode);
170         SpungeFree(mem, SPUNGE_ALLOC_TYPE_MALLOC);
171     }
172 
173     return itemCount;
174 }
175 
DympAskMoreMemory(DympoolType * pool,int stepSize,int throttleGrow)176 int DympAskMoreMemory(DympoolType *pool, int stepSize, int throttleGrow)
177 {
178     int stepSizeWork = stepSize;
179     int maxSizeRemain;
180     int tempMax;
181 
182     FILLP_UNUSED_PARA(throttleGrow);
183 
184     if ((pool == FILLP_NULL_PTR) || (stepSize <= 0)) {
185         FILLP_LOGERR("Wrong to ask memory, stepSize:%d", stepSize);
186         return -1;
187     }
188 
189     tempMax = pool->maxSize;
190 
191     maxSizeRemain = tempMax - pool->currentSize;
192     if (maxSizeRemain <= 0) {
193         FILLP_LOGDBG("maxSizeRemain=%d is invalid, unable to expand memory", maxSizeRemain);
194         return 0;
195     }
196 
197     if (stepSizeWork > maxSizeRemain) {
198         stepSizeWork = maxSizeRemain;
199     }
200     return DympExpandMemory(pool, stepSizeWork);
201 }
202 
203 
DympAlloc(DympoolType * pool,void ** data,int throttleGrow)204 int DympAlloc(DympoolType *pool, void **data, int throttleGrow)
205 {
206     DympItemType *tmp = FILLP_NULL_PTR;
207     FILLP_INT ret = 0;
208     int i;
209 
210     if ((pool == FILLP_NULL_PTR) || (data == FILLP_NULL_PTR)) {
211         FILLP_LOGERR("MemPool pointer is invalid \n");
212         return ERR_NULLPTR;
213     }
214 
215     for (i = 0; i < pool->maxSize; i++) {
216         ret = FillpQueuePop(pool->mp, (void *)&tmp, 1);
217         if ((ret <= 0) && (pool->autoExpand == FILLP_TRUE) && (pool->currentSize < pool->maxSize) &&
218             (DympAskMoreMemory(pool, pool->initSize, throttleGrow) > 0)) {
219             continue;
220         }
221 
222         break;
223     }
224 
225     if (ret <= 0) {
226         return ERR_NOBUFS;
227     }
228 
229     *data = (char *)tmp + sizeof(DympItemType);
230     return ERR_OK;
231 }
232 
DympFree(void * data)233 void DympFree(void *data)
234 {
235     DympItemType *item = FILLP_NULL_PTR;
236     if (data == FILLP_NULL_PTR) {
237         return;
238     }
239 
240     item = (DympItemType *)DYMP_GET_ITEM_FROM_DATA(data);
241     if (FillpQueuePush(item->mp, (void *)&item, FILLP_FALSE, 1) != ERR_OK) {
242         FILLP_LOGWAR("Mem Pool free enqueue Error \n");
243         return;
244     }
245 
246     return;
247 }
248 
249 #ifdef __cplusplus
250 }
251 #endif
252