1 /*
2  * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF)
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD
7  */
8 /*
9  * Licensed to the Apache Software Foundation (ASF) under one
10  * or more contributor license agreements.  See the NOTICE file
11  * distributed with this work for additional information
12  * regarding copyright ownership.  The ASF licenses this file
13  * to you under the Apache License, Version 2.0 (the
14  * "License"); you may not use this file except in compliance
15  * with the License.  You may obtain a copy of the License at
16  *
17  *  http://www.apache.org/licenses/LICENSE-2.0
18  *
19  * Unless required by applicable law or agreed to in writing,
20  * software distributed under the License is distributed on an
21  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22  * KIND, either express or implied.  See the License for the
23  * specific language governing permissions and limitations
24  * under the License.
25  */
26 
27 /**
28  * @addtogroup OSKernel
29  * @{
30  *   @defgroup OSMempool Memory Pools
31  *   @{
32  */
33 
34 
35 #ifndef _OS_MEMPOOL_H_
36 #define _OS_MEMPOOL_H_
37 
38 #include <stdbool.h>
39 #include "os/os.h"
40 
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44 
45 /**
46  * A memory block structure. This simply contains a pointer to the free list
47  * chain and is only used when the block is on the free list. When the block
48  * has been removed from the free list the entire memory block is usable by the
49  * caller.
50  */
51 struct os_memblock {
52     SLIST_ENTRY(os_memblock) mb_next;
53 };
54 
55 /* XXX: Change this structure so that we keep the first address in the pool? */
56 /* XXX: add memory debug structure and associated code */
57 /* XXX: Change how I coded the SLIST_HEAD here. It should be named:
58    SLIST_HEAD(,os_memblock) mp_head; */
59 
60 /**
61  * Memory pool
62  */
63 struct os_mempool {
64     /** Size of the memory blocks, in bytes. */
65     uint32_t mp_block_size;
66     /** The number of memory blocks. */
67     uint16_t mp_num_blocks;
68     /** The number of free blocks left */
69     uint16_t mp_num_free;
70     /** The lowest number of free blocks seen */
71     uint16_t mp_min_free;
72     /** Bitmap of OS_MEMPOOL_F_[...] values. */
73     uint8_t mp_flags;
74     /** Address of memory buffer used by pool */
75     uint32_t mp_membuf_addr;
76     STAILQ_ENTRY(os_mempool) mp_list;
77     SLIST_HEAD(,os_memblock);
78     /** Name for memory block */
79     const char *name;
80 };
81 
82 /**
83  * Indicates an extended mempool.  Address can be safely cast to
84  * (struct os_mempool_ext *).
85  */
86 #define OS_MEMPOOL_F_EXT        0x01
87 
88 struct os_mempool_ext;
89 
90 /**
91  * Block put callback function.  If configured, this callback gets executed
92  * whenever a block is freed to the corresponding extended mempool.  Note: The
93  * os_memblock_put() function calls this callback instead of freeing the block
94  * itself.  Therefore, it is the callback's responsibility to free the block
95  * via a call to os_memblock_put_from_cb().
96  *
97  * @param ome                   The extended mempool that a block is being
98  *                                  freed back to.
99  * @param data                  The block being freed.
100  * @param arg                   Optional argument configured along with the
101  *                                  callback.
102  *
103  * @return                      Indicates whether the block was successfully
104  *                                  freed.  A non-zero value should only be
105  *                                  returned if the block was not successfully
106  *                                  released back to its pool.
107  */
108 typedef os_error_t os_mempool_put_fn(struct os_mempool_ext *ome, void *data,
109                                      void *arg);
110 
111 struct os_mempool_ext {
112     struct os_mempool mpe_mp;
113 
114     /* Callback that is executed immediately when a block is freed. */
115     os_mempool_put_fn *mpe_put_cb;
116     void *mpe_put_arg;
117 };
118 
119 #define OS_MEMPOOL_INFO_NAME_LEN (32)
120 
121 /**
122  * Information describing a memory pool, used to return OS information
123  * to the management layer.
124  */
125 struct os_mempool_info {
126     /** Size of the memory blocks in the pool */
127     int omi_block_size;
128     /** Number of memory blocks in the pool */
129     int omi_num_blocks;
130     /** Number of free memory blocks */
131     int omi_num_free;
132     /** Minimum number of free memory blocks ever */
133     int omi_min_free;
134     /** Name of the memory pool */
135     char omi_name[OS_MEMPOOL_INFO_NAME_LEN];
136 };
137 
138 /**
139  * Get information about the next system memory pool.
140  *
141  * @param mempool The current memory pool, or NULL if starting iteration.
142  * @param info    A pointer to the structure to return memory pool information
143  *                into.
144  *
145  * @return The next memory pool in the list to get information about, or NULL
146  *         when at the last memory pool.
147  */
148 struct os_mempool *os_mempool_info_get_next(struct os_mempool *,
149                                             struct os_mempool_info *);
150 
151 #if (OS_ALIGNMENT == 4)
152 typedef uint32_t os_membuf_t;
153 #elif (OS_ALIGNMENT == 8)
154 typedef uint64_t os_membuf_t;
155 #elif (OS_ALIGNMENT == 16)
156 typedef __uint128_t os_membuf_t;
157 #else
158 #error "Unhandled `OS_ALIGNMENT` for `os_membuf_t`"
159 #endif /* OS_ALIGNMENT == * */
160 #define OS_MEMPOOL_SIZE(n,blksize)      ((((blksize) + ((OS_ALIGNMENT)-1)) / (OS_ALIGNMENT)) * (n))
161 
162 /** Calculates the number of bytes required to initialize a memory pool. */
163 #define OS_MEMPOOL_BYTES(n,blksize)     \
164     (sizeof (os_membuf_t) * OS_MEMPOOL_SIZE((n), (blksize)))
165 
166 #if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED
167 /**
168  * Initialize a memory pool.
169  *
170  * @param mp            Pointer to a pointer to a mempool
171  * @param blocks        The number of blocks in the pool
172  * @param blocks_size   The size of the block, in bytes.
173  * @param membuf        Pointer to memory to contain blocks.
174  * @param name          Name of the pool.
175  *
176  * @return os_error_t
177  */
178 os_error_t r_os_mempool_init(struct os_mempool *mp, uint16_t blocks,
179                            uint32_t block_size, void *membuf, const char *name);
180 #define os_mempool_init r_os_mempool_init
181 /**
182  * Initializes an extended memory pool.  Extended attributes (e.g., callbacks)
183  * are not specified when this function is called; they are assigned manually
184  * after initialization.
185  *
186  * @param mpe           The extended memory pool to initialize.
187  * @param blocks        The number of blocks in the pool.
188  * @param block_size    The size of each block, in bytes.
189  * @param membuf        Pointer to memory to contain blocks.
190  * @param name          Name of the pool.
191  *
192  * @return os_error_t
193  */
194 os_error_t r_os_mempool_ext_init(struct os_mempool_ext *mpe, uint16_t blocks,
195                                uint32_t block_size, void *membuf, const char *name);
196 #define os_mempool_ext_init r_os_mempool_ext_init
197 /**
198  * Removes the specified mempool from the list of initialized mempools.
199  *
200  * @param mp                    The mempool to unregister.
201  *
202  * @return                      0 on success;
203  *                              OS_INVALID_PARM if the mempool is not
204  *                                  registered.
205  */
206 os_error_t r_os_mempool_unregister(struct os_mempool *mp);
207 #define os_mempool_unregister r_os_mempool_unregister
208 
209 
210 /**
211  * Clears a memory pool.
212  *
213  * @param mp            The mempool to clear.
214  *
215  * @return os_error_t
216  */
217 os_error_t r_os_mempool_clear(struct os_mempool *mp);
218 #define os_mempool_clear r_os_mempool_clear
219 
220 
221 /**
222  * Performs an integrity check of the specified mempool.  This function
223  * attempts to detect memory corruption in the specified memory pool.
224  *
225  * @param mp                    The mempool to check.
226  *
227  * @return                      true if the memory pool passes the integrity
228  *                                  check;
229  *                              false if the memory pool is corrupt.
230  */
231 bool r_os_mempool_is_sane(const struct os_mempool *mp);
232 #define os_mempool_is_sane r_os_mempool_is_sane
233 
234 
235 /**
236  * Checks if a memory block was allocated from the specified mempool.
237  *
238  * @param mp                    The mempool to check as parent.
239  * @param block_addr            The memory block to check as child.
240  *
241  * @return                      0 if the block does not belong to the mempool;
242  *                              1 if the block does belong to the mempool.
243  */
244 int r_os_memblock_from(const struct os_mempool *mp, const void *block_addr);
245 #define os_memblock_from r_os_memblock_from
246 
247 
248 /**
249  * Get a memory block from a memory pool
250  *
251  * @param mp Pointer to the memory pool
252  *
253  * @return void* Pointer to block if available; NULL otherwise
254  */
255 void *r_os_memblock_get(struct os_mempool *mp);
256 #define os_memblock_get r_os_memblock_get
257 /**
258  * Puts the memory block back into the pool, ignoring the put callback, if any.
259  * This function should only be called from a put callback to free a block
260  * without causing infinite recursion.
261  *
262  * @param mp Pointer to memory pool
263  * @param block_addr Pointer to memory block
264  *
265  * @return os_error_t
266  */
267 os_error_t r_os_memblock_put_from_cb(struct os_mempool *mp, void *block_addr);
268 #define os_memblock_put_from_cb r_os_memblock_put_from_cb
269 
270 
271 /**
272  * Puts the memory block back into the pool
273  *
274  * @param mp Pointer to memory pool
275  * @param block_addr Pointer to memory block
276  *
277  * @return os_error_t
278  */
279 os_error_t r_os_memblock_put(struct os_mempool *mp, void *block_addr);
280 #define os_memblock_put r_os_memblock_put
281 
282 #else
283 /**
284  * Initialize a memory pool.
285  *
286  * @param mp            Pointer to a pointer to a mempool
287  * @param blocks        The number of blocks in the pool
288  * @param blocks_size   The size of the block, in bytes.
289  * @param membuf        Pointer to memory to contain blocks.
290  * @param name          Name of the pool.
291  *
292  * @return os_error_t
293  */
294 os_error_t os_mempool_init(struct os_mempool *mp, uint16_t blocks,
295                            uint32_t block_size, void *membuf, const char *name);
296 
297 /**
298  * Initializes an extended memory pool.  Extended attributes (e.g., callbacks)
299  * are not specified when this function is called; they are assigned manually
300  * after initialization.
301  *
302  * @param mpe           The extended memory pool to initialize.
303  * @param blocks        The number of blocks in the pool.
304  * @param block_size    The size of each block, in bytes.
305  * @param membuf        Pointer to memory to contain blocks.
306  * @param name          Name of the pool.
307  *
308  * @return os_error_t
309  */
310 os_error_t os_mempool_ext_init(struct os_mempool_ext *mpe, uint16_t blocks,
311                                uint32_t block_size, void *membuf, const char *name);
312 
313 /**
314  * Removes the specified mempool from the list of initialized mempools.
315  *
316  * @param mp                    The mempool to unregister.
317  *
318  * @return                      0 on success;
319  *                              OS_INVALID_PARM if the mempool is not
320  *                                  registered.
321  */
322 os_error_t os_mempool_unregister(struct os_mempool *mp);
323 
324 /**
325  * Clears a memory pool.
326  *
327  * @param mp            The mempool to clear.
328  *
329  * @return os_error_t
330  */
331 os_error_t os_mempool_clear(struct os_mempool *mp);
332 
333 /**
334  * Clears an extended memory pool.
335  *
336  * @param mpe            The extended memory pool to clear.
337  *
338  * @return os_error_t
339  */
340 os_error_t os_mempool_ext_clear(struct os_mempool_ext *mpe);
341 
342 /**
343  * Performs an integrity check of the specified mempool.  This function
344  * attempts to detect memory corruption in the specified memory pool.
345  *
346  * @param mp                    The mempool to check.
347  *
348  * @return                      true if the memory pool passes the integrity
349  *                                  check;
350  *                              false if the memory pool is corrupt.
351  */
352 bool os_mempool_is_sane(const struct os_mempool *mp);
353 
354 /**
355  * Checks if a memory block was allocated from the specified mempool.
356  *
357  * @param mp                    The mempool to check as parent.
358  * @param block_addr            The memory block to check as child.
359  *
360  * @return                      0 if the block does not belong to the mempool;
361  *                              1 if the block does belong to the mempool.
362  */
363 int os_memblock_from(const struct os_mempool *mp, const void *block_addr);
364 
365 /**
366  * Get a memory block from a memory pool
367  *
368  * @param mp Pointer to the memory pool
369  *
370  * @return void* Pointer to block if available; NULL otherwise
371  */
372 void *os_memblock_get(struct os_mempool *mp);
373 
374 /**
375  * Puts the memory block back into the pool, ignoring the put callback, if any.
376  * This function should only be called from a put callback to free a block
377  * without causing infinite recursion.
378  *
379  * @param mp Pointer to memory pool
380  * @param block_addr Pointer to memory block
381  *
382  * @return os_error_t
383  */
384 os_error_t os_memblock_put_from_cb(struct os_mempool *mp, void *block_addr);
385 
386 /**
387  * Puts the memory block back into the pool
388  *
389  * @param mp Pointer to memory pool
390  * @param block_addr Pointer to memory block
391  *
392  * @return os_error_t
393  */
394 os_error_t os_memblock_put(struct os_mempool *mp, void *block_addr);
395 #endif
396 
397 #ifdef __cplusplus
398 }
399 #endif
400 
401 #endif  /* _OS_MEMPOOL_H_ */
402 
403 
404 /**
405  *   @} OSMempool
406  * @} OSKernel
407  */
408