le_mem.h

Go to the documentation of this file.
1 /**
2  * @page c_memory Dynamic Memory Allocation API
3  *
4  *
5  * @subpage le_mem.h "API Reference"
6  *
7  * <HR>
8  *
9  * Dynamic memory allocation (especially deallocation) using the C runtime heap, through
10  * malloc, free, strdup, calloc, realloc, etc. can result in performance degradation and out-of-memory
11  * conditions.
12  *
13  * This is due to fragmentation of the heap. The degraded performance and exhausted memory result from indirect interactions
14  * within the heap between unrelated application code. These issues are non-deterministic,
15  * and can be very difficult to rectify.
16  *
17  * Memory Pools offer a powerful solution. They trade-off a deterministic amount of
18  * memory for
19  * - deterministic behaviour,
20  * - O(1) allocation and release performance, and
21  * - built-in memory allocation tracking.
22  *
23  * And it brings the power of @b destructors to C!
24  *
25  * @todo
26  * Do we need to add a "resettable heap" option to the memory management tool kit?
27  *
28  *
29  * @section mem_overview Overview
30  *
31  * The most basic usage involves:
32  * - Creating a pool (usually done once at process start-up)
33  * - Allocating objects (memory blocks) from a pool
34  * - Releasing objects back to their pool.
35  *
36  * Pools generally can't be deleted. You create them when your process
37  * starts-up, and use them until your process terminates. It's up to the OS to clean-up the memory
38  * pools, along with everything else your process is using, when your process terminates. (Although,
39  * if you find yourself really needing to delete pools, @ref mem_sub_pools could offer you a solution.)
40  *
41  * Pools also support the following advanced features:
42  * - reference counting
43  * - destructors
44  * - statistics
45  * - multi-threading
46  * - sub-pools (pools that can be deleted).
47  *
48  * The following sections describe these, beginning with the most basic usage and working up to more
49  * advanced topics.
50  *
51  *
52  * @section mem_creating Creating a Pool
53  *
54  * Before allocating memory from a pool, the pool must be created using le_mem_CreatePool(), passing
55  * it the name of the pool and the size of the objects to be allocated from that pool. This returns
56  * a reference to the new pool, which has zero free objects in it.
57  *
58  * To populate your new pool with free objects, you call @c le_mem_ExpandPool().
59  * This is separated into two functions (rather than having
60  * one function with three parameters) to make it virtually impossible to accidentally get the parameters
61  * in the wrong order (which would result in nasty bugs that couldn't be caught by the compiler).
62  * The ability to expand pools comes in handy (see @ref mem_pool_sizes).
63  *
64  * This code sample defines a class "Point" and a pool "PointPool" used to
65  * allocate memory for objects of that class:
66  * @code
67  * #define MAX_POINTS 12 // Maximum number of points that can be handled.
68  *
69  * typedef struct
70  * {
71  * int x; // pixel position along x-axis
72  * int y; // pixel position along y-axis
73  * }
74  * Point_t;
75  *
76  * le_mem_PoolRef_t PointPool;
77  *
78  * int xx_pt_ProcessStart(void)
79  * {
80  * PointPool = le_mem_CreatePool("xx.pt.Points", sizeof(Point_t));
81  * le_mem_ExpandPool(PointPool, MAX_POINTS);
82  *
83  * return SUCCESS;
84  * }
85  * @endcode
86  *
87  * To make things easier for power-users, @c le_mem_ExpandPool() returns the same pool
88  * reference that it was given. This allows the xx_pt_ProcessStart() function to be re-implemented
89  * as follows:
90  * @code
91  * int xx_pt_ProcessStart(void)
92  * {
93  * PointPool = le_mem_ExpandPool(le_mem_CreatePool(sizeof(Point_t)), MAX_POINTS);
94  *
95  * return SUCCESS;
96  * }
97  * @endcode
98  *
99  * Although this requires a dozen or so fewer keystrokes of typing and occupies one less line
100  * of code, it's arguably less readable than the previous example.
101  *
102  * For a discussion on how to pick the number of objects to have in your pools, see @ref mem_pool_sizes.
103  *
104  * @section mem_allocating Allocating From a Pool
105  *
106  * Allocating from a pool has multiple options:
107  * - @c le_mem_TryAlloc() - Quietly return NULL if there are no free blocks in the pool.
108  * - @c le_mem_AssertAlloc() - Log an error and take down the process if there are no free blocks in
109  * the pool.
110  * - @c le_mem_ForceAlloc() - If there are no free blocks in the pool, log a warning and automatically
111  * expand the pool (or log an error and terminate the calling process there's
112  * not enough free memory to expand the pool).
113  *
114  * All of these functions take a pool reference and return a pointer to the object
115  * allocated from the pool.
116  *
117  * The first option, using @c le_mem_TryAlloc(), is the
118  * closest to the way good old malloc() works. It requires the caller check the
119  * return code to see if it's NULL. This can be annoying enough that a lot of
120  * people get lazy and don't check the return code (Bad programmer! Bad!). It turns out that
121  * this option isn't really what people usually want (but occasionally they do)
122  *
123  * The second option, using @c le_mem_AssertAlloc(), is only used when the allocation should
124  * never fail, by design; a failure to allocate a block is a fatal error.
125  * This isn't often used, but can save a lot of boilerplate error checking code.
126  *
127  * The third option, @c using le_mem_ForceAlloc(), is the one that gets used most often.
128  * It allows developers to avoid writing error checking code, because the allocation will
129  * essentially never fail because it's handled inside the memory allocator. It also
130  * allows developers to defer fine tuning their pool sizes until after they get things working.
131  * Later, they check the logs for pool size usage, and then modify their pool sizes accordingly.
132  * If a particular pool is continually growing, it's a good indication there's a
133  * memory leak. This permits seeing exactly what objects are being leaked. If certain debug
134  * options are turned on, they can even find out which line in which file allocated the blocks
135  * being leaked.
136  *
137  *
138  * @section mem_releasing Releasing Back Into a Pool
139  *
140  * Releasing memory back to a pool never fails, so there's no need to check a return code.
141  * Also, each object knows which pool it came from, so the code that releases the object doesn't have to care.
142  * All it has to do is call @c le_mem_Release() and pass a pointer to the object to be released.
143  *
144  * The critical thing to remember is that once an object has been released, it
145  * <b> must never be accessed again </b>. Here is a <b> very bad code example</b>:
146  * @code
147  * Point_t* pointPtr = le_mem_ForceAlloc(PointPool);
148  * pointPtr->x = 5;
149  * pointPtr->y = 10;
150  * le_mem_Release(pointPtr);
151  * printf("Point is at position (%d, %d).\n", pointPtr->x, pointPtr->y);
152  * @endcode
153  *
154  *
155  * @section mem_ref_counting Reference Counting
156  *
157  * Reference counting is a powerful feature of our memory pools. Here's how it works:
158  * - Every object allocated from a pool starts with a reference count of 1.
159  * - Whenever someone calls le_mem_AddRef() on an object, its reference count is incremented by 1.
160  * - When it's released, its reference count is decremented by 1.
161  * - When its reference count reaches zero, it's destroyed (i.e., its memory is released back into the pool.)
162  *
163  * This allows one function to:
164  * - create an object.
165  * - work with it.
166  * - increment its reference count and pass a pointer to the object to another function (or thread, data structure, etc.).
167  * - work with it some more.
168  * - release the object without having to worry about when the other function is finished with it.
169  *
170  * The other function also releases the object when it's done with it. So, the object will
171  * exist until both functions are done.
172  *
173  * If there are multiple threads involved, be careful to protect the shared
174  * object from race conditions(see the @ref mem_threading).
175  *
176  * Another great advantage of reference counting is it enables @ref mem_destructors.
177  *
178  * @note le_mem_GetRefCount() can be used to check the current reference count on an object.
179  *
180  * @section mem_destructors Destructors
181  *
182  * Destructors are a powerful feature of C++. Anyone who has any non-trivial experience with C++ has
183  * used them. Because C was created before object-oriented programming was around, there's
184  * no native language support for destructors in C. Object-oriented design is still possible
185  * and highly desireable even when the programming is done in C.
186  *
187  * In Legato, it's possible to call @c le_mem_SetDestructor() to attach a function to a memory pool
188  * to be used as a destructor for objects allocated from that pool. If a pool has a destructor,
189  * whenever the reference count reaches zero for an object allocated from that pool,
190  * the pool's destructor function will pass a pointer to that object. After
191  * the destructor returns, the object will be fully destroyed, and its memory will be released back
192  * into the pool for later reuse by another object.
193  *
194  * Here's a destructor code sample:
195  * @code
196  * static void PointDestructor(void* objPtr)
197  * {
198  * Point_t* pointPtr = objPtr;
199  *
200  * printf("Destroying point (%d, %d)\n", pointPtr->x, pointPtr->y);
201  *
202  * @todo Add more to sample.
203  * }
204  *
205  * int xx_pt_ProcessStart(void)
206  * {
207  * PointPool = le_mem_CreatePool(sizeof(Point_t));
208  * le_mem_ExpandPool(PointPool, MAX_POINTS);
209  * le_mem_SetDestructor(PointPool, PointDestructor);
210  * return SUCCESS;
211  * }
212  *
213  * static void DeletePointList(Point_t** pointList, size_t numPoints)
214  * {
215  * size_t i;
216  * for (i = 0; i < numPoints; i++)
217  * {
218  * le_mem_Release(pointList[i]);
219  * }
220  * }
221  * @endcode
222  *
223  * In this sample, when DeletePointList() is called (with a pointer to an array of pointers
224  * to Point_t objects with reference counts of 1), each of the objects in the pointList is
225  * released. This causes their reference counts to hit 0, which triggers executing
226  * PointDestructor() for each object in the pointList, and the "Destroying point..." message will
227  * be printed for each.
228  *
229  *
230  * @section mem_stats Statistics
231  *
232  * Some statistics are gathered for each memory pool:
233  * - Number of allocations.
234  * - Number of currently free objects.
235  * - Number of overflows (times that le_mem_ForceAlloc() had to expand the pool).
236  *
237  * Statistics (and other pool properties) can be checked using functions:
238  * - @c le_mem_GetStats()
239  * - @c le_mem_GetObjectCount()
240  * - @c le_mem_GetObjectSize()
241  *
242  * Statistics are fetched together atomically using a single function call.
243  * This prevents inconsistencies between them if in a multi-threaded program.
244  *
245  * If you don't have a reference to a specified pool, but you have the name of the pool, you can
246  * get a reference to the pool using @c le_mem_FindPool().
247  *
248  * In addition to programmatically fetching these, they're also available through the
249  * "poolstat" console command (unless your process's main thread is blocked).
250  *
251  * To reset the pool statistics, use @c le_mem_ResetStats().
252  *
253  * @section mem_diagnostics Diagnostics
254  *
255  * The memory system also supports two different forms of diagnostics. Both are enabled by setting
256  * the appropriate KConfig options when building the framework.
257  *
258  * The first of these options is @ref MEM_TRACE. When you enable @ref MEM_TRACE every pool is given
259  * a tracepoint with the name of the pool on creation.
260  *
261  * For instance, the configTree node pool is called, "configTree.nodePool". So to enable a trace of
262  * all config tree node creation and deletion one would use the log tool as follows:
263  *
264  * @code
265  * $ log trace configTree.nodePool
266  * @endcode
267  *
268  * The second diagnostic build flag is @ref MEM_POOLS. When @ref MEM_POOLS is disabled, the pools
269  * are disabled and instead malloc and free are directly used. Thus enabling the use of tools
270  * like Valgrind.
271  *
272  * @section mem_threading Multi-Threading
273  *
274  * All functions in this API are <b> thread-safe, but not async-safe </b>. The objects
275  * allocated from pools are not inherently protected from races between threads.
276  *
277  * Allocating and releasing objects, checking stats, incrementing reference
278  * counts, etc. can all be done from multiple threads (excluding signal handlers) without having
279  * to worry about corrupting the memory pools' hidden internal data structures.
280  *
281  * There's no magical way to prevent different threads from interferring with each other
282  * if they both access the @a contents of the same object at the same time.
283  *
284  * The best way to prevent multi-threaded race conditions is simply don't share data between
285  * threads. If multiple threads must access the same data structure, then mutexes, semaphores,
286  * or similar methods should be used to @a synchronize threads and avoid
287  * data structure corruption or thread misbehaviour.
288  *
289  * Although memory pools are @a thread-safe, they are not @a async-safe. This means that memory pools
290  * @a can be corrupted if they are accessed by a signal handler while they are being accessed
291  * by a normal thread. To be safe, <b> don't call any memory pool functions from within a signal handler. </b>
292  *
293  * One problem using destructor functions in a
294  * multi-threaded environment is that the destructor function modifies a data structure shared
295  * between threads, so it's easy to forget to synchronize calls to @c le_mem_Release() with other code
296  * accessing the data structure. If a mutex is used to coordinate access to
297  * the data structure, then the mutex must be held by the thread that calls le_mem_Release() to
298  * ensure there's no other thread accessing the data structure when the destructor runs.
299  *
300  * @section mem_pool_sizes Managing Pool Sizes
301  *
302  * We know it's possible to have pools automatically expand
303  * when they are exhausted, but we don't really want that to happen normally.
304  * Ideally, the pools should be fully allocated to their maximum sizes at start-up so there aren't
305  * any surprises later when certain feature combinations cause the
306  * system to run out of memory in the field. If we allocate everything we think
307  * is needed up-front, then we are much more likely to uncover any memory shortages during
308  * testing, before it's in the field.
309  *
310  * Choosing the right size for your pools correctly at start-up is easy to do if there is a maximum
311  * number of fixed, external @a things that are being represented by the objects being allocated
312  * from the pool. If the pool holds "call objects" representing phone calls over a T1
313  * carrier that will never carry more than 24 calls at a time, then it's obvious that you need to
314  * size your call object pool at 24.
315  *
316  * Other times, it's not so easy to choose the pool size like
317  * code to be reused in different products or different configurations that have different
318  * needs. In those cases, you still have a few options:
319  *
320  * - At start-up, query the operating environment and base the pool sizes.
321  * - Read a configuration setting from a file or other configuration data source.
322  * - Use a build-time configuration setting.
323  *
324  * The build-time configuration setting is the easiest, and generally requires less
325  * interaction between components at start-up simplifying APIs
326  * and reducing boot times.
327  *
328  * If the pool size must be determined at start-up, use @c le_mem_ExpandPool().
329  * Perhaps there's a service-provider module designed to allocate objects on behalf
330  * of client. It can have multiple clients at the same time, but it doesn't know how many clients
331  * or what their resource needs will be until the clients register with it at start-up. We'd want
332  * those clients to be as decoupled from each other as possible (i.e., we want the clients know as little
333  * as possible about each other); we don't want the clients to get together and add up all
334  * their needs before telling the service-provider. We'd rather have the clients independently
335  * report their own needs to the service-provider. Also, we don't want each client to have to wait
336  * for all the other clients to report their needs before starting to use
337  * the services offered by the service-provider. That would add more complexity to the interactions
338  * between the clients and the service-provider.
339  *
340  * This is what should happen when the service-provider can't wait for all clients
341  * to report their needs before creating the pool:
342  * - When the service-provider starts up, it creates an empty pool.
343  * - Whenever a client registers itself with the service-provider, the client can tell the
344  * service-provider what its specific needs are, and the service-provider can expand its
345  * object pool accordingly.
346  * - Since registrations happen at start-up, pool expansion occurs
347  * at start-up, and testing will likely find any pool sizing before going into the field.
348  *
349  * Where clients dynamically start and stop during runtime in response
350  * to external events (e.g., when someone is using the device's Web UI), we still have
351  * a problem because we can't @a shrink pools or delete pools when clients go away. This is where
352  * @ref mem_sub_pools is useful.
353  *
354  * @section mem_sub_pools Sub-Pools
355  *
356  * Essentially, a Sub-Pool is a memory pool that gets its blocks from another pool (the super-pool).
357  * Sub Pools @a can be deleted, causing its blocks to be released back into the super-pool.
358  *
359  * This is useful when a service-provider module needs to handle clients that
360  * dynamically pop into existence and later disappear again. When a client attaches to the service
361  * and says it will probably need a maximum of X of the service-provider's resources, the
362  * service provider can set aside that many of those resources in a sub-pool for that client.
363  * If that client goes over its limit, the sub-pool will log a warning message.
364  *
365  * The problem of sizing the super-pool correctly at start-up still exists,
366  * so what's the point of having a sub-pool, when all of the resources could just be allocated from
367  * the super-pool?
368  *
369  * The benefit is really gained in troubleshooting. If client A, B, C, D and E are
370  * all behaving nicely, but client F is leaking resources, the sub-pool created
371  * on behalf of client F will start warning about the memory leak; time won't have to be
372  * wasted looking at clients A through E to rule them out.
373  *
374  * A visual side effect of using sub-pools is that their blocks will count as being in use by the
375  * super-pool but they will not count as allocations of the super-pool.
376  *
377  * To create a sub-pool, call @c le_mem_CreateSubPool(). It takes a reference to the super-pool
378  * and the number of objects to move to the sub-pool, and it returns a reference to the new sub-pool.
379  *
380  * To delete a sub-pool, call @c le_mem_DeleteSubPool(). Do not try to use it to delete a pool that
381  * was created using le_mem_CreatePool(). It's only for sub-pools created using le_mem_CreateSubPool().
382  * Also, it's @b not okay to delete a sub-pool while there are still blocks allocated from it, or
383  * if it has any sub-pools. You'll see errors in your logs if you do that.
384  *
385  * Sub-Pools automatically inherit their parent's destructor function.
386  *
387  * @section mem_reduced_pools Reduced-size pools
388  *
389  * One problem that occurs with memory pools is where objects of different sizes need to be
390  * stored. A classic example is strings -- the longest string an application needs to be able
391  * to handle may be much longer than the typical string size. In this case a lot of memory
392  * will be wasted with standard memory pools, since all objects allocated from the pool will
393  * be the size of the longest possible object.
394  *
395  * The solution is to use reduced-size pools. These are a kind of sub-pool where the size
396  * of the object in the sub-pool is different from the size of the object in the super-pool.
397  * This way multiple blocks from the sub-pool can be stored in a single block of the super-pool.
398  *
399  * Reduced-size pools have some limitations:
400  *
401  * - Each block in the super-pool is divided up to create blocks in the subpool. So subpool
402  * blocks sizes must be less than half the size of the super-pool block size. An attempt to
403  * create a pool with a larger block size will just return a reference to the super-pool.
404  * - Due overhead, each block actually requires 8-80 bytes more space than requested.
405  * There is little point in subdividing pools < 4x overhead, or ~300 bytes in the default
406  * configuration. Note the exact amount of overhead depends on the size of the guard bands
407  * and the size of pointer on your target.
408  * - Blocks used by the reduced pool are permanently moved from the super-pool to the reduced
409  * pool. This must be taken into account when sizing the super-pool.
410  *
411  * Example 1:
412  *
413  * A network service needs to allocate space for packets received over a network. It should
414  * Typical packet length is up to 200 bytes, but occasional packets may be up to 1500 bytes. The
415  * service needs to be able to queue at least 32 packets, up to 5 of which can be 1500 bytes.
416  * Two pools are used: A pool of 12 objects 1500 bytes in size, and a reduced-size pool of 32
417  * objects 200 bytes in size (280 bytes with overhead). Seven objects from the superpool are
418  * used to store reduced-size objects. This represents a memory savings of 60% compared with
419  * a pool of 32 1500 byte objects.
420  *
421  * Example 2:
422  *
423  * An application builds file paths which can be from 16-70 bytes. Only three such paths can be
424  * created at a time, but they can be any size. In this case it is better to just create
425  * a single pool of three 70-byte objects. Most of the potential space gains would be consumed
426  * by overhead. Even if this was not the case, the super pool still needs three free objects
427  * in addition to the objects required by the subpool, so there is no space savings.
428  *
429  * To create a reduced-size pool, use @c le_mem_CreateReducedPool(). It takes a reference to the
430  * super-pool, the initial number of objects in the sub-pool, and size of an object in the sub-pool
431  * compared with the parent pool, and it returns a reference to the new sub-pool.
432  *
433  * Reduced-size pools are deleted using @c le_mem_DeleteSubPool() like other sub-pools.
434  *
435  * To help the programmer pick the right pool to allocate from, reduced-size pools provide
436  * @c le_mem_TryVarAlloc(), @c le_mem_AssertVarAlloc() and @c le_mem_ForceVarAlloc() functions.
437  * In addition to the pool these take the object size to allocate. If this size is larger than
438  * the pool's object size and the pool is a reduced-size pool, and there is a parent pool
439  * large enough for this object, it will allocate the object from the parent pool instead.
440  * If no parent pool is large enough, the program will exit.
441  *
442  * You can call @c le_mem_GetBlockSize() to get the actual size of the object returned by
443  * one of these functions.
444  *
445  * As with other sub-pools, they cannot be deleted while any blocks are allocated from the pool,
446  * or it has any sub-pools. Reduced-size pools also automatically inherit their parent's
447  * destructor function.
448  *
449  * <HR>
450  *
451  * Copyright (C) Sierra Wireless Inc.
452  */
453 
454 //--------------------------------------------------------------------------------------------------
455 /** @file le_mem.h
456  *
457  * Legato @ref c_memory include file.
458  *
459  * Copyright (C) Sierra Wireless Inc.
460  *
461  */
462 //--------------------------------------------------------------------------------------------------
463 
464 #ifndef LEGATO_MEM_INCLUDE_GUARD
465 #define LEGATO_MEM_INCLUDE_GUARD
466 
467 #include "le_singlyLinkedList.h"
468 
469 #ifndef LE_COMPONENT_NAME
470 # define LE_COMPONENT_NAME
471 #endif
472 
473 //--------------------------------------------------------------------------------------------------
474 /**
475  * Prototype for destructor functions.
476  *
477  * @param objPtr Pointer to the object where reference count has reached zero. After the destructor
478  * returns this object's memory will be released back into the pool (and this pointer
479  * will become invalid).
480  *
481  * @return Nothing.
482  *
483  * See @ref mem_destructors for more information.
484  */
485 //--------------------------------------------------------------------------------------------------
486 typedef void (*le_mem_Destructor_t)
487 (
488  void* objPtr ///< see parameter documentation in comment above.
489 );
490 
491 // Max memory pool name bytes -- must match definition in limit.h
492 #define LE_MEM_LIMIT_MAX_MEM_POOL_NAME_BYTES 32
493 
494 //--------------------------------------------------------------------------------------------------
495 /**
496  * Definition of a memory pool.
497  *
498  * @note This should not be used directly. To create a memory pool use either le_mem_CreatePool()
499  * or LE_MEM_DEFINE_STATIC_POOL()/le_mem_InitStaticPool().
500  */
501 //--------------------------------------------------------------------------------------------------
502 typedef struct le_mem_Pool
503 {
504  le_dls_Link_t poolLink; ///< This pool's link in the list of memory pools.
505  struct le_mem_Pool* superPoolPtr; ///< A pointer to our super pool if we are a sub-pool. NULL
506  /// if we are not a sub-pool.
507 #if LE_CONFIG_MEM_POOL_STATS
508  // These members go before LE_CONFIG_MEM_POOLS so numAllocations will always be aligned, even on
509  // 32-bit architectures, even when LE_CONFIG_MEM_POOLS is not declared
510  size_t numOverflows; ///< Number of times le_mem_ForceAlloc() had to expand pool.
511  uint64_t numAllocations; ///< Total number of times an object has been allocated
512  /// from this pool.
513  size_t maxNumBlocksUsed; ///< Maximum number of allocated blocks at any one time.
514 #endif
515 #if LE_CONFIG_MEM_POOLS
516  le_sls_List_t freeList; ///< List of free memory blocks.
517 #endif
518 
519  size_t userDataSize; ///< Size of the object requested by the client in bytes.
520  size_t blockSize; ///< Number of bytes in a block, including all overhead.
521  size_t totalBlocks; ///< Total number of blocks in this pool including free
522  /// and allocated blocks.
523  size_t numBlocksInUse; ///< Number of currently allocated blocks.
524  size_t numBlocksToForce; ///< Number of blocks that is added when Force Alloc
525  /// expands the pool.
526 #if LE_CONFIG_MEM_TRACE
527  le_log_TraceRef_t memTrace; ///< If tracing is enabled, keeps track of a trace object
528  ///< for this pool.
529 #endif
530 
531  le_mem_Destructor_t destructor; ///< The destructor for objects in this pool.
532 #if LE_CONFIG_MEM_POOL_NAMES_ENABLED
533  char name[LE_MEM_LIMIT_MAX_MEM_POOL_NAME_BYTES]; ///< Name of the pool.
534 #endif
535 }
537 
538 
539 //--------------------------------------------------------------------------------------------------
540 /**
541  * Objects of this type are used to refer to a memory pool created using either
542  * le_mem_CreatePool() or le_mem_CreateSubPool().
543  */
544 //--------------------------------------------------------------------------------------------------
545 typedef struct le_mem_Pool* le_mem_PoolRef_t;
546 
547 
548 //--------------------------------------------------------------------------------------------------
549 /**
550  * List of memory pool statistics.
551  */
552 //--------------------------------------------------------------------------------------------------
553 typedef struct
554 {
555  size_t numBlocksInUse; ///< Number of currently allocated blocks.
556  size_t maxNumBlocksUsed; ///< Maximum number of allocated blocks at any one time.
557  size_t numOverflows; ///< Number of times le_mem_ForceAlloc() had to expand the pool.
558  uint64_t numAllocs; ///< Number of times an object has been allocated from this pool.
559  size_t numFree; ///< Number of free objects currently available in this pool.
560 }
562 
563 
564 #if LE_CONFIG_MEM_TRACE
565  //----------------------------------------------------------------------------------------------
566  /**
567  * Internal function used to retrieve a pool handle for a given pool block.
568  */
569  //----------------------------------------------------------------------------------------------
570  le_mem_PoolRef_t _le_mem_GetBlockPool
571  (
572  void* objPtr ///< [IN] Pointer to the object we're finding a pool for.
573  );
574 
575  typedef void* (*_le_mem_AllocFunc_t)(le_mem_PoolRef_t pool);
576 
577  //----------------------------------------------------------------------------------------------
578  /**
579  * Internal function used to call a memory allocation function and trace its call site.
580  */
581  //----------------------------------------------------------------------------------------------
582  void* _le_mem_AllocTracer
583  (
584  le_mem_PoolRef_t pool, ///< [IN] The pool activity we're tracing.
585  _le_mem_AllocFunc_t funcPtr, ///< [IN] Pointer to the mem function in question.
586  const char* poolFunction, ///< [IN] The pool function being called.
587  const char* file, ///< [IN] The file the call came from.
588  const char* callingfunction, ///< [IN] The function calling into the pool.
589  size_t line ///< [IN] The line in the function where the call
590  /// occurred.
591  );
592 
593  //----------------------------------------------------------------------------------------------
594  /**
595  * Internal function used to call a variable memory allocation function and trace its call site.
596  */
597  //----------------------------------------------------------------------------------------------
598  void* _le_mem_VarAllocTracer
599  (
600  le_mem_PoolRef_t pool, ///< [IN] The pool activity we're tracing.
601  size_t size, ///< [IN] The size of block to allocate
602  _le_mem_AllocFunc_t funcPtr, ///< [IN] Pointer to the mem function in question.
603  const char* poolFunction, ///< [IN] The pool function being called.
604  const char* file, ///< [IN] The file the call came from.
605  const char* callingfunction, ///< [IN] The function calling into the pool.
606  size_t line ///< [IN] The line in the function where the call
607  /// occurred.
608  );
609 
610  //----------------------------------------------------------------------------------------------
611  /**
612  * Internal function used to trace memory pool activity.
613  */
614  //----------------------------------------------------------------------------------------------
615  void _le_mem_Trace
616  (
617  le_mem_PoolRef_t pool, ///< [IN] The pool activity we're tracing.
618  const char* file, ///< [IN] The file the call came from.
619  const char* callingfunction, ///< [IN] The function calling into the pool.
620  size_t line, ///< [IN] The line in the function where the call
621  /// occurred.
622  const char* poolFunction, ///< [IN] The pool function being called.
623  void* blockPtr ///< [IN] Block allocated/freed.
624  );
625 #endif
626 
627 
628 /// @cond HIDDEN_IN_USER_DOCS
629 //--------------------------------------------------------------------------------------------------
630 /**
631  * Internal function used to implement le_mem_InitStaticPool() with automatic component scoping
632  * of pool names.
633  */
634 //--------------------------------------------------------------------------------------------------
635 le_mem_PoolRef_t _le_mem_InitStaticPool
636 (
637  const char* componentName, ///< [IN] Name of the component.
638  const char* name, ///< [IN] Name of the pool inside the component.
639  size_t numBlocks, ///< [IN] Number of members in the pool by default
640  size_t objSize, ///< [IN] Size of the individual objects to be allocated from this pool
641  /// (in bytes), e.g., sizeof(MyObject_t).
642  le_mem_Pool_t* poolPtr, ///< [IN] Pointer to pre-allocated pool header.
643  void* poolDataPtr ///< [IN] Pointer to pre-allocated pool data.
644 );
645 /// @endcond
646 
647 
648 #if LE_CONFIG_MEM_POOL_NAMES_ENABLED
649 //--------------------------------------------------------------------------------------------------
650 /** @cond HIDDEN_IN_USER_DOCS
651  *
652  * Internal function used to implement le_mem_CreatePool() with automatic component scoping
653  * of pool names.
654  */
655 //--------------------------------------------------------------------------------------------------
656 le_mem_PoolRef_t _le_mem_CreatePool
657 (
658  const char* componentName, ///< [IN] Name of the component.
659  const char* name, ///< [IN] Name of the pool inside the component.
660  size_t objSize ///< [IN] Size of the individual objects to be allocated from this pool
661  /// (in bytes), e.g., sizeof(MyObject_t).
662 );
663 /// @endcond
664 //--------------------------------------------------------------------------------------------------
665 /**
666  * Creates an empty memory pool.
667  *
668  * @return
669  * Reference to the memory pool object.
670  *
671  * @note
672  * On failure, the process exits, so you don't have to worry about checking the returned
673  * reference for validity.
674  */
675 //--------------------------------------------------------------------------------------------------
676 static inline le_mem_PoolRef_t le_mem_CreatePool
677 (
678  const char* name, ///< [IN] Name of the pool inside the component.
679  size_t objSize ///< [IN] Size of the individual objects to be allocated from this pool
680  /// (in bytes), e.g., sizeof(MyObject_t).
681 )
682 {
683  return _le_mem_CreatePool(STRINGIZE(LE_COMPONENT_NAME), name, objSize);
684 }
685 #else /* if not LE_CONFIG_MEM_POOL_NAMES_ENABLED */
686 //--------------------------------------------------------------------------------------------------
687 /** @cond HIDDEN_IN_USER_DOCS
688  *
689  * Internal function used to implement le_mem_CreatePool() with automatic component scoping
690  * of pool names.
691  */
692 //--------------------------------------------------------------------------------------------------
693 le_mem_PoolRef_t _le_mem_CreatePool
694 (
695  size_t objSize ///< [IN] Size of the individual objects to be allocated from this pool
696  /// (in bytes), e.g., sizeof(MyObject_t).
697 );
698 /// @endcond
699 //--------------------------------------------------------------------------------------------------
700 /**
701  * Creates an empty memory pool.
702  *
703  * @return
704  * Reference to the memory pool object.
705  *
706  * @note
707  * On failure, the process exits, so you don't have to worry about checking the returned
708  * reference for validity.
709  */
710 //--------------------------------------------------------------------------------------------------
711 LE_DECLARE_INLINE le_mem_PoolRef_t le_mem_CreatePool
712 (
713  const char* name, ///< [IN] Name of the pool inside the component.
714  size_t objSize ///< [IN] Size of the individual objects to be allocated from this pool
715  /// (in bytes), e.g., sizeof(MyObject_t).
716 )
717 {
718  LE_UNUSED(name);
719  return _le_mem_CreatePool(objSize);
720 }
721 #endif /* end LE_CONFIG_MEM_POOL_NAMES_ENABLED */
722 
723 //--------------------------------------------------------------------------------------------------
724 /**
725  * Number of words in a memory pool, given number of blocks and object size.
726  *
727  * @note Only used internally
728  */
729 //--------------------------------------------------------------------------------------------------
730 #define LE_MEM_POOL_WORDS(numBlocks, objSize) \
731  ((numBlocks)*(((sizeof(le_mem_Pool_t*) + sizeof(size_t)) /* sizeof(MemBlock_t) */ + \
732  (((objSize)<sizeof(le_sls_Link_t))?sizeof(le_sls_Link_t):(objSize))+ \
733  sizeof(uint32_t)*LE_CONFIG_NUM_GUARD_BAND_WORDS*2+ \
734  sizeof(size_t) - 1) / sizeof(size_t)))
735 
736 //--------------------------------------------------------------------------------------------------
737 /**
738  * Calculate the number of blocks for a pool.
739  *
740  * @param name Pool name.
741  * @param def Default number of blocks.
742  *
743  * @return Number of blocks, either the value provided by <name>_POOL_SIZE if it is defined, or
744  * <def>. To be valid, <name>_POOL_SIZE must be defined as ,<value> (note the leading
745  * comma).
746  */
747 //--------------------------------------------------------------------------------------------------
748 #define LE_MEM_BLOCKS(name, def) (LE_DEFAULT(CAT(_mem_, CAT(name, _POOL_SIZE)), (def)))
749 
750 //--------------------------------------------------------------------------------------------------
751 /**
752  * Declare variables for a static memory pool.
753  *
754  * In a static memory pool initial pool memory is statically allocated at compile time, ensuring
755  * pool can be created with at least some elements. This is especially valuable on embedded
756  * systems.
757  *
758  * @param name Pool name.
759  * @param numBlocks Default number of blocks. This can be overriden in components using the "pools"
760  * directive.
761  * @param objSize Size of each block in the pool.
762  */
763 /*
764  * Internal Note: size_t is used instead of uint8_t to ensure alignment on platforms where
765  * alignment matters.
766  */
767 //--------------------------------------------------------------------------------------------------
768 #if LE_CONFIG_MEM_POOLS
769 # define LE_MEM_DEFINE_STATIC_POOL(name, numBlocks, objSize) \
770  static le_mem_Pool_t _mem_##name##Pool; \
771  static size_t _mem_##name##Data[LE_MEM_POOL_WORDS(LE_MEM_BLOCKS(name, numBlocks), objSize)]
772 #else
773 # define LE_MEM_DEFINE_STATIC_POOL(name, numBlocks, objSize) \
774  static le_mem_Pool_t _mem_##name##Pool
775 #endif
776 
777 //--------------------------------------------------------------------------------------------------
778 /**
779  * Declare variables for a static memory pool, must specify which object section the variable goes
780  * into
781  *
782  * By default static memory will the assigned to the bss or data section of the final object.
783  * This macro tells the linker to assign to variable to a specific section, sectionName.
784  * Essentially a "__attribute__((section("sectionName")))" will be added after the variable
785  * declaration.
786  *
787  *
788  * @param name Pool name.
789  * @param numBlocks Default number of blocks. This can be overridden in components using the "pools"
790  * directive.
791  * @param objSize Size of each block in the pool.
792  * @param sectionName __attribute__((section("section"))) will be added to the pool declaration so the
793  memory is associated with a the specific section instead of bss, data,..
794  */
795 /*
796  * Internal Note: size_t is used instead of uint8_t to ensure alignment on platforms where
797  * alignment matters.
798  */
799 //--------------------------------------------------------------------------------------------------
800 #if LE_CONFIG_MEM_POOLS
801 # define LE_MEM_DEFINE_STATIC_POOL_IN_SECTION(name, numBlocks, objSize, sectionName) \
802  static le_mem_Pool_t _mem_##name##Pool __attribute__((section(sectionName))); \
803  static size_t _mem_##name##Data[LE_MEM_POOL_WORDS( \
804  LE_MEM_BLOCKS(name, numBlocks), objSize)] __attribute__((section(sectionName)))
805 #else
806 # define LE_MEM_DEFINE_STATIC_POOL_IN_SECTION(name, numBlocks, objSize, sectionName) \
807  static le_mem_Pool_t _mem_##name##Pool __attribute__((section(sectionName)));
808 #endif
809 
810 //--------------------------------------------------------------------------------------------------
811 /**
812  * Initialize an empty static memory pool.
813  *
814  * @param name Pool name.
815  * @param numBlocks Default number of blocks. This can be overriden in components using the "pools"
816  * directive.
817  * @param objSize Size of each block in the pool.
818  *
819  * @return
820  * Reference to the memory pool object.
821  *
822  * @note
823  * This function cannot fail.
824  */
825 //--------------------------------------------------------------------------------------------------
826 #if LE_CONFIG_MEM_POOLS
827 # define le_mem_InitStaticPool(name, numBlocks, objSize) \
828  (inline_static_assert( \
829  sizeof(_mem_##name##Data) == \
830  sizeof(size_t[LE_MEM_POOL_WORDS(LE_MEM_BLOCKS(name, numBlocks), objSize)]), \
831  "initial pool size does not match definition"), \
832  _le_mem_InitStaticPool(STRINGIZE(LE_COMPONENT_NAME), #name, \
833  LE_MEM_BLOCKS(name, numBlocks), (objSize), &_mem_##name##Pool, _mem_##name##Data))
834 #else
835 # define le_mem_InitStaticPool(name, numBlocks, objSize) \
836  _le_mem_InitStaticPool(STRINGIZE(LE_COMPONENT_NAME), #name, \
837  LE_MEM_BLOCKS(name, numBlocks), (objSize), &_mem_##name##Pool, NULL)
838 #endif
839 
840 //--------------------------------------------------------------------------------------------------
841 /**
842  * Expands the size of a memory pool.
843  *
844  * @return Reference to the memory pool object (the same value passed into it).
845  *
846  * @note On failure, the process exits, so you don't have to worry about checking the returned
847  * reference for validity.
848  */
849 //--------------------------------------------------------------------------------------------------
850 le_mem_PoolRef_t le_mem_ExpandPool
851 (
852  le_mem_PoolRef_t pool, ///< [IN] Pool to be expanded.
853  size_t numObjects ///< [IN] Number of objects to add to the pool.
854 );
855 
856 
857 
858 #if !LE_CONFIG_MEM_TRACE
859  //----------------------------------------------------------------------------------------------
860  /**
861  * Attempts to allocate an object from a pool.
862  *
863  * @return
864  * Pointer to the allocated object, or NULL if the pool doesn't have any free objects
865  * to allocate.
866  */
867  //----------------------------------------------------------------------------------------------
868  void* le_mem_TryAlloc
869  (
870  le_mem_PoolRef_t pool ///< [IN] Pool from which the object is to be allocated.
871  );
872 #else
873  /// @cond HIDDEN_IN_USER_DOCS
874  void* _le_mem_TryAlloc(le_mem_PoolRef_t pool);
875  /// @endcond
876 
877 # define le_mem_TryAlloc(pool) \
878  _le_mem_AllocTracer(pool, \
879  _le_mem_TryAlloc, \
880  "le_mem_TryAlloc", \
881  STRINGIZE(LE_FILENAME), \
882  __FUNCTION__, \
883  __LINE__)
884 
885 #endif
886 
887 
888 #if !LE_CONFIG_MEM_TRACE
889  //----------------------------------------------------------------------------------------------
890  /**
891  * Allocates an object from a pool or logs a fatal error and terminates the process if the pool
892  * doesn't have any free objects to allocate.
893  *
894  * @return Pointer to the allocated object.
895  *
896  * @note On failure, the process exits, so you don't have to worry about checking the
897  * returned pointer for validity.
898  */
899  //----------------------------------------------------------------------------------------------
900  void* le_mem_AssertAlloc
901  (
902  le_mem_PoolRef_t pool ///< [IN] Pool from which the object is to be allocated.
903  );
904 #else
905  /// @cond HIDDEN_IN_USER_DOCS
906  void* _le_mem_AssertAlloc(le_mem_PoolRef_t pool);
907  /// @endcond
908 
909 # define le_mem_AssertAlloc(pool) \
910  _le_mem_AllocTracer(pool, \
911  _le_mem_AssertAlloc, \
912  "le_mem_AssertAlloc", \
913  STRINGIZE(LE_FILENAME), \
914  __FUNCTION__, \
915  __LINE__)
916 #endif
917 
918 
919 #if !LE_CONFIG_MEM_TRACE
920  //----------------------------------------------------------------------------------------------
921  /**
922  * Allocates an object from a pool or logs a warning and expands the pool if the pool
923  * doesn't have any free objects to allocate.
924  *
925  * @return Pointer to the allocated object.
926  *
927  * @note On failure, the process exits, so you don't have to worry about checking the
928  * returned pointer for validity.
929  */
930  //----------------------------------------------------------------------------------------------
931  void* le_mem_ForceAlloc
932  (
933  le_mem_PoolRef_t pool ///< [IN] Pool from which the object is to be allocated.
934  );
935 #else
936  /// @cond HIDDEN_IN_USER_DOCS
937  void* _le_mem_ForceAlloc(le_mem_PoolRef_t pool);
938  /// @endcond
939 
940 # define le_mem_ForceAlloc(pool) \
941  _le_mem_AllocTracer(pool, \
942  _le_mem_ForceAlloc, \
943  "le_mem_ForceAlloc", \
944  STRINGIZE(LE_FILENAME), \
945  __FUNCTION__, \
946  __LINE__)
947 #endif
948 
949 
950 #if !LE_CONFIG_MEM_TRACE
951  //----------------------------------------------------------------------------------------------
952  /**
953  * Attempts to allocate an object from a pool.
954  *
955  * @return
956  * Pointer to the allocated object, or NULL if the pool doesn't have any free objects
957  * to allocate.
958  */
959  //----------------------------------------------------------------------------------------------
960  void* le_mem_TryVarAlloc
961  (
962  le_mem_PoolRef_t pool, ///< [IN] Pool from which the object is to be allocated.
963  size_t size ///< [IN] The size of block to allocate
964  );
965 #else
966  /// @cond HIDDEN_IN_USER_DOCS
967  void* _le_mem_TryVarAlloc(le_mem_PoolRef_t pool, size_t size);
968  /// @endcond
969 
970 # define le_mem_TryVarAlloc(pool, size) \
971  _le_mem_VarAllocTracer(pool, \
972  size, \
973  _le_mem_TryVarAlloc, \
974  "le_mem_TryVarAlloc", \
975  STRINGIZE(LE_FILENAME), \
976  __FUNCTION__, \
977  __LINE__)
978 
979 #endif
980 
981 
982 #if !LE_CONFIG_MEM_TRACE
983  //----------------------------------------------------------------------------------------------
984  /**
985  * Allocates an object from a pool or logs a fatal error and terminates the process if the pool
986  * doesn't have any free objects to allocate.
987  *
988  * @return Pointer to the allocated object.
989  *
990  * @note On failure, the process exits, so you don't have to worry about checking the
991  * returned pointer for validity.
992  */
993  //----------------------------------------------------------------------------------------------
995  (
996  le_mem_PoolRef_t pool, ///< [IN] Pool from which the object is to be allocated.
997  size_t size ///< [IN] The size of block to allocate
998  );
999 #else
1000  /// @cond HIDDEN_IN_USER_DOCS
1001  void* _le_mem_AssertVarAlloc(le_mem_PoolRef_t pool, size_t size);
1002  /// @endcond
1003 
1004 # define le_mem_AssertVarAlloc(pool, size) \
1005  _le_mem_VarAllocTracer(pool, \
1006  size, \
1007  _le_mem_AssertVarAlloc, \
1008  "le_mem_AssertVarAlloc", \
1009  STRINGIZE(LE_FILENAME), \
1010  __FUNCTION__, \
1011  __LINE__)
1012 #endif
1013 
1014 
1015 #if !LE_CONFIG_MEM_TRACE
1016  //----------------------------------------------------------------------------------------------
1017  /**
1018  * Allocates an object from a pool or logs a warning and expands the pool if the pool
1019  * doesn't have any free objects to allocate.
1020  *
1021  * @return Pointer to the allocated object.
1022  *
1023  * @note On failure, the process exits, so you don't have to worry about checking the
1024  * returned pointer for validity.
1025  */
1026  //----------------------------------------------------------------------------------------------
1027  void* le_mem_ForceVarAlloc
1028  (
1029  le_mem_PoolRef_t pool, ///< [IN] Pool from which the object is to be allocated.
1030  size_t size ///< [IN] The size of block to allocate
1031  );
1032 #else
1033  /// @cond HIDDEN_IN_USER_DOCS
1034  void* _le_mem_ForceVarAlloc(le_mem_PoolRef_t pool, size_t size);
1035  /// @endcond
1036 
1037 # define le_mem_ForceVarAlloc(pool, size) \
1038  _le_mem_VarAllocTracer(pool, \
1039  size, \
1040  _le_mem_ForceVarAlloc, \
1041  "le_mem_ForceVarAlloc", \
1042  STRINGIZE(LE_FILENAME), \
1043  __FUNCTION__, \
1044  __LINE__)
1045 #endif
1046 
1047 //--------------------------------------------------------------------------------------------------
1048 /**
1049  * Attempts to allocate an object from a pool using the configured allocation failure behaviour
1050  * (force or assert). Forced allocation will expand into the heap if the configured pool size is
1051  * exceeded, while assert allocation will abort the program with an error if the pool cannot satisfy
1052  * the request.
1053  *
1054  * @param pool Pool from which the object is to be allocated.
1055  *
1056  * @return Pointer to the allocated object.
1057  */
1058 //--------------------------------------------------------------------------------------------------
1059 #if LE_CONFIG_MEM_ALLOC_FORCE
1060 # define le_mem_Alloc(pool) le_mem_ForceAlloc(pool)
1061 #elif LE_CONFIG_MEM_ALLOC_ASSERT
1062 # define le_mem_Alloc(pool) le_mem_AssertAlloc(pool)
1063 #else
1064 # error "No supported allocation scheme selected!"
1065 #endif
1066 
1067 //--------------------------------------------------------------------------------------------------
1068 /**
1069  * Attempts to allocate a variably-sized object from a pool using the configured allocation failure
1070  * behaviour (force or assert). Forced allocation will expand into the heap if the configured pool
1071  * size is exceeded, while assert allocation will abort the program with an error if the pool cannot
1072  * satisfy the request.
1073  *
1074  * @param pool Pool from which the object is to be allocated.
1075  * @param size The size of block to allocate.
1076  *
1077  * @return Pointer to the allocated object.
1078  */
1079 //--------------------------------------------------------------------------------------------------
1080 #if LE_CONFIG_MEM_ALLOC_FORCE
1081 # define le_mem_VarAlloc(pool, size) le_mem_ForceVarAlloc((pool), (size))
1082 #elif LE_CONFIG_MEM_ALLOC_ASSERT
1083 # define le_mem_VarAlloc(pool, size) le_mem_AssertVarAlloc((pool), (size))
1084 #else
1085 # error "No supported allocation scheme selected!"
1086 #endif
1087 
1088 //--------------------------------------------------------------------------------------------------
1089 /**
1090  * Sets the number of objects that are added when le_mem_ForceAlloc expands the pool.
1091  *
1092  * @return
1093  * Nothing.
1094  *
1095  * @note
1096  * The default value is one.
1097  */
1098 //--------------------------------------------------------------------------------------------------
1100 (
1101  le_mem_PoolRef_t pool, ///< [IN] Pool to set the number of objects for.
1102  size_t numObjects ///< [IN] Number of objects that is added when
1103  /// le_mem_ForceAlloc expands the pool.
1104 );
1105 
1106 
1107 #if !LE_CONFIG_MEM_TRACE
1108  //----------------------------------------------------------------------------------------------
1109  /**
1110  * Releases an object. If the object's reference count has reached zero, it will be destructed
1111  * and its memory will be put back into the pool for later reuse.
1112  *
1113  * @return
1114  * Nothing.
1115  *
1116  * @warning
1117  * - <b>Don't EVER access an object after releasing it.</b> It might not exist anymore.
1118  * - If the object has a destructor accessing a data structure shared by multiple
1119  * threads, ensure you hold the mutex (or take other measures to prevent races) before
1120  * releasing the object.
1121  */
1122  //----------------------------------------------------------------------------------------------
1123  void le_mem_Release
1124  (
1125  void* objPtr ///< [IN] Pointer to the object to be released.
1126  );
1127 #else
1128  /// @cond HIDDEN_IN_USER_DOCS
1129  void _le_mem_Release(void* objPtr);
1130  /// @endcond
1131 
1132 # define le_mem_Release(objPtr) \
1133  _le_mem_Trace(_le_mem_GetBlockPool(objPtr), \
1134  STRINGIZE(LE_FILENAME), \
1135  __FUNCTION__, \
1136  __LINE__, \
1137  "le_mem_Release", \
1138  (objPtr)); \
1139  _le_mem_Release(objPtr);
1140 #endif
1141 
1142 
1143 #if !LE_CONFIG_MEM_TRACE
1144  //----------------------------------------------------------------------------------------------
1145  /**
1146  * Increments the reference count on an object by 1.
1147  *
1148  * See @ref mem_ref_counting for more information.
1149  *
1150  * @return
1151  * Nothing.
1152  */
1153  //----------------------------------------------------------------------------------------------
1154  void le_mem_AddRef
1155  (
1156  void* objPtr ///< [IN] Pointer to the object.
1157  );
1158 #else
1159  /// @cond HIDDEN_IN_USER_DOCS
1160  void _le_mem_AddRef(void* objPtr);
1161  /// @endcond
1162 
1163 # define le_mem_AddRef(objPtr) \
1164  _le_mem_Trace(_le_mem_GetBlockPool(objPtr), \
1165  STRINGIZE(LE_FILENAME), \
1166  __FUNCTION__, \
1167  __LINE__, \
1168  "le_mem_AddRef", \
1169  (objPtr)); \
1170  _le_mem_AddRef(objPtr);
1171 #endif
1172 
1173 //--------------------------------------------------------------------------------------------------
1174 /**
1175  * Fetches the size of a block (in bytes).
1176  *
1177  * @return
1178  * Object size, in bytes.
1179  */
1180 //--------------------------------------------------------------------------------------------------
1181 size_t le_mem_GetBlockSize
1182 (
1183  void* objPtr ///< [IN] Pointer to the object to get size of.
1184 );
1185 
1186 //----------------------------------------------------------------------------------------------
1187 /**
1188  * Fetches the reference count on an object.
1189  *
1190  * See @ref mem_ref_counting for more information.
1191  *
1192  * @warning If using this in a multi-threaded application that shares memory pool objects
1193  * between threads, steps must be taken to coordinate the threads (e.g., using a mutex)
1194  * to ensure that the reference count value fetched remains correct when it is used.
1195  *
1196  * @return
1197  * The reference count on the object.
1198  */
1199 //----------------------------------------------------------------------------------------------
1200 size_t le_mem_GetRefCount
1201 (
1202  void* objPtr ///< [IN] Pointer to the object.
1203 );
1204 
1205 
1206 //--------------------------------------------------------------------------------------------------
1207 /**
1208  * Sets the destructor function for a specified pool.
1209  *
1210  * See @ref mem_destructors for more information.
1211  *
1212  * @return
1213  * Nothing.
1214  */
1215 //--------------------------------------------------------------------------------------------------
1217 (
1218  le_mem_PoolRef_t pool, ///< [IN] The pool.
1219  le_mem_Destructor_t destructor ///< [IN] Destructor function.
1220 );
1221 
1222 
1223 //--------------------------------------------------------------------------------------------------
1224 /**
1225  * Fetches the statistics for a specified pool.
1226  *
1227  * @return
1228  * Nothing. Uses output parameter instead.
1229  */
1230 //--------------------------------------------------------------------------------------------------
1231 void le_mem_GetStats
1232 (
1233  le_mem_PoolRef_t pool, ///< [IN] Pool where stats are to be fetched.
1234  le_mem_PoolStats_t* statsPtr ///< [OUT] Pointer to where the stats will be stored.
1235 );
1236 
1237 
1238 //--------------------------------------------------------------------------------------------------
1239 /**
1240  * Resets the statistics for a specified pool.
1241  *
1242  * @return
1243  * Nothing.
1244  */
1245 //--------------------------------------------------------------------------------------------------
1246 void le_mem_ResetStats
1247 (
1248  le_mem_PoolRef_t pool ///< [IN] Pool where stats are to be reset.
1249 );
1250 
1251 
1252 //--------------------------------------------------------------------------------------------------
1253 /**
1254  * Gets the memory pool's name, including the component name prefix.
1255  *
1256  * If the pool were given the name "myPool" and the component that it belongs to is called
1257  * "myComponent", then the full pool name returned by this function would be "myComponent.myPool".
1258  *
1259  * @return
1260  * LE_OK if successful.
1261  * LE_OVERFLOW if the name was truncated to fit in the provided buffer.
1262  */
1263 //--------------------------------------------------------------------------------------------------
1265 (
1266  le_mem_PoolRef_t pool, ///< [IN] The memory pool.
1267  char* namePtr, ///< [OUT] Buffer to store the name of the memory pool.
1268  size_t bufSize ///< [IN] Size of the buffer namePtr points to.
1269 );
1270 
1271 
1272 //--------------------------------------------------------------------------------------------------
1273 /**
1274  * Checks if the specified pool is a sub-pool.
1275  *
1276  * @return
1277  * true if it is a sub-pool.
1278  * false if it is not a sub-pool.
1279  */
1280 //--------------------------------------------------------------------------------------------------
1281 bool le_mem_IsSubPool
1282 (
1283  le_mem_PoolRef_t pool ///< [IN] The memory pool.
1284 );
1285 
1286 
1287 //--------------------------------------------------------------------------------------------------
1288 /**
1289  * Fetches the number of objects a specified pool can hold (this includes both the number of
1290  * free and in-use objects).
1291  *
1292  * @return
1293  * Total number of objects.
1294  */
1295 //--------------------------------------------------------------------------------------------------
1296 size_t le_mem_GetObjectCount
1297 (
1298  le_mem_PoolRef_t pool ///< [IN] Pool where number of objects is to be fetched.
1299 );
1300 
1301 
1302 //--------------------------------------------------------------------------------------------------
1303 /**
1304  * Fetches the size of the objects in a specified pool (in bytes).
1305  *
1306  * @return
1307  * Object size, in bytes.
1308  */
1309 //--------------------------------------------------------------------------------------------------
1310 size_t le_mem_GetObjectSize
1311 (
1312  le_mem_PoolRef_t pool ///< [IN] Pool where object size is to be fetched.
1313 );
1314 
1315 
1316 //--------------------------------------------------------------------------------------------------
1317 /**
1318  * Fetches the total size of the object including all the memory overhead in a given pool (in bytes).
1319  *
1320  * @return
1321  * Total object memory size, in bytes.
1322  */
1323 //--------------------------------------------------------------------------------------------------
1325 (
1326  le_mem_PoolRef_t pool ///< [IN] The pool whose object memory size is to be fetched.
1327 );
1328 
1329 
1330 #if LE_CONFIG_MEM_POOL_NAMES_ENABLED
1331 //--------------------------------------------------------------------------------------------------
1332 /** @cond HIDDEN_IN_USER_DOCS
1333  *
1334  * Internal function used to implement le_mem_FindPool() with automatic component scoping
1335  * of pool names.
1336  */
1337 //--------------------------------------------------------------------------------------------------
1338 le_mem_PoolRef_t _le_mem_FindPool
1339 (
1340  const char* componentName, ///< [IN] Name of the component.
1341  const char* name ///< [IN] Name of the pool inside the component.
1342 );
1343 /// @endcond
1344 //--------------------------------------------------------------------------------------------------
1345 /**
1346  * Finds a pool based on the pool's name.
1347  *
1348  * @return
1349  * Reference to the pool, or NULL if the pool doesn't exist.
1350  */
1351 //--------------------------------------------------------------------------------------------------
1352 static inline le_mem_PoolRef_t le_mem_FindPool
1354  const char* name ///< [IN] Name of the pool inside the component.
1355 )
1356 {
1357  return _le_mem_FindPool(STRINGIZE(LE_COMPONENT_NAME), name);
1358 }
1359 #else
1360 //--------------------------------------------------------------------------------------------------
1361 /**
1362  * Finds a pool based on the pool's name.
1363  *
1364  * @return
1365  * Reference to the pool, or NULL if the pool doesn't exist.
1366  */
1367 //--------------------------------------------------------------------------------------------------
1368 LE_DECLARE_INLINE le_mem_PoolRef_t le_mem_FindPool
1369 (
1370  const char* name ///< [IN] Name of the pool inside the component.
1371 )
1372 {
1373  LE_UNUSED(name);
1374  return NULL;
1375 }
1376 #endif /* end LE_CONFIG_MEM_POOL_NAMES_ENABLED */
1377 
1378 
1379 #if LE_CONFIG_MEM_POOL_NAMES_ENABLED
1380 //--------------------------------------------------------------------------------------------------
1381 /** @cond HIDDEN_IN_USER_DOCS
1382  *
1383  * Internal function used to implement le_mem_CreateSubPool() with automatic component scoping
1384  * of pool names.
1385  */
1386 //--------------------------------------------------------------------------------------------------
1387 le_mem_PoolRef_t _le_mem_CreateSubPool
1388 (
1389  le_mem_PoolRef_t superPool, ///< [IN] Super-pool.
1390  const char* componentName, ///< [IN] Name of the component.
1391  const char* name, ///< [IN] Name of the sub-pool (will be copied into the
1392  /// sub-pool).
1393  size_t numObjects ///< [IN] Number of objects to take from the super-pool.
1394 );
1395 /// @endcond
1396 //--------------------------------------------------------------------------------------------------
1397 /**
1398  * Creates a sub-pool.
1399  *
1400  * See @ref mem_sub_pools for more information.
1401  *
1402  * @return
1403  * Reference to the sub-pool.
1404  */
1405 //--------------------------------------------------------------------------------------------------
1406 static inline le_mem_PoolRef_t le_mem_CreateSubPool
1408  le_mem_PoolRef_t superPool, ///< [IN] Super-pool.
1409  const char* name, ///< [IN] Name of the sub-pool (will be copied into the
1410  /// sub-pool).
1411  size_t numObjects ///< [IN] Number of objects to take from the super-pool.
1412 )
1413 {
1414  return _le_mem_CreateSubPool(superPool, STRINGIZE(LE_COMPONENT_NAME), name, numObjects);
1415 }
1416 #else /* if not LE_CONFIG_MEM_POOL_NAMES_ENABLED */
1417 //--------------------------------------------------------------------------------------------------
1418 /** @cond HIDDEN_IN_USER_DOCS
1419  *
1420  * Internal function used to implement le_mem_CreateSubPool() with automatic component scoping
1421  * of pool names.
1422  */
1423 //--------------------------------------------------------------------------------------------------
1424 le_mem_PoolRef_t _le_mem_CreateSubPool
1425 (
1426  le_mem_PoolRef_t superPool, ///< [IN] Super-pool.
1427  size_t numObjects ///< [IN] Number of objects to take from the super-pool.
1428 );
1429 /// @endcond
1430 //--------------------------------------------------------------------------------------------------
1431 /**
1432  * Creates a sub-pool.
1433  *
1434  * See @ref mem_sub_pools for more information.
1435  *
1436  * @return
1437  * Reference to the sub-pool.
1438  */
1439 //--------------------------------------------------------------------------------------------------
1440 LE_DECLARE_INLINE le_mem_PoolRef_t le_mem_CreateSubPool
1441 (
1442  le_mem_PoolRef_t superPool, ///< [IN] Super-pool.
1443  const char* name, ///< [IN] Name of the sub-pool (will be copied into the
1444  /// sub-pool).
1445  size_t numObjects ///< [IN] Number of objects to take from the super-pool.
1446 )
1447 {
1448  LE_UNUSED(name);
1449  return _le_mem_CreateSubPool(superPool, numObjects);
1450 }
1451 #endif /* end LE_CONFIG_MEM_POOL_NAMES_ENABLED */
1452 
1453 
1454 #if LE_CONFIG_MEM_POOL_NAMES_ENABLED
1455 //--------------------------------------------------------------------------------------------------
1456 /** @cond HIDDEN_IN_USER_DOCS
1457  *
1458  * Internal function used to implement le_mem_CreateSubPool() with automatic component scoping
1459  * of pool names.
1460  */
1461 //--------------------------------------------------------------------------------------------------
1462 le_mem_PoolRef_t _le_mem_CreateReducedPool
1463 (
1464  le_mem_PoolRef_t superPool, ///< [IN] Super-pool.
1465  const char* componentName, ///< [IN] Name of the component.
1466  const char* name, ///< [IN] Name of the sub-pool (will be copied into the
1467  /// sub-pool).
1468  size_t numObjects, ///< [IN] Number of objects to take from the super-pool.
1469  size_t objSize ///< [IN] Minimum size of objects in the subpool.
1470 );
1471 /// @endcond
1472 //--------------------------------------------------------------------------------------------------
1473 /**
1474  * Creates a sub-pool of smaller objects.
1475  *
1476  * See @ref mem_reduced_pools for more information.
1477  *
1478  * @return
1479  * Reference to the sub-pool.
1480  */
1481 //--------------------------------------------------------------------------------------------------
1482 static inline le_mem_PoolRef_t le_mem_CreateReducedPool
1484  le_mem_PoolRef_t superPool, ///< [IN] Super-pool.
1485  const char* name, ///< [IN] Name of the sub-pool (will be copied into the
1486  /// sub-pool).
1487  size_t numObjects, ///< [IN] Minimum number of objects in the subpool
1488  ///< by default.
1489  size_t objSize ///< [IN] Minimum size of objects in the subpool.
1490 )
1491 {
1492  return _le_mem_CreateReducedPool(superPool, STRINGIZE(LE_COMPONENT_NAME), name, numObjects, objSize);
1493 }
1494 #else /* if not LE_CONFIG_MEM_POOL_NAMES_ENABLED */
1495 //--------------------------------------------------------------------------------------------------
1496 /** @cond HIDDEN_IN_USER_DOCS
1497  *
1498  * Internal function used to implement le_mem_CreateSubPool() with automatic component scoping
1499  * of pool names.
1500  */
1501 //--------------------------------------------------------------------------------------------------
1502 le_mem_PoolRef_t _le_mem_CreateReducedPool
1503 (
1504  le_mem_PoolRef_t superPool, ///< [IN] Super-pool.
1505  size_t numObjects, ///< [IN] Minimum number of objects in the subpool
1506  ///< by default.
1507  size_t objSize ///< [IN] Minimum size of objects in the subpool.
1508 );
1509 /// @endcond
1510 //--------------------------------------------------------------------------------------------------
1511 /**
1512  * Creates a sub-pool of smaller objects.
1513  *
1514  * See @ref mem_reduced_pools for more information.
1515  *
1516  * @return
1517  * Reference to the sub-pool.
1518  */
1519 //--------------------------------------------------------------------------------------------------
1521 (
1522  le_mem_PoolRef_t superPool, ///< [IN] Super-pool.
1523  const char* name, ///< [IN] Name of the sub-pool (will be copied into the
1524  /// sub-pool).
1525  size_t numObjects, ///< [IN] Minimum number of objects in the subpool
1526  ///< by default.
1527  size_t objSize ///< [IN] Minimum size of objects in the subpool.
1528 )
1529 {
1530  LE_UNUSED(name);
1531  return _le_mem_CreateReducedPool(superPool, numObjects, objSize);
1532 }
1533 #endif /* end LE_CONFIG_MEM_POOL_NAMES_ENABLED */
1534 
1535 
1536 //--------------------------------------------------------------------------------------------------
1537 /**
1538  * Deletes a sub-pool.
1539  *
1540  * See @ref mem_sub_pools for more information.
1541  *
1542  * @return
1543  * Nothing.
1544  */
1545 //--------------------------------------------------------------------------------------------------
1547 (
1548  le_mem_PoolRef_t subPool ///< [IN] Sub-pool to be deleted.
1549 );
1550 
1551 #if LE_CONFIG_RTOS
1552 //--------------------------------------------------------------------------------------------------
1553 /**
1554  * Prepare system to support hibernate-to-memory.
1555  */
1556 //--------------------------------------------------------------------------------------------------
1558 (
1559  void *startPtr, ///< [IN] Beginning of memory pool region
1560  void *endPtr ///< [IN] End of memory pool region
1561 );
1562 
1563 
1564 //--------------------------------------------------------------------------------------------------
1565 /**
1566  * Compress memory pools ready for hibernate-to-RAM
1567  *
1568  * This compresses the memory pools ready for hibernation. All Legato tasks must remain
1569  * suspended until after le_mem_Resume() is called.
1570  *
1571  * @return Nothing
1572  */
1573 //--------------------------------------------------------------------------------------------------
1574 void le_mem_Hibernate
1575 (
1576  void **freeStartPtr, ///< [OUT] Beginning of unused memory which does not need to be
1577  ///< preserved in hibernation
1578  void **freeEndPtr ///< [OUT] End of unused memory
1579 );
1580 
1581 //--------------------------------------------------------------------------------------------------
1582 /**
1583  * Decompress memory pools after waking from hibernate-to-RAM
1584  *
1585  * This decompresses memory pools after hibernation. After this function returns, Legato tasks
1586  * may be resumed.
1587  *
1588  * @return Nothing
1589  */
1590 //--------------------------------------------------------------------------------------------------
1591 void le_mem_Resume
1592 (
1593  void
1594 );
1595 
1596 #endif /* end LE_CONFIG_RTOS */
1597 
1598 //--------------------------------------------------------------------------------------------------
1599 /**
1600  * Duplicate a UTF-8 string. The space for the duplicate string will be allocated from the provided
1601  * memory pool using le_mem_VarAlloc().
1602  *
1603  * @return The allocated duplicate of the string. This may later be released with
1604  * le_mem_Release().
1605  */
1606 //--------------------------------------------------------------------------------------------------
1607 char *le_mem_StrDup
1608 (
1609  le_mem_PoolRef_t poolRef, ///< Pool from which to allocate the string.
1610  const char *srcStr ///< String to duplicate.
1611 );
1612 
1613 #endif // LEGATO_MEM_INCLUDE_GUARD
size_t numBlocksToForce
Definition: le_mem.h:524
size_t numFree
Number of free objects currently available in this pool.
Definition: le_mem.h:559
uint64_t numAllocations
Definition: le_mem.h:511
void * le_mem_TryAlloc(le_mem_PoolRef_t pool)
le_sls_List_t freeList
List of free memory blocks.
Definition: le_mem.h:516
void * le_mem_TryVarAlloc(le_mem_PoolRef_t pool, size_t size)
le_mem_PoolRef_t le_mem_ExpandPool(le_mem_PoolRef_t pool, size_t numObjects)
le_result_t
Definition: le_basics.h:46
void * le_mem_AssertAlloc(le_mem_PoolRef_t pool)
#define LE_UNUSED(v)
Definition: le_basics.h:369
void le_mem_GetStats(le_mem_PoolRef_t pool, le_mem_PoolStats_t *statsPtr)
void le_mem_Resume(void)
size_t numBlocksInUse
Number of currently allocated blocks.
Definition: le_mem.h:555
size_t totalBlocks
Definition: le_mem.h:521
struct le_mem_Pool * superPoolPtr
Definition: le_mem.h:505
#define STRINGIZE(x)
Definition: le_basics.h:221
void le_mem_SetDestructor(le_mem_PoolRef_t pool, le_mem_Destructor_t destructor)
void * le_mem_AssertVarAlloc(le_mem_PoolRef_t pool, size_t size)
uint64_t numAllocs
Number of times an object has been allocated from this pool.
Definition: le_mem.h:558
size_t maxNumBlocksUsed
Maximum number of allocated blocks at any one time.
Definition: le_mem.h:513
size_t maxNumBlocksUsed
Maximum number of allocated blocks at any one time.
Definition: le_mem.h:556
void * le_mem_ForceVarAlloc(le_mem_PoolRef_t pool, size_t size)
void le_mem_ResetStats(le_mem_PoolRef_t pool)
size_t numOverflows
Number of times le_mem_ForceAlloc() had to expand the pool.
Definition: le_mem.h:557
static le_mem_PoolRef_t le_mem_CreateReducedPool(le_mem_PoolRef_t superPool, const char *name, size_t numObjects, size_t objSize)
Definition: le_mem.h:1483
void le_mem_SetNumObjsToForce(le_mem_PoolRef_t pool, size_t numObjects)
size_t numOverflows
Number of times le_mem_ForceAlloc() had to expand pool.
Definition: le_mem.h:510
char * le_mem_StrDup(le_mem_PoolRef_t poolRef, const char *srcStr)
void le_mem_DeleteSubPool(le_mem_PoolRef_t subPool)
struct le_mem_Pool * le_mem_PoolRef_t
Definition: le_mem.h:545
le_result_t le_mem_GetName(le_mem_PoolRef_t pool, char *namePtr, size_t bufSize)
void le_mem_InitHibernation(void *startPtr, void *endPtr)
bool le_mem_IsSubPool(le_mem_PoolRef_t pool)
void le_mem_Release(void *objPtr)
Definition: le_mem.h:553
static le_mem_PoolRef_t le_mem_FindPool(const char *name)
Definition: le_mem.h:1353
size_t blockSize
Number of bytes in a block, including all overhead.
Definition: le_mem.h:520
void(* le_mem_Destructor_t)(void *objPtr)
Definition: le_mem.h:487
size_t le_mem_GetObjectCount(le_mem_PoolRef_t pool)
Definition: le_mem.h:502
Definition: le_singlyLinkedList.h:201
size_t le_mem_GetObjectFullSize(le_mem_PoolRef_t pool)
le_mem_Destructor_t destructor
The destructor for objects in this pool.
Definition: le_mem.h:531
size_t le_mem_GetBlockSize(void *objPtr)
static le_mem_PoolRef_t le_mem_CreatePool(const char *name, size_t objSize)
Definition: le_mem.h:677
size_t le_mem_GetObjectSize(le_mem_PoolRef_t pool)
le_dls_Link_t poolLink
This pool&#39;s link in the list of memory pools.
Definition: le_mem.h:504
static le_mem_PoolRef_t le_mem_CreateSubPool(le_mem_PoolRef_t superPool, const char *name, size_t numObjects)
Definition: le_mem.h:1407
void le_mem_AddRef(void *objPtr)
void * le_mem_ForceAlloc(le_mem_PoolRef_t pool)
size_t userDataSize
Size of the object requested by the client in bytes.
Definition: le_mem.h:519
void le_mem_Hibernate(void **freeStartPtr, void **freeEndPtr)
size_t numBlocksInUse
Number of currently allocated blocks.
Definition: le_mem.h:523
size_t le_mem_GetRefCount(void *objPtr)
#define LE_DECLARE_INLINE
Definition: le_basics.h:320