unified: rename 'memory maps' to 'memory slabs'
This better aligns with the actual functionality of the object. Change-Id: I70abf54f994e92abd7367251089ea4f735d273fe Signed-off-by: Benjamin Walsh <benjamin.walsh@windriver.com>
This commit is contained in:
parent
3c7dda3897
commit
7ef0f624a7
9 changed files with 242 additions and 236 deletions
|
@ -1,145 +0,0 @@
|
||||||
.. _memory_maps_v2:
|
|
||||||
|
|
||||||
Memory Maps
|
|
||||||
###########
|
|
||||||
|
|
||||||
A :dfn:`memory map` is a kernel object that allows memory blocks
|
|
||||||
to be dynamically allocated from a designated memory region.
|
|
||||||
All memory blocks in a memory map have a single fixed size,
|
|
||||||
allowing them to be allocated and released efficiently
|
|
||||||
and avoiding memory fragmentation concerns.
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:local:
|
|
||||||
:depth: 2
|
|
||||||
|
|
||||||
Concepts
|
|
||||||
********
|
|
||||||
|
|
||||||
Any number of memory maps can be defined. Each memory map is referenced
|
|
||||||
by its memory address.
|
|
||||||
|
|
||||||
A memory map has the following key properties:
|
|
||||||
|
|
||||||
* The **block size** of each block, measured in bytes.
|
|
||||||
It must be at least 4 bytes long.
|
|
||||||
|
|
||||||
* The **number of blocks** available for allocation.
|
|
||||||
It must be greater than zero.
|
|
||||||
|
|
||||||
* A **buffer** that provides the memory for the memory map's blocks.
|
|
||||||
It must be at least "block size" times "number of blocks" bytes long.
|
|
||||||
|
|
||||||
A thread that needs to use a memory block simply allocates it from a memory
|
|
||||||
map. When the thread finishes with a memory block,
|
|
||||||
it must release the block back to the memory map so the block can be reused.
|
|
||||||
|
|
||||||
If all the blocks are currently in use, a thread can optionally wait
|
|
||||||
for one to become available.
|
|
||||||
Any number of thread may wait on an empty memory map simultaneously;
|
|
||||||
when a memory block becomes available, it is given to the highest-priority
|
|
||||||
thread that has waited the longest.
|
|
||||||
|
|
||||||
Unlike a heap, more than one memory map can be defined, if needed. This
|
|
||||||
allows for a memory map with smaller blocks and others with larger-sized
|
|
||||||
blocks. Alternatively, a memory pool object may be used.
|
|
||||||
|
|
||||||
Internal Operation
|
|
||||||
==================
|
|
||||||
|
|
||||||
A memory map's buffer is an array of fixed-size blocks,
|
|
||||||
with no wasted space between the blocks.
|
|
||||||
|
|
||||||
The memory map keeps track of unallocated blocks using a linked list;
|
|
||||||
the first 4 bytes of each unused block provide the necessary linkage.
|
|
||||||
|
|
||||||
Implementation
|
|
||||||
**************
|
|
||||||
|
|
||||||
Defining a Memory Map
|
|
||||||
=====================
|
|
||||||
|
|
||||||
A memory map is defined using a variable of type :c:type:`struct k_mem_map`.
|
|
||||||
It must then be initialized by calling :cpp:func:`k_mem_map_init()`.
|
|
||||||
|
|
||||||
The following code defines and initializes a memory map that has 6 blocks
|
|
||||||
of 400 bytes each and is aligned to a 4-byte boundary..
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
struct k_mem_map my_map;
|
|
||||||
char __aligned(4) my_map_buffer[6 * 400];
|
|
||||||
|
|
||||||
k_mem_map_init(&my_map, my_map_buffer, 400, 6);
|
|
||||||
|
|
||||||
Alternatively, a memory map can be defined and initialized at compile time
|
|
||||||
by calling :c:macro:`K_MEM_MAP_DEFINE()`.
|
|
||||||
|
|
||||||
The following code has the same effect as the code segment above. Observe
|
|
||||||
that the macro defines both the memory map and its buffer.
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
K_MEM_MAP_DEFINE(my_map, 400, 6, 4);
|
|
||||||
|
|
||||||
Allocating a Memory Block
|
|
||||||
=========================
|
|
||||||
|
|
||||||
A memory block is allocated by calling :cpp:func:`k_mem_map_alloc()`.
|
|
||||||
|
|
||||||
The following code builds on the example above, and waits up to 100 milliseconds
|
|
||||||
for a memory block to become available, then fills it with zeroes.
|
|
||||||
A warning is printed if a suitable block is not obtained.
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
char *block_ptr;
|
|
||||||
|
|
||||||
if (k_mem_map_alloc(&my_map, &block_ptr, 100) == 0)) {
|
|
||||||
memset(block_ptr, 0, 400);
|
|
||||||
...
|
|
||||||
} else {
|
|
||||||
printf("Memory allocation time-out");
|
|
||||||
}
|
|
||||||
|
|
||||||
Releasing a Memory Block
|
|
||||||
========================
|
|
||||||
|
|
||||||
A memory block is released by calling :cpp:func:`k_mem_map_free()`.
|
|
||||||
|
|
||||||
The following code builds on the example above, and allocates a memory block,
|
|
||||||
then releases it once it is no longer needed.
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
char *block_ptr;
|
|
||||||
|
|
||||||
k_mem_map_alloc(&my_map, &block_ptr, K_FOREVER);
|
|
||||||
... /* use memory block pointed at by block_ptr */
|
|
||||||
k_mem_map_free(&my_map, &block_ptr);
|
|
||||||
|
|
||||||
Suggested Uses
|
|
||||||
**************
|
|
||||||
|
|
||||||
Use a memory map to allocate and free memory in fixed-size blocks.
|
|
||||||
|
|
||||||
Use memory map blocks when sending large amounts of data from one thread
|
|
||||||
to another, to avoid unnecessary copying of the data.
|
|
||||||
|
|
||||||
Configuration Options
|
|
||||||
*********************
|
|
||||||
|
|
||||||
Related configuration options:
|
|
||||||
|
|
||||||
* None.
|
|
||||||
|
|
||||||
APIs
|
|
||||||
****
|
|
||||||
|
|
||||||
The following memory map APIs are provided by :file:`kernel.h`:
|
|
||||||
|
|
||||||
* :cpp:func:`k_mem_map_init()`
|
|
||||||
* :cpp:func:`k_mem_map_alloc()`
|
|
||||||
* :cpp:func:`k_mem_map_free()`
|
|
||||||
* :cpp:func:`k_mem_map_num_used_get()`
|
|
||||||
* :cpp:func:`k_mem_map_num_free_get()`
|
|
|
@ -9,6 +9,6 @@ allocate memory.
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
maps.rst
|
slabs.rst
|
||||||
pools.rst
|
pools.rst
|
||||||
heap.rst
|
heap.rst
|
||||||
|
|
145
doc/kernel_v2/memory/slabs.rst
Normal file
145
doc/kernel_v2/memory/slabs.rst
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
.. _memory_slabs_v2:
|
||||||
|
|
||||||
|
Memory slabs
|
||||||
|
############
|
||||||
|
|
||||||
|
A :dfn:`memory slab` is a kernel object that allows memory blocks
|
||||||
|
to be dynamically allocated from a designated memory region.
|
||||||
|
All memory blocks in a memory slab have a single fixed size,
|
||||||
|
allowing them to be allocated and released efficiently
|
||||||
|
and avoiding memory fragmentation concerns.
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
:depth: 2
|
||||||
|
|
||||||
|
Concepts
|
||||||
|
********
|
||||||
|
|
||||||
|
Any number of memory slabs can be defined. Each memory slab is referenced
|
||||||
|
by its memory address.
|
||||||
|
|
||||||
|
A memory slab has the following key properties:
|
||||||
|
|
||||||
|
* The **block size** of each block, measured in bytes.
|
||||||
|
It must be at least 4 bytes long.
|
||||||
|
|
||||||
|
* The **number of blocks** available for allocation.
|
||||||
|
It must be greater than zero.
|
||||||
|
|
||||||
|
* A **buffer** that provides the memory for the memory slab's blocks.
|
||||||
|
It must be at least "block size" times "number of blocks" bytes long.
|
||||||
|
|
||||||
|
A thread that needs to use a memory block simply allocates it from a memory
|
||||||
|
slab. When the thread finishes with a memory block,
|
||||||
|
it must release the block back to the memory slab so the block can be reused.
|
||||||
|
|
||||||
|
If all the blocks are currently in use, a thread can optionally wait
|
||||||
|
for one to become available.
|
||||||
|
Any number of threads may wait on an empty memory slab simultaneously;
|
||||||
|
when a memory block becomes available, it is given to the highest-priority
|
||||||
|
thread that has waited the longest.
|
||||||
|
|
||||||
|
Unlike a heap, more than one memory slab can be defined, if needed. This
|
||||||
|
allows for a memory slab with smaller blocks and others with larger-sized
|
||||||
|
blocks. Alternatively, a memory pool object may be used.
|
||||||
|
|
||||||
|
Internal Operation
|
||||||
|
==================
|
||||||
|
|
||||||
|
A memory slab's buffer is an array of fixed-size blocks,
|
||||||
|
with no wasted space between the blocks.
|
||||||
|
|
||||||
|
The memory slab keeps track of unallocated blocks using a linked list;
|
||||||
|
the first 4 bytes of each unused block provide the necessary linkage.
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
**************
|
||||||
|
|
||||||
|
Defining a Memory Slab
|
||||||
|
======================
|
||||||
|
|
||||||
|
A memory slab is defined using a variable of type :c:type:`struct k_mem_slab`.
|
||||||
|
It must then be initialized by calling :cpp:func:`k_mem_slab_init()`.
|
||||||
|
|
||||||
|
The following code defines and initializes a memory slab that has 6 blocks
|
||||||
|
of 400 bytes each and is aligned to a 4-byte boundary..
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
struct k_mem_slab my_slab;
|
||||||
|
char __aligned(4) my_slab_buffer[6 * 400];
|
||||||
|
|
||||||
|
k_mem_slab_init(&my_slab, my_slab_buffer, 400, 6);
|
||||||
|
|
||||||
|
Alternatively, a memory slab can be defined and initialized at compile time
|
||||||
|
by calling :c:macro:`K_MEM_SLAB_DEFINE()`.
|
||||||
|
|
||||||
|
The following code has the same effect as the code segment above. Observe
|
||||||
|
that the macro defines both the memory slab and its buffer.
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
K_MEM_SLAB_DEFINE(my_slab, 400, 6, 4);
|
||||||
|
|
||||||
|
Allocating a Memory Block
|
||||||
|
=========================
|
||||||
|
|
||||||
|
A memory block is allocated by calling :cpp:func:`k_mem_slab_alloc()`.
|
||||||
|
|
||||||
|
The following code builds on the example above, and waits up to 100 milliseconds
|
||||||
|
for a memory block to become available, then fills it with zeroes.
|
||||||
|
A warning is printed if a suitable block is not obtained.
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
char *block_ptr;
|
||||||
|
|
||||||
|
if (k_mem_slab_alloc(&my_slab, &block_ptr, 100) == 0)) {
|
||||||
|
memset(block_ptr, 0, 400);
|
||||||
|
...
|
||||||
|
} else {
|
||||||
|
printf("Memory allocation time-out");
|
||||||
|
}
|
||||||
|
|
||||||
|
Releasing a Memory Block
|
||||||
|
========================
|
||||||
|
|
||||||
|
A memory block is released by calling :cpp:func:`k_mem_slab_free()`.
|
||||||
|
|
||||||
|
The following code builds on the example above, and allocates a memory block,
|
||||||
|
then releases it once it is no longer needed.
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
char *block_ptr;
|
||||||
|
|
||||||
|
k_mem_slab_alloc(&my_slab, &block_ptr, K_FOREVER);
|
||||||
|
... /* use memory block pointed at by block_ptr */
|
||||||
|
k_mem_slab_free(&my_slab, &block_ptr);
|
||||||
|
|
||||||
|
Suggested Uses
|
||||||
|
**************
|
||||||
|
|
||||||
|
Use a memory slab to allocate and free memory in fixed-size blocks.
|
||||||
|
|
||||||
|
Use memory slab blocks when sending large amounts of data from one thread
|
||||||
|
to another, to avoid unnecessary copying of the data.
|
||||||
|
|
||||||
|
Configuration Options
|
||||||
|
*********************
|
||||||
|
|
||||||
|
Related configuration options:
|
||||||
|
|
||||||
|
* None.
|
||||||
|
|
||||||
|
APIs
|
||||||
|
****
|
||||||
|
|
||||||
|
The following memory slab APIs are provided by :file:`kernel.h`:
|
||||||
|
|
||||||
|
* :cpp:func:`k_mem_slab_init()`
|
||||||
|
* :cpp:func:`k_mem_slab_alloc()`
|
||||||
|
* :cpp:func:`k_mem_slab_free()`
|
||||||
|
* :cpp:func:`k_mem_slab_num_used_get()`
|
||||||
|
* :cpp:func:`k_mem_slab_num_free_get()`
|
|
@ -120,6 +120,9 @@ The microkernel mailbox object type now supports the sending of asynchronous
|
||||||
messages using a message buffer. (The version 1 kernel only supported
|
messages using a message buffer. (The version 1 kernel only supported
|
||||||
asynchronous messages using a message block.)
|
asynchronous messages using a message block.)
|
||||||
|
|
||||||
|
The microkernel memory map object has been renamed to "memory slab", to better
|
||||||
|
reflect its management of equal-size memory blocks.
|
||||||
|
|
||||||
Task Groups
|
Task Groups
|
||||||
***********
|
***********
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ struct k_pipe;
|
||||||
struct k_fifo;
|
struct k_fifo;
|
||||||
struct k_lifo;
|
struct k_lifo;
|
||||||
struct k_stack;
|
struct k_stack;
|
||||||
struct k_mem_map;
|
struct k_mem_slab;
|
||||||
struct k_mem_pool;
|
struct k_mem_pool;
|
||||||
struct k_timer;
|
struct k_timer;
|
||||||
|
|
||||||
|
@ -1395,9 +1395,9 @@ extern void k_pipe_block_put(struct k_pipe *pipe, struct k_mem_block *block,
|
||||||
* memory management
|
* memory management
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* memory maps */
|
/* memory slabs */
|
||||||
|
|
||||||
struct k_mem_map {
|
struct k_mem_slab {
|
||||||
_wait_q_t wait_q;
|
_wait_q_t wait_q;
|
||||||
uint32_t num_blocks;
|
uint32_t num_blocks;
|
||||||
size_t block_size;
|
size_t block_size;
|
||||||
|
@ -1405,65 +1405,66 @@ struct k_mem_map {
|
||||||
char *free_list;
|
char *free_list;
|
||||||
uint32_t num_used;
|
uint32_t num_used;
|
||||||
|
|
||||||
_DEBUG_TRACING_KERNEL_OBJECTS_NEXT_PTR(k_mem_map);
|
_DEBUG_TRACING_KERNEL_OBJECTS_NEXT_PTR(k_mem_slab);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define K_MEM_MAP_INITIALIZER(obj, map_buffer, map_block_size, map_num_blocks) \
|
#define K_MEM_SLAB_INITIALIZER(obj, slab_buffer, slab_block_size, \
|
||||||
|
slab_num_blocks) \
|
||||||
{ \
|
{ \
|
||||||
.wait_q = SYS_DLIST_STATIC_INIT(&obj.wait_q), \
|
.wait_q = SYS_DLIST_STATIC_INIT(&obj.wait_q), \
|
||||||
.num_blocks = map_num_blocks, \
|
.num_blocks = slab_num_blocks, \
|
||||||
.block_size = map_block_size, \
|
.block_size = slab_block_size, \
|
||||||
.buffer = map_buffer, \
|
.buffer = slab_buffer, \
|
||||||
.free_list = NULL, \
|
.free_list = NULL, \
|
||||||
.num_used = 0, \
|
.num_used = 0, \
|
||||||
_DEBUG_TRACING_KERNEL_OBJECTS_INIT \
|
_DEBUG_TRACING_KERNEL_OBJECTS_INIT \
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Define a memory map
|
* @brief Define a memory slab
|
||||||
*
|
*
|
||||||
* This declares and initializes a memory map whose buffer is aligned to
|
* This declares and initializes a memory slab whose buffer is aligned to
|
||||||
* a @a map_align -byte boundary. The new memory map can be passed to the
|
* a @a slab_align -byte boundary. The new memory slab can be passed to the
|
||||||
* kernel's memory map functions.
|
* kernel's memory slab functions.
|
||||||
*
|
*
|
||||||
* Note that for each of the blocks in the memory map to be aligned to
|
* Note that for each of the blocks in the memory slab to be aligned to
|
||||||
* @a map_align bytes, then @a map_block_size must be a multiple of
|
* @a slab_align bytes, then @a slab_block_size must be a multiple of
|
||||||
* @a map_align.
|
* @a slab_align.
|
||||||
*
|
*
|
||||||
* @param name Name of the memory map
|
* @param name Name of the memory slab
|
||||||
* @param map_block_size Size of each block in the buffer (in bytes)
|
* @param slab_block_size Size of each block in the buffer (in bytes)
|
||||||
* @param map_num_blocks Number blocks in the buffer
|
* @param slab_num_blocks Number blocks in the buffer
|
||||||
* @param map_align Alignment of the memory map's buffer (power of 2)
|
* @param slab_align Alignment of the memory slab's buffer (power of 2)
|
||||||
*/
|
*/
|
||||||
#define K_MEM_MAP_DEFINE(name, map_block_size, map_num_blocks, map_align) \
|
#define K_MEM_SLAB_DEFINE(name, slab_block_size, slab_num_blocks, slab_align) \
|
||||||
char __noinit __aligned(map_align) \
|
char __noinit __aligned(slab_align) \
|
||||||
_k_mem_map_buf_##name[(map_num_blocks) * (map_block_size)]; \
|
_k_mem_slab_buf_##name[(slab_num_blocks) * (slab_block_size)]; \
|
||||||
struct k_mem_map name \
|
struct k_mem_slab name \
|
||||||
__in_section(_k_mem_map_ptr, private, mem_map) = \
|
__in_section(_k_mem_map_ptr, private, mem_slab) = \
|
||||||
K_MEM_MAP_INITIALIZER(name, _k_mem_map_buf_##name, \
|
K_MEM_SLAB_INITIALIZER(name, _k_mem_slab_buf_##name, \
|
||||||
map_block_size, map_num_blocks)
|
slab_block_size, slab_num_blocks)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize a memory map.
|
* @brief Initialize a memory slab.
|
||||||
*
|
*
|
||||||
* Initializes the memory map and creates its list of free blocks.
|
* Initializes the memory slab and creates its list of free blocks.
|
||||||
*
|
*
|
||||||
* @param map Pointer to the memory map object
|
* @param slab Pointer to the memory slab object
|
||||||
* @param buffer Pointer to buffer used for the blocks.
|
* @param buffer Pointer to buffer used for the blocks.
|
||||||
* @param block_size Size of each block, in bytes.
|
* @param block_size Size of each block, in bytes.
|
||||||
* @param num_blocks Number of blocks.
|
* @param num_blocks Number of blocks.
|
||||||
*
|
*
|
||||||
* @return N/A
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
extern void k_mem_map_init(struct k_mem_map *map, void *buffer,
|
extern void k_mem_slab_init(struct k_mem_slab *slab, void *buffer,
|
||||||
size_t block_size, uint32_t num_blocks);
|
size_t block_size, uint32_t num_blocks);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Allocate a memory map block.
|
* @brief Allocate a memory slab block.
|
||||||
*
|
*
|
||||||
* Takes a block from the list of unused blocks.
|
* Takes a block from the list of unused blocks.
|
||||||
*
|
*
|
||||||
* @param map Pointer to memory map object.
|
* @param slab Pointer to memory slab object.
|
||||||
* @param mem Pointer to area to receive block address.
|
* @param mem Pointer to area to receive block address.
|
||||||
* @param timeout Maximum time (milliseconds) to wait for allocation to
|
* @param timeout Maximum time (milliseconds) to wait for allocation to
|
||||||
* complete. Use K_NO_WAIT to return immediately, or K_FOREVER to wait
|
* complete. Use K_NO_WAIT to return immediately, or K_FOREVER to wait
|
||||||
|
@ -1471,20 +1472,21 @@ extern void k_mem_map_init(struct k_mem_map *map, void *buffer,
|
||||||
*
|
*
|
||||||
* @return 0 if successful, -ENOMEM if failed immediately, -EAGAIN if timed out
|
* @return 0 if successful, -ENOMEM if failed immediately, -EAGAIN if timed out
|
||||||
*/
|
*/
|
||||||
extern int k_mem_map_alloc(struct k_mem_map *map, void **mem, int32_t timeout);
|
extern int k_mem_slab_alloc(struct k_mem_slab *slab, void **mem,
|
||||||
|
int32_t timeout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Free a memory map block.
|
* @brief Free a memory slab block.
|
||||||
*
|
*
|
||||||
* Gives block to a waiting thread if there is one, otherwise returns it to
|
* Gives block to a waiting thread if there is one, otherwise returns it to
|
||||||
* the list of unused blocks.
|
* the list of unused blocks.
|
||||||
*
|
*
|
||||||
* @param map Pointer to memory map object.
|
* @param slab Pointer to memory slab object.
|
||||||
* @param mem Pointer to area to containing block address.
|
* @param mem Pointer to area to containing block address.
|
||||||
*
|
*
|
||||||
* @return N/A
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
extern void k_mem_map_free(struct k_mem_map *map, void **mem);
|
extern void k_mem_slab_free(struct k_mem_slab *slab, void **mem);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the number of used memory blocks
|
* @brief Get the number of used memory blocks
|
||||||
|
@ -1493,13 +1495,13 @@ extern void k_mem_map_free(struct k_mem_map *map, void **mem);
|
||||||
* specified pool. It should be used for stats purposes only as that
|
* specified pool. It should be used for stats purposes only as that
|
||||||
* value may potentially be out-of-date by the time it is used.
|
* value may potentially be out-of-date by the time it is used.
|
||||||
*
|
*
|
||||||
* @param map Memory map to query
|
* @param slab Memory slab to query
|
||||||
*
|
*
|
||||||
* @return Number of used memory blocks
|
* @return Number of used memory blocks
|
||||||
*/
|
*/
|
||||||
static inline uint32_t k_mem_map_num_used_get(struct k_mem_map *map)
|
static inline uint32_t k_mem_slab_num_used_get(struct k_mem_slab *slab)
|
||||||
{
|
{
|
||||||
return map->num_used;
|
return slab->num_used;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1509,13 +1511,13 @@ static inline uint32_t k_mem_map_num_used_get(struct k_mem_map *map)
|
||||||
* specified pool. It should be used for stats purposes only as that value
|
* specified pool. It should be used for stats purposes only as that value
|
||||||
* may potentially be out-of-date by the time it is used.
|
* may potentially be out-of-date by the time it is used.
|
||||||
*
|
*
|
||||||
* @param map Memory map to query
|
* @param slab Memory slab to query
|
||||||
*
|
*
|
||||||
* @return Number of unused memory blocks
|
* @return Number of unused memory blocks
|
||||||
*/
|
*/
|
||||||
static inline uint32_t k_mem_map_num_free_get(struct k_mem_map *map)
|
static inline uint32_t k_mem_slab_num_free_get(struct k_mem_slab *slab)
|
||||||
{
|
{
|
||||||
return map->num_blocks - map->num_used;
|
return slab->num_blocks - slab->num_used;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* memory pools */
|
/* memory pools */
|
||||||
|
|
|
@ -398,25 +398,26 @@ static inline int task_event_recv(kevent_t legacy_event, int32_t timeout)
|
||||||
|
|
||||||
/* memory maps */
|
/* memory maps */
|
||||||
|
|
||||||
#define kmemory_map_t struct k_mem_map *
|
#define kmemory_map_t struct k_mem_slab *
|
||||||
|
|
||||||
static inline int task_mem_map_alloc(kmemory_map_t map, void **mptr,
|
static inline int task_mem_map_alloc(kmemory_map_t map, void **mptr,
|
||||||
int32_t timeout)
|
int32_t timeout)
|
||||||
{
|
{
|
||||||
return _error_to_rc(k_mem_map_alloc(map, mptr, _ticks_to_ms(timeout)));
|
return _error_to_rc(k_mem_slab_alloc(map, mptr,
|
||||||
|
_ticks_to_ms(timeout)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define task_mem_map_free k_mem_map_free
|
#define task_mem_map_free k_mem_slab_free
|
||||||
|
|
||||||
static inline int task_mem_map_used_get(kmemory_map_t map)
|
static inline int task_mem_map_used_get(kmemory_map_t map)
|
||||||
{
|
{
|
||||||
return (int)k_mem_map_num_used_get(map);
|
return (int)k_mem_slab_num_used_get(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DEFINE_MEM_MAP(name, map_num_blocks, map_block_size) \
|
#define DEFINE_MEM_MAP(name, map_num_blocks, map_block_size) \
|
||||||
K_MEM_MAP_DEFINE(_k_mem_map_obj_##name, map_block_size, \
|
K_MEM_SLAB_DEFINE(_k_mem_map_obj_##name, map_block_size, \
|
||||||
map_num_blocks, 4); \
|
map_num_blocks, 4); \
|
||||||
struct k_mem_map *const name = &_k_mem_map_obj_##name
|
struct k_mem_slab *const name = &_k_mem_map_obj_##name
|
||||||
|
|
||||||
|
|
||||||
/* memory pools */
|
/* memory pools */
|
||||||
|
|
|
@ -21,7 +21,7 @@ lib-y += $(strip \
|
||||||
lifo.o \
|
lifo.o \
|
||||||
fifo.o \
|
fifo.o \
|
||||||
stack.o \
|
stack.o \
|
||||||
mem_map.o \
|
mem_slab.o \
|
||||||
mem_pool.o \
|
mem_pool.o \
|
||||||
msg_q.o \
|
msg_q.o \
|
||||||
mailbox.o \
|
mailbox.o \
|
||||||
|
|
|
@ -24,73 +24,73 @@
|
||||||
#include <ksched.h>
|
#include <ksched.h>
|
||||||
#include <init.h>
|
#include <init.h>
|
||||||
|
|
||||||
extern struct k_mem_map _k_mem_map_ptr_start[];
|
extern struct k_mem_slab _k_mem_map_ptr_start[];
|
||||||
extern struct k_mem_map _k_mem_map_ptr_end[];
|
extern struct k_mem_slab _k_mem_map_ptr_end[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize kernel memory map subsystem.
|
* @brief Initialize kernel memory slab subsystem.
|
||||||
*
|
*
|
||||||
* Perform any initialization of memory maps that wasn't done at build time.
|
* Perform any initialization of memory slabs that wasn't done at build time.
|
||||||
* Currently this just involves creating the list of free blocks for each map.
|
* Currently this just involves creating the list of free blocks for each slab.
|
||||||
*
|
*
|
||||||
* @return N/A
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
static void create_free_list(struct k_mem_map *map)
|
static void create_free_list(struct k_mem_slab *slab)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
map->free_list = NULL;
|
slab->free_list = NULL;
|
||||||
p = map->buffer;
|
p = slab->buffer;
|
||||||
|
|
||||||
for (j = 0; j < map->num_blocks; j++) {
|
for (j = 0; j < slab->num_blocks; j++) {
|
||||||
*(char **)p = map->free_list;
|
*(char **)p = slab->free_list;
|
||||||
map->free_list = p;
|
slab->free_list = p;
|
||||||
p += map->block_size;
|
p += slab->block_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Complete initialization of statically defined memory maps.
|
* @brief Complete initialization of statically defined memory slabs.
|
||||||
*
|
*
|
||||||
* Perform any initialization that wasn't done at build time.
|
* Perform any initialization that wasn't done at build time.
|
||||||
*
|
*
|
||||||
* @return N/A
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
static int init_mem_map_module(struct device *dev)
|
static int init_mem_slab_module(struct device *dev)
|
||||||
{
|
{
|
||||||
ARG_UNUSED(dev);
|
ARG_UNUSED(dev);
|
||||||
|
|
||||||
struct k_mem_map *map;
|
struct k_mem_slab *slab;
|
||||||
|
|
||||||
for (map = _k_mem_map_ptr_start; map < _k_mem_map_ptr_end; map++) {
|
for (slab = _k_mem_map_ptr_start; slab < _k_mem_map_ptr_end; slab++) {
|
||||||
create_free_list(map);
|
create_free_list(slab);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void k_mem_map_init(struct k_mem_map *map, void *buffer,
|
void k_mem_slab_init(struct k_mem_slab *slab, void *buffer,
|
||||||
size_t block_size, uint32_t num_blocks)
|
size_t block_size, uint32_t num_blocks)
|
||||||
{
|
{
|
||||||
map->num_blocks = num_blocks;
|
slab->num_blocks = num_blocks;
|
||||||
map->block_size = block_size;
|
slab->block_size = block_size;
|
||||||
map->buffer = buffer;
|
slab->buffer = buffer;
|
||||||
map->num_used = 0;
|
slab->num_used = 0;
|
||||||
create_free_list(map);
|
create_free_list(slab);
|
||||||
sys_dlist_init(&map->wait_q);
|
sys_dlist_init(&slab->wait_q);
|
||||||
SYS_TRACING_OBJ_INIT(mem_map, map);
|
SYS_TRACING_OBJ_INIT(micro_mem_map, slab);
|
||||||
}
|
}
|
||||||
|
|
||||||
int k_mem_map_alloc(struct k_mem_map *map, void **mem, int32_t timeout)
|
int k_mem_slab_alloc(struct k_mem_slab *slab, void **mem, int32_t timeout)
|
||||||
{
|
{
|
||||||
unsigned int key = irq_lock();
|
unsigned int key = irq_lock();
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (map->free_list != NULL) {
|
if (slab->free_list != NULL) {
|
||||||
/* take a free block */
|
/* take a free block */
|
||||||
*mem = map->free_list;
|
*mem = slab->free_list;
|
||||||
map->free_list = *(char **)(map->free_list);
|
slab->free_list = *(char **)(slab->free_list);
|
||||||
map->num_used++;
|
slab->num_used++;
|
||||||
result = 0;
|
result = 0;
|
||||||
} else if (timeout == K_NO_WAIT) {
|
} else if (timeout == K_NO_WAIT) {
|
||||||
/* don't wait for a free block to become available */
|
/* don't wait for a free block to become available */
|
||||||
|
@ -98,7 +98,7 @@ int k_mem_map_alloc(struct k_mem_map *map, void **mem, int32_t timeout)
|
||||||
result = -ENOMEM;
|
result = -ENOMEM;
|
||||||
} else {
|
} else {
|
||||||
/* wait for a free block or timeout */
|
/* wait for a free block or timeout */
|
||||||
_pend_current_thread(&map->wait_q, timeout);
|
_pend_current_thread(&slab->wait_q, timeout);
|
||||||
result = _Swap(key);
|
result = _Swap(key);
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
*mem = _current->swap_data;
|
*mem = _current->swap_data;
|
||||||
|
@ -111,10 +111,10 @@ int k_mem_map_alloc(struct k_mem_map *map, void **mem, int32_t timeout)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void k_mem_map_free(struct k_mem_map *map, void **mem)
|
void k_mem_slab_free(struct k_mem_slab *slab, void **mem)
|
||||||
{
|
{
|
||||||
int key = irq_lock();
|
int key = irq_lock();
|
||||||
struct k_thread *pending_thread = _unpend_first_thread(&map->wait_q);
|
struct k_thread *pending_thread = _unpend_first_thread(&slab->wait_q);
|
||||||
|
|
||||||
if (pending_thread) {
|
if (pending_thread) {
|
||||||
_set_thread_return_value_with_data(pending_thread, 0, *mem);
|
_set_thread_return_value_with_data(pending_thread, 0, *mem);
|
||||||
|
@ -125,12 +125,12 @@ void k_mem_map_free(struct k_mem_map *map, void **mem)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
**(char ***)mem = map->free_list;
|
**(char ***)mem = slab->free_list;
|
||||||
map->free_list = *(char **)mem;
|
slab->free_list = *(char **)mem;
|
||||||
map->num_used--;
|
slab->num_used--;
|
||||||
}
|
}
|
||||||
|
|
||||||
irq_unlock(key);
|
irq_unlock(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
SYS_INIT(init_mem_map_module, PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
|
SYS_INIT(init_mem_slab_module, PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
|
|
@ -788,7 +788,7 @@ def kernel_main_c_maps():
|
||||||
name = map[0]
|
name = map[0]
|
||||||
blocks = map[1]
|
blocks = map[1]
|
||||||
block_size = map[2]
|
block_size = map[2]
|
||||||
kernel_main_c_out("K_MEM_MAP_DEFINE(_k_mem_map_obj_%s, %s, %s, 4);\n" %
|
kernel_main_c_out("K_MEM_SLAB_DEFINE(_k_mem_map_obj_%s, %s, %s, 4);\n" %
|
||||||
(name, block_size, blocks))
|
(name, block_size, blocks))
|
||||||
|
|
||||||
|
|
||||||
|
@ -1126,8 +1126,8 @@ def generate_sysgen_h_obj_ids():
|
||||||
sem_type = 'struct k_sem *'
|
sem_type = 'struct k_sem *'
|
||||||
pipe_struct = 'k_pipe'
|
pipe_struct = 'k_pipe'
|
||||||
pipe_type = 'struct k_pipe *'
|
pipe_type = 'struct k_pipe *'
|
||||||
map_struct = 'k_mem_map'
|
map_struct = 'k_mem_slab'
|
||||||
map_type = 'struct k_mem_map *'
|
map_type = 'struct k_mem_slab *'
|
||||||
fifo_struct = 'k_msgq'
|
fifo_struct = 'k_msgq'
|
||||||
fifo_type = 'struct k_msgq *'
|
fifo_type = 'struct k_msgq *'
|
||||||
mbox_struct = 'k_mbox'
|
mbox_struct = 'k_mbox'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue