le_mem.h

Go to the documentation of this file.
1 /**
2  * @page c_memory Dynamic Memory Allocation API
3  *
4  *
5  * @ref 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  * @section mem_destructors Destructors
179  *
180  * Destructors are a powerful feature of C++. Anyone who has any non-trivial experience with C++ has
181  * used them. Because C was created before object-oriented programming was around, there's
182  * no native language support for destructors in C. Object-oriented design is still possible
183  * and highly desireable even when the programming is done in C.
184  *
185  * In Legato, it's possible to call @c le_mem_SetDestructor() to attach a function to a memory pool
186  * to be used as a destructor for objects allocated from that pool. If a pool has a destructor,
187  * whenever the reference count reaches zero for an object allocated from that pool,
188  * the pool's destructor function will pass a pointer to that object. After
189  * the destructor returns, the object will be fully destroyed, and its memory will be released back
190  * into the pool for later reuse by another object.
191  *
192  * Here's a destructor code sample:
193  * @code
194  * static void PointDestructor(void* objPtr)
195  * {
196  * Point_t* pointPtr = objPtr;
197  *
198  * printf("Destroying point (%d, %d)\n", pointPtr->x, pointPtr->y);
199  *
200  * @todo Add more to sample.
201  * }
202  *
203  * int xx_pt_ProcessStart(void)
204  * {
205  * PointPool = le_mem_CreatePool(sizeof(Point_t));
206  * le_mem_ExpandPool(PointPool, MAX_POINTS);
207  * le_mem_SetDestructor(PointPool, PointDestructor);
208  * return SUCCESS;
209  * }
210  *
211  * static void DeletePointList(Point_t** pointList, size_t numPoints)
212  * {
213  * size_t i;
214  * for (i = 0; i < numPoints; i++)
215  * {
216  * le_mem_Release(pointList[i]);
217  * }
218  * }
219  * @endcode
220  *
221  * In this sample, when DeletePointList() is called (with a pointer to an array of pointers
222  * to Point_t objects with reference counts of 1), each of the objects in the pointList is
223  * released. This causes their reference counts to hit 0, which triggers executing
224  * PointDestructor() for each object in the pointList, and the "Destroying point..." message will
225  * be printed for each.
226  *
227  *
228  * @section mem_stats Statistics
229  *
230  * Some statistics are gathered for each memory pool:
231  * - Number of allocations.
232  * - Number of currently free objects.
233  * - Number of overflows (times that le_mem_ForceAlloc() had to expand the pool).
234  *
235  * Statistics (and other pool properties) can be checked using functions:
236  * - @c le_mem_GetStats()
237  * - @c le_mem_GetObjectCount()
238  * - @c le_mem_GetObjectSize()
239  *
240  * Statistics are fetched together atomically using a single function call.
241  * This prevents inconsistencies between them if in a multi-threaded program.
242  *
243  * If you don't have a reference to a specified pool, but you have the name of the pool, you can
244  * get a reference to the pool using @c le_mem_FindPool().
245  *
246  * In addition to programmatically fetching these, they're also available through the
247  * "poolstat" console command (unless your process's main thread is blocked).
248  *
249  * To reset the pool statistics, use @c le_mem_ResetStats().
250  *
251  * @section mem_diagnostics Diagnostics
252  *
253  * The memory system also supports two different forms of diagnostics. Both are enabled by defining
254  * special preprocessor macros when building the framework.
255  *
256  * The first of which is @c LE_MEM_TRACE. When you define @c LE_MEM_TRACE every pool is given a
257  * tracepoint with the name of the pool on creation.
258  *
259  * For instance, the configTree node pool is called, "configTree.nodePool". So to enable a trace of
260  * all config tree node creation and deletion one would use the log tool as follows:
261  *
262  * @code
263  * $ log trace configTree.nodePool
264  * @endcode
265  *
266  * The second diagnostic build flag is @c LE_MEM_VALGRIND. When @c LE_MEM_VALGRIND is enabled, the
267  * pools are disabled and instead malloc and free are directly used. Thus enabling the use of tools
268  * like Valgrind.
269  *
270  * @section mem_threading Multi-Threading
271  *
272  * All functions in this API are <b> thread-safe, but not async-safe </b>. The objects
273  * allocated from pools are not inherently protected from races between threads.
274  *
275  * Allocating and releasing objects, checking stats, incrementing reference
276  * counts, etc. can all be done from multiple threads (excluding signal handlers) without having
277  * to worry about corrupting the memory pools' hidden internal data structures.
278  *
279  * There's no magical way to prevent different threads from interferring with each other
280  * if they both access the @a contents of the same object at the same time.
281  *
282  * The best way to prevent multi-threaded race conditions is simply don't share data between
283  * threads. If multiple threads must access the same data structure, then mutexes, semaphores,
284  * or similar methods should be used to @a synchronize threads and avoid
285  * data structure corruption or thread misbehaviour.
286  *
287  * Although memory pools are @a thread-safe, they are not @a async-safe. This means that memory pools
288  * @a can be corrupted if they are accessed by a signal handler while they are being accessed
289  * by a normal thread. To be safe, <b> don't call any memory pool functions from within a signal handler. </b>
290  *
291  * One problem using destructor functions in a
292  * multi-threaded environment is that the destructor function modifies a data structure shared
293  * between threads, so it's easy to forget to synchronize calls to @c le_mem_Release() with other code
294  * accessing the data structure. If a mutex is used to coordinate access to
295  * the data structure, then the mutex must be held by the thread that calls le_mem_Release() to
296  * ensure there's no other thread accessing the data structure when the destructor runs.
297  *
298  * @section mem_pool_sizes Managing Pool Sizes
299  *
300  * We know it's possible to have pools automatically expand
301  * when they are exhausted, but we don't really want that to happen normally.
302  * Ideally, the pools should be fully allocated to their maximum sizes at start-up so there aren't
303  * any surprises later when certain feature combinations cause the
304  * system to run out of memory in the field. If we allocate everything we think
305  * is needed up-front, then we are much more likely to uncover any memory shortages during
306  * testing, before it's in the field.
307  *
308  * Choosing the right size for your pools correctly at start-up is easy to do if there is a maximum
309  * number of fixed, external @a things that are being represented by the objects being allocated
310  * from the pool. If the pool holds "call objects" representing phone calls over a T1
311  * carrier that will never carry more than 24 calls at a time, then it's obvious that you need to
312  * size your call object pool at 24.
313  *
314  * Other times, it's not so easy to choose the pool size like
315  * code to be reused in different products or different configurations that have different
316  * needs. In those cases, you still have a few options:
317  *
318  * - At start-up, query the operating environment and base the pool sizes.
319  * - Read a configuration setting from a file or other configuration data source.
320  * - Use a build-time configuration setting.
321  *
322  * The build-time configuration setting is the easiest, and generally requires less
323  * interaction between components at start-up simplifying APIs
324  * and reducing boot times.
325  *
326  * If the pool size must be determined at start-up, use @c le_mem_ExpandPool().
327  * Perhaps there's a service-provider module designed to allocate objects on behalf
328  * of client. It can have multiple clients at the same time, but it doesn't know how many clients
329  * or what their resource needs will be until the clients register with it at start-up. We'd want
330  * those clients to be as decoupled from each other as possible (i.e., we want the clients know as little
331  * as possible about each other); we don't want the clients to get together and add up all
332  * their needs before telling the service-provider. We'd rather have the clients independently
333  * report their own needs to the service-provider. Also, we don't want each client to have to wait
334  * for all the other clients to report their needs before starting to use
335  * the services offered by the service-provider. That would add more complexity to the interactions
336  * between the clients and the service-provider.
337  *
338  * This is what should happen when the service-provider can't wait for all clients
339  * to report their needs before creating the pool:
340  * - When the service-provider starts up, it creates an empty pool.
341  * - Whenever a client registers itself with the service-provider, the client can tell the
342  * service-provider what its specific needs are, and the service-provider can expand its
343  * object pool accordingly.
344  * - Since registrations happen at start-up, pool expansion occurs
345  * at start-up, and testing will likely find any pool sizing before going into the field.
346  *
347  * Where clients dynamically start and stop during runtime in response
348  * to external events (e.g., when someone is using the device's Web UI), we still have
349  * a problem because we can't @a shrink pools or delete pools when clients go away. This is where
350  * @ref mem_sub_pools is useful.
351  *
352  * @section mem_sub_pools Sub-Pools
353  *
354  * Essentially, a Sub-Pool is a memory pool that gets its blocks from another pool (the super-pool).
355  * Sub Pools @a can be deleted, causing its blocks to be released back into the super-pool.
356  *
357  * This is useful when a service-provider module needs to handle clients that
358  * dynamically pop into existence and later disappear again. When a client attaches to the service
359  * and says it will probably need a maximum of X of the service-provider's resources, the
360  * service provider can set aside that many of those resources in a sub-pool for that client.
361  * If that client goes over its limit, the sub-pool will log a warning message.
362  *
363  * The problem of sizing the super-pool correctly at start-up still exists,
364  * so what's the point of having a sub-pool, when all of the resources could just be allocated from
365  * the super-pool?
366  *
367  * The benefit is really gained in troubleshooting. If client A, B, C, D and E are
368  * all behaving nicely, but client F is leaking resources, the sub-pool created
369  * on behalf of client F will start warning about the memory leak; time won't have to be
370  * wasted looking at clients A through E to rule them out.
371  *
372  * To create a sub-pool, call @c le_mem_CreateSubPool(). It takes a reference to the super-pool
373  * and the objects specified to the sub-pool, and it returns a reference to the new sub-pool.
374  *
375  * To delete a sub-pool, call @c le_mem_DeleteSubPool(). Do not try to use it to delete a pool that
376  * was created using le_mem_CreatePool(). It's only for sub-pools created using le_mem_CreateSubPool().
377  * Also, it's @b not okay to delete a sub-pool while there are still blocks allocated from it.
378  * You'll see errors in your logs if you do that.
379  *
380  * Sub-Pools automatically inherit their parent's destructor function.
381  *
382  * @note You can't create sub-pools of sub-pools (i.e., sub-pools that get their blocks from another
383  * sub-pool).
384  *
385  * <HR>
386  *
387  * Copyright (C) Sierra Wireless Inc. Use of this work is subject to license.
388  */
389 
390 //--------------------------------------------------------------------------------------------------
391 /** @file le_mem.h
392  *
393  * Legato @ref c_memory include file.
394  *
395  * Copyright (C) Sierra Wireless Inc. Use of this work is subject to license.
396  *
397  */
398 //--------------------------------------------------------------------------------------------------
399 
400 #ifndef LEGATO_MEM_INCLUDE_GUARD
401 #define LEGATO_MEM_INCLUDE_GUARD
402 
403 #ifndef LE_COMPONENT_NAME
404 #define LE_COMPONENT_NAME
405 #endif
406 
407 
408 //--------------------------------------------------------------------------------------------------
409 /**
410  * Objects of this type are used to refer to a memory pool created using either
411  * le_mem_CreatePool() or le_mem_CreateSubPool().
412  */
413 //--------------------------------------------------------------------------------------------------
414 typedef struct le_mem_Pool* le_mem_PoolRef_t;
415 
416 
417 //--------------------------------------------------------------------------------------------------
418 /**
419  * Prototype for destructor functions.
420  *
421  * @param objPtr Pointer to the object where reference count has reached zero. After the destructor
422  * returns this object's memory will be released back into the pool (and this pointer
423  * will become invalid).
424  *
425  * @return Nothing.
426  *
427  * See @ref mem_destructors for more information.
428  */
429 //--------------------------------------------------------------------------------------------------
430 typedef void (*le_mem_Destructor_t)
431 (
432  void* objPtr ///< see parameter documentation in comment above.
433 );
434 
435 
436 //--------------------------------------------------------------------------------------------------
437 /**
438  * List of memory pool statistics.
439  */
440 //--------------------------------------------------------------------------------------------------
441 typedef struct
442 {
443  size_t numBlocksInUse; ///< Number of currently allocated blocks.
444  size_t maxNumBlocksUsed; ///< Maximum number of allocated blocks at any one time.
445  size_t numOverflows; ///< Number of times le_mem_ForceAlloc() had to expand the pool.
446  uint64_t numAllocs; ///< Number of times an object has been allocated from this pool.
447  size_t numFree; ///< Number of free objects currently available in this pool.
448 }
450 
451 
452 #ifdef LE_MEM_TRACE
453  //----------------------------------------------------------------------------------------------
454  /**
455  * Internal function used to retrieve a pool handle for a given pool block.
456  */
457  //----------------------------------------------------------------------------------------------
458  le_mem_PoolRef_t _le_mem_GetBlockPool
459  (
460  void* objPtr ///< [IN] Pointer to the object we're finding a pool for.
461  );
462 
463  typedef void* (*_le_mem_AllocFunc_t)(le_mem_PoolRef_t pool);
464 
465  //----------------------------------------------------------------------------------------------
466  /**
467  * Internal function used to call a memory allocation function and trace its call site.
468  */
469  //----------------------------------------------------------------------------------------------
470  void* _le_mem_AllocTracer
471  (
472  le_mem_PoolRef_t pool, ///< [IN] The pool activity we're tracing.
473  _le_mem_AllocFunc_t funcPtr, ///< [IN] Pointer to the mem function in question.
474  const char* poolFunction, ///< [IN] The pool function being called.
475  const char* file, ///< [IN] The file the call came from.
476  const char* callingfunction, ///< [IN] The function calling into the pool.
477  size_t line ///< [IN] The line in the function where the call
478  /// occurred.
479  );
480 
481  //----------------------------------------------------------------------------------------------
482  /**
483  * Internal function used to trace memory pool activity.
484  */
485  //----------------------------------------------------------------------------------------------
486  void _le_mem_Trace
487  (
488  le_mem_PoolRef_t pool, ///< [IN] The pool activity we're tracing.
489  const char* file, ///< [IN] The file the call came from.
490  const char* callingfunction, ///< [IN] The function calling into the pool.
491  size_t line, ///< [IN] The line in the function where the call
492  /// occurred.
493  const char* poolFunction, ///< [IN] The pool function being called.
494  void* blockPtr ///< [IN] Block allocated/freed.
495  );
496 #endif
497 
498 
499 //--------------------------------------------------------------------------------------------------
500 /** @cond HIDDEN_IN_USER_DOCS
501  *
502  * Internal function used to implement le_mem_CreatePool() with automatic component scoping
503  * of pool names.
504  */
505 //--------------------------------------------------------------------------------------------------
506 le_mem_PoolRef_t _le_mem_CreatePool
507 (
508  const char* componentName, ///< [IN] Name of the component.
509  const char* name, ///< [IN] Name of the pool inside the component.
510  size_t objSize ///< [IN] Size of the individual objects to be allocated from this pool
511  /// (in bytes), e.g., sizeof(MyObject_t).
512 );
513 /// @endcond
514 
515 
516 //--------------------------------------------------------------------------------------------------
517 /**
518  * Creates an empty memory pool.
519  *
520  * @return
521  * Reference to the memory pool object.
522  *
523  * @note
524  * On failure, the process exits, so you don't have to worry about checking the returned
525  * reference for validity.
526  */
527 //--------------------------------------------------------------------------------------------------
529 (
530  const char* name, ///< [IN] Name of the pool (will be copied into the Pool).
531  size_t objSize ///< [IN] Size of the individual objects to be allocated from this pool
532  /// (in bytes), e.g., sizeof(MyObject_t).
533 )
534 {
535  return _le_mem_CreatePool(STRINGIZE(LE_COMPONENT_NAME), name, objSize);
536 }
537 
538 
539 //--------------------------------------------------------------------------------------------------
540 /**
541  * Expands the size of a memory pool.
542  *
543  * @return Reference to the memory pool object (the same value passed into it).
544  *
545  * @note On failure, the process exits, so you don't have to worry about checking the returned
546  * reference for validity.
547  */
548 //--------------------------------------------------------------------------------------------------
550 (
551  le_mem_PoolRef_t pool, ///< [IN] Pool to be expanded.
552  size_t numObjects ///< [IN] Number of objects to add to the pool.
553 );
554 
555 
556 
557 #ifndef LE_MEM_TRACE
558  //----------------------------------------------------------------------------------------------
559  /**
560  * Attempts to allocate an object from a pool.
561  *
562  * @return
563  * Pointer to the allocated object, or NULL if the pool doesn't have any free objects
564  * to allocate.
565  */
566  //----------------------------------------------------------------------------------------------
567  void* le_mem_TryAlloc
568  (
569  le_mem_PoolRef_t pool ///< [IN] Pool from which the object is to be allocated.
570  );
571 #else
572  /// @cond HIDDEN_IN_USER_DOCS
573  void* _le_mem_TryAlloc(le_mem_PoolRef_t pool);
574  /// @endcond
575 
576  #define le_mem_TryAlloc(pool) \
577  _le_mem_AllocTracer(pool, \
578  _le_mem_TryAlloc, \
579  "le_mem_TryAlloc", \
580  __FILE__, \
581  __FUNCTION__, \
582  __LINE__)
583 
584 #endif
585 
586 
587 #ifndef LE_MEM_TRACE
588  //----------------------------------------------------------------------------------------------
589  /**
590  * Allocates an object from a pool or logs a fatal error and terminates the process if the pool
591  * doesn't have any free objects to allocate.
592  *
593  * @return Pointer to the allocated object.
594  *
595  * @note On failure, the process exits, so you don't have to worry about checking the
596  * returned pointer for validity.
597  */
598  //----------------------------------------------------------------------------------------------
599  void* le_mem_AssertAlloc
600  (
601  le_mem_PoolRef_t pool ///< [IN] Pool from which the object is to be allocated.
602  );
603 #else
604  /// @cond HIDDEN_IN_USER_DOCS
605  void* _le_mem_AssertAlloc(le_mem_PoolRef_t pool);
606  /// @endcond
607 
608  #define le_mem_AssertAlloc(pool) \
609  _le_mem_AllocTracer(pool, \
610  _le_mem_AssertAlloc, \
611  "le_mem_AssertAlloc", \
612  __FILE__, \
613  __FUNCTION__, \
614  __LINE__)
615 #endif
616 
617 
618 #ifndef LE_MEM_TRACE
619  //----------------------------------------------------------------------------------------------
620  /**
621  * Allocates an object from a pool or logs a warning and expands the pool if the pool
622  * doesn't have any free objects to allocate.
623  *
624  * @return Pointer to the allocated object.
625  *
626  * @note On failure, the process exits, so you don't have to worry about checking the
627  * returned pointer for validity.
628  */
629  //----------------------------------------------------------------------------------------------
630  void* le_mem_ForceAlloc
631  (
632  le_mem_PoolRef_t pool ///< [IN] Pool from which the object is to be allocated.
633  );
634 #else
635  /// @cond HIDDEN_IN_USER_DOCS
636  void* _le_mem_ForceAlloc(le_mem_PoolRef_t pool);
637  /// @endcond
638 
639  #define le_mem_ForceAlloc(pool) \
640  _le_mem_AllocTracer(pool, \
641  _le_mem_ForceAlloc, \
642  "le_mem_ForceAlloc", \
643  __FILE__, \
644  __FUNCTION__, \
645  __LINE__)
646 #endif
647 
648 
649 //--------------------------------------------------------------------------------------------------
650 /**
651  * Sets the number of objects that are added when le_mem_ForceAlloc expands the pool.
652  *
653  * @return
654  * Nothing.
655  *
656  * @note
657  * The default value is one.
658  */
659 //--------------------------------------------------------------------------------------------------
661 (
662  le_mem_PoolRef_t pool, ///< [IN] Pool to set the number of objects for.
663  size_t numObjects ///< [IN] Number of objects that is added when
664  /// le_mem_ForceAlloc expands the pool.
665 );
666 
667 
668 #ifndef LE_MEM_TRACE
669  //----------------------------------------------------------------------------------------------
670  /**
671  * Releases an object. If the object's reference count has reached zero, it will be destructed
672  * and its memory will be put back into the pool for later reuse.
673  *
674  * @return
675  * Nothing.
676  *
677  * @warning
678  * - <b>Don't EVER access an object after releasing it.</b> It might not exist anymore.
679  * - If the object has a destructor accessing a data structure shared by multiple
680  * threads, ensure you hold the mutex (or take other measures to prevent races) before
681  * releasing the object.
682  */
683  //----------------------------------------------------------------------------------------------
684  void le_mem_Release
685  (
686  void* objPtr ///< [IN] Pointer to the object to be released.
687  );
688 #else
689  /// @cond HIDDEN_IN_USER_DOCS
690  void _le_mem_Release(void* objPtr);
691  /// @endcond
692 
693  #define le_mem_Release(objPtr) \
694  _le_mem_Trace(_le_mem_GetBlockPool(objPtr), \
695  __FILE__, \
696  __FUNCTION__, \
697  __LINE__, \
698  "le_mem_Release", \
699  (objPtr)); \
700  _le_mem_Release(objPtr);
701 #endif
702 
703 
704 #ifndef LE_MEM_TRACE
705  //----------------------------------------------------------------------------------------------
706  /**
707  * Increments the reference count on an object by 1.
708  *
709  * See @ref mem_ref_counting for more information.
710  *
711  * @return
712  * Nothing.
713  */
714  //----------------------------------------------------------------------------------------------
715  void le_mem_AddRef
716  (
717  void* objPtr ///< [IN] Pointer to the object.
718  );
719 #else
720  /// @cond HIDDEN_IN_USER_DOCS
721  void _le_mem_AddRef(void* objPtr);
722  /// @endcond
723 
724  #define le_mem_AddRef(objPtr) \
725  _le_mem_Trace(_le_mem_GetBlockPool(objPtr), \
726  __FILE__, \
727  __FUNCTION__, \
728  __LINE__, \
729  "le_mem_AddRef", \
730  (objPtr)); \
731  _le_mem_AddRef(objPtr);
732 #endif
733 
734 
735 //--------------------------------------------------------------------------------------------------
736 /**
737  * Sets the destructor function for a specified pool.
738  *
739  * See @ref mem_destructors for more information.
740  *
741  * @return
742  * Nothing.
743  */
744 //--------------------------------------------------------------------------------------------------
746 (
747  le_mem_PoolRef_t pool, ///< [IN] The pool.
748  le_mem_Destructor_t destructor ///< [IN] Destructor function.
749 );
750 
751 
752 //--------------------------------------------------------------------------------------------------
753 /**
754  * Fetches the statistics for a specified pool.
755  *
756  * @return
757  * Nothing. Uses output parameter instead.
758  */
759 //--------------------------------------------------------------------------------------------------
760 void le_mem_GetStats
761 (
762  le_mem_PoolRef_t pool, ///< [IN] Pool where stats are to be fetched.
763  le_mem_PoolStats_t* statsPtr ///< [OUT] Pointer to where the stats will be stored.
764 );
765 
766 
767 //--------------------------------------------------------------------------------------------------
768 /**
769  * Resets the statistics for a specified pool.
770  *
771  * @return
772  * Nothing.
773  */
774 //--------------------------------------------------------------------------------------------------
776 (
777  le_mem_PoolRef_t pool ///< [IN] Pool where stats are to be reset.
778 );
779 
780 
781 //--------------------------------------------------------------------------------------------------
782 /**
783  * Gets the memory pool's name, including the component name prefix.
784  *
785  * If the pool were given the name "myPool" and the component that it belongs to is called
786  * "myComponent", then the full pool name returned by this function would be "myComponent.myPool".
787  *
788  * @return
789  * LE_OK if successful.
790  * LE_OVERFLOW if the name was truncated to fit in the provided buffer.
791  */
792 //--------------------------------------------------------------------------------------------------
794 (
795  le_mem_PoolRef_t pool, ///< [IN] The memory pool.
796  char* namePtr, ///< [OUT] Buffer to store the name of the memory pool.
797  size_t bufSize ///< [IN] Size of the buffer namePtr points to.
798 );
799 
800 
801 //--------------------------------------------------------------------------------------------------
802 /**
803  * Checks if the specified pool is a sub-pool.
804  *
805  * @return
806  * true if it is a sub-pool.
807  * false if it is not a sub-pool.
808  */
809 //--------------------------------------------------------------------------------------------------
810 const bool le_mem_IsSubPool
811 (
812  le_mem_PoolRef_t pool ///< [IN] The memory pool.
813 );
814 
815 
816 //--------------------------------------------------------------------------------------------------
817 /**
818  * Fetches the number of objects a specified pool can hold (this includes both the number of
819  * free and in-use objects).
820  *
821  * @return
822  * Total number of objects.
823  */
824 //--------------------------------------------------------------------------------------------------
826 (
827  le_mem_PoolRef_t pool ///< [IN] Pool where number of objects is to be fetched.
828 );
829 
830 
831 //--------------------------------------------------------------------------------------------------
832 /**
833  * Fetches the size of the objects in a specified pool (in bytes).
834  *
835  * @return
836  * Object size, in bytes.
837  */
838 //--------------------------------------------------------------------------------------------------
840 (
841  le_mem_PoolRef_t pool ///< [IN] Pool where object size is to be fetched.
842 );
843 
844 
845 //--------------------------------------------------------------------------------------------------
846 /**
847  * Fetches the total size of the object including all the memory overhead in a given pool (in bytes).
848  *
849  * @return
850  * Total object memory size, in bytes.
851  */
852 //--------------------------------------------------------------------------------------------------
854 (
855  le_mem_PoolRef_t pool ///< [IN] The pool whose object memory size is to be fetched.
856 );
857 
858 
859 //--------------------------------------------------------------------------------------------------
860 /** @cond HIDDEN_IN_USER_DOCS
861  *
862  * Internal function used to implement le_mem_FindPool() with automatic component scoping
863  * of pool names.
864  */
865 //--------------------------------------------------------------------------------------------------
866 le_mem_PoolRef_t _le_mem_FindPool
867 (
868  const char* componentName, ///< [IN] Name of the component.
869  const char* name ///< [IN] Name of the pool inside the component.
870 );
871 /// @endcond
872 
873 
874 //--------------------------------------------------------------------------------------------------
875 /**
876  * Finds a pool based on the pool's name.
877  *
878  * @return
879  * Reference to the pool, or NULL if the pool doesn't exist.
880  */
881 //--------------------------------------------------------------------------------------------------
882 static inline le_mem_PoolRef_t le_mem_FindPool
883 (
884  const char* name ///< [IN] Name of the pool.
885 )
886 {
887  return _le_mem_FindPool(STRINGIZE(LE_COMPONENT_NAME), name);
888 }
889 
890 
891 //--------------------------------------------------------------------------------------------------
892 /** @cond HIDDEN_IN_USER_DOCS
893  *
894  * Internal function used to implement le_mem_CreateSubPool() with automatic component scoping
895  * of pool names.
896  */
897 //--------------------------------------------------------------------------------------------------
898 le_mem_PoolRef_t _le_mem_CreateSubPool
899 (
900  le_mem_PoolRef_t superPool, ///< [IN] Super-pool.
901  const char* componentName, ///< [IN] Name of the component.
902  const char* name, ///< [IN] Name of the sub-pool (will be copied into the
903  /// sub-pool).
904  size_t numObjects ///< [IN] Number of objects to take from the super-pool.
905 );
906 /// @endcond
907 
908 
909 //--------------------------------------------------------------------------------------------------
910 /**
911  * Creates a sub-pool. You can't create sub-pools of sub-pools so do not attempt to pass a
912  * sub-pool in the superPool parameter.
913  *
914  * See @ref mem_sub_pools for more information.
915  *
916  * @return
917  * Reference to the sub-pool.
918  */
919 //--------------------------------------------------------------------------------------------------
921 (
922  le_mem_PoolRef_t superPool, ///< [IN] Super-pool.
923  const char* name, ///< [IN] Name of the sub-pool (will be copied into the
924  /// sub-pool).
925  size_t numObjects ///< [IN] Number of objects to take from the super-pool.
926 )
927 {
928  return _le_mem_CreateSubPool(superPool, STRINGIZE(LE_COMPONENT_NAME), name, numObjects);
929 }
930 
931 
932 //--------------------------------------------------------------------------------------------------
933 /**
934  * Deletes a sub-pool.
935  *
936  * See @ref mem_sub_pools for more information.
937  *
938  * @return
939  * Nothing.
940  */
941 //--------------------------------------------------------------------------------------------------
943 (
944  le_mem_PoolRef_t subPool ///< [IN] Sub-pool to be deleted.
945 );
946 
947 
948 #endif // LEGATO_MEM_INCLUDE_GUARD
void * le_mem_TryAlloc(le_mem_PoolRef_t pool)
le_mem_PoolRef_t le_mem_ExpandPool(le_mem_PoolRef_t pool, size_t numObjects)
uint64_t numAllocs
Number of times an object has been allocated from this pool.
Definition: le_mem.h:446
le_result_t
Definition: le_basics.h:35
void * le_mem_AssertAlloc(le_mem_PoolRef_t pool)
void le_mem_GetStats(le_mem_PoolRef_t pool, le_mem_PoolStats_t *statsPtr)
const bool le_mem_IsSubPool(le_mem_PoolRef_t pool)
size_t numBlocksInUse
Number of currently allocated blocks.
Definition: le_mem.h:443
static le_mem_PoolRef_t le_mem_FindPool(const char *name)
Definition: le_mem.h:883
size_t maxNumBlocksUsed
Maximum number of allocated blocks at any one time.
Definition: le_mem.h:444
#define STRINGIZE(x)
Definition: le_basics.h:206
void le_mem_SetDestructor(le_mem_PoolRef_t pool, le_mem_Destructor_t destructor)
static le_mem_PoolRef_t le_mem_CreatePool(const char *name, size_t objSize)
Definition: le_mem.h:529
void le_mem_ResetStats(le_mem_PoolRef_t pool)
void le_mem_SetNumObjsToForce(le_mem_PoolRef_t pool, size_t numObjects)
void le_mem_DeleteSubPool(le_mem_PoolRef_t subPool)
struct le_mem_Pool * le_mem_PoolRef_t
Definition: le_mem.h:414
le_result_t le_mem_GetName(le_mem_PoolRef_t pool, char *namePtr, size_t bufSize)
void le_mem_Release(void *objPtr)
size_t numFree
Number of free objects currently available in this pool.
Definition: le_mem.h:447
size_t numOverflows
Number of times le_mem_ForceAlloc() had to expand the pool.
Definition: le_mem.h:445
void(* le_mem_Destructor_t)(void *objPtr)
Definition: le_mem.h:431
size_t le_mem_GetObjectCount(le_mem_PoolRef_t pool)
Definition: le_mem.h:441
size_t le_mem_GetObjectFullSize(le_mem_PoolRef_t pool)
size_t le_mem_GetObjectSize(le_mem_PoolRef_t pool)
void le_mem_AddRef(void *objPtr)
void * le_mem_ForceAlloc(le_mem_PoolRef_t pool)
static le_mem_PoolRef_t le_mem_CreateSubPool(le_mem_PoolRef_t superPool, const char *name, size_t numObjects)
Definition: le_mem.h:921