unified: Implement memory pools
Due to the memory pool structure only static declaration of memory pool is possible. Change-Id: I4797ed88fd2ac3b7812ff26e552e1745611c4575 Signed-off-by: Dmitriy Korovkin <dmitriy.korovkin@windriver.com>
This commit is contained in:
parent
3fb21ac39c
commit
3c426888a1
9 changed files with 938 additions and 99 deletions
|
@ -245,6 +245,18 @@ SECTIONS
|
||||||
_k_event_list_end = .;
|
_k_event_list_end = .;
|
||||||
} GROUP_LINK_IN(RAMABLE_REGION)
|
} GROUP_LINK_IN(RAMABLE_REGION)
|
||||||
|
|
||||||
|
SECTION_PROLOGUE(_k_memory_pool, (OPTIONAL),)
|
||||||
|
{
|
||||||
|
*(._k_memory_pool.struct*)
|
||||||
|
KEEP(*(SORT_BY_NAME("._k_memory_pool.struct*")))
|
||||||
|
|
||||||
|
_k_mem_pool_start = .;
|
||||||
|
*(._k_memory_pool.*)
|
||||||
|
KEEP(*(SORT_BY_NAME("._k_memory_pool*")))
|
||||||
|
_k_mem_pool_end = .;
|
||||||
|
} GROUP_LINK_IN(RAMABLE_REGION)
|
||||||
|
|
||||||
|
|
||||||
__data_ram_end = .;
|
__data_ram_end = .;
|
||||||
|
|
||||||
SECTION_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),)
|
SECTION_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),)
|
||||||
|
|
|
@ -206,6 +206,17 @@ SECTIONS
|
||||||
_k_event_list_end = .;
|
_k_event_list_end = .;
|
||||||
} GROUP_LINK_IN(RAM)
|
} GROUP_LINK_IN(RAM)
|
||||||
|
|
||||||
|
SECTION_PROLOGUE(_k_memory_pool, (OPTIONAL),)
|
||||||
|
{
|
||||||
|
*(._k_memory_pool.struct*)
|
||||||
|
KEEP(*(SORT_BY_NAME("._k_memory_pool.struct*")))
|
||||||
|
|
||||||
|
_k_mem_pool_start = .;
|
||||||
|
*(._k_memory_pool.*)
|
||||||
|
KEEP(*(SORT_BY_NAME("._k_memory_pool*")))
|
||||||
|
_k_mem_pool_end = .;
|
||||||
|
} GROUP_LINK_IN(RAM)
|
||||||
|
|
||||||
__data_ram_end = .;
|
__data_ram_end = .;
|
||||||
|
|
||||||
SECTION_PROLOGUE(_BSS_SECTION_NAME, (NOLOAD OPTIONAL),)
|
SECTION_PROLOGUE(_BSS_SECTION_NAME, (NOLOAD OPTIONAL),)
|
||||||
|
|
201
include/kernel.h
201
include/kernel.h
|
@ -1036,26 +1036,207 @@ static inline int k_mem_map_num_used_get(struct k_mem_map *map)
|
||||||
|
|
||||||
/* memory pools */
|
/* memory pools */
|
||||||
|
|
||||||
struct k_mem_pool {
|
/*
|
||||||
_wait_q_t wait_q;
|
* Memory pool requires a buffer and two arrays of structures for the
|
||||||
int max_block_size;
|
* memory block accounting:
|
||||||
int num_max_blocks;
|
* A set of arrays of k_mem_pool_quad_block structures where each keeps a
|
||||||
|
* status of four blocks of memory.
|
||||||
|
*/
|
||||||
|
struct k_mem_pool_quad_block {
|
||||||
|
char *mem_blocks; /* pointer to the first of four memory blocks */
|
||||||
|
uint32_t mem_status; /* four bits. If bit is set, memory block is
|
||||||
|
allocated */
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
* Memory pool mechanism uses one array of k_mem_pool_quad_block for accounting
|
||||||
|
* blocks of one size. Block sizes go from maximal to minimal. Next memory
|
||||||
|
* block size is 4 times less than the previous one and thus requires 4 times
|
||||||
|
* bigger array of k_mem_pool_quad_block structures to keep track of the
|
||||||
|
* memory blocks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The array of k_mem_pool_block_set keeps the information of each array of
|
||||||
|
* k_mem_pool_quad_block structures
|
||||||
|
*/
|
||||||
|
struct k_mem_pool_block_set {
|
||||||
|
int block_size; /* memory block size */
|
||||||
|
int nr_of_entries; /* nr of quad block structures in the array */
|
||||||
|
struct k_mem_pool_quad_block *quad_block;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Memory pool descriptor */
|
||||||
|
struct k_mem_pool {
|
||||||
|
int max_block_size;
|
||||||
|
int min_block_size;
|
||||||
|
int nr_of_maxblocks;
|
||||||
|
int nr_of_block_sets;
|
||||||
|
struct k_mem_pool_block_set *block_set;
|
||||||
|
char *bufblock;
|
||||||
|
_wait_q_t wait_q;
|
||||||
_DEBUG_TRACING_KERNEL_OBJECTS_NEXT_PTR(k_mem_pool);
|
_DEBUG_TRACING_KERNEL_OBJECTS_NEXT_PTR(k_mem_pool);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* cannot initialize pools statically */
|
#ifdef CONFIG_ARM
|
||||||
|
#define _SECTION_TYPE_SIGN "%"
|
||||||
|
#else
|
||||||
|
#define _SECTION_TYPE_SIGN "@"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Static memory pool initialization
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Use .altmacro to be able to recalculate values and pass them as string
|
||||||
|
* arguments when calling assembler macros resursively
|
||||||
|
*/
|
||||||
|
__asm__(".altmacro\n\t");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Recursively calls a macro
|
||||||
|
* The followig global symbols need to be initialized:
|
||||||
|
* __memory_pool_max_block_size - maximal size of the memory block
|
||||||
|
* __memory_pool_min_block_size - minimal size of the memory block
|
||||||
|
* Notes:
|
||||||
|
* Global symbols are used due the fact that assembler macro allows only
|
||||||
|
* one argument be passed with the % conversion
|
||||||
|
* Some assemblers do not get division operation ("/"). To avoid it >> 2
|
||||||
|
* is used instead of / 4.
|
||||||
|
* n_max argument needs to go first in the invoked macro, as some
|
||||||
|
* assemblers concatenate \name and %(\n_max * 4) arguments
|
||||||
|
* if \name goes first
|
||||||
|
*/
|
||||||
|
__asm__(".macro __do_recurse macro_name, name, n_max\n\t"
|
||||||
|
".ifge __memory_pool_max_block_size >> 2 -"
|
||||||
|
" __memory_pool_min_block_size\n\t\t"
|
||||||
|
"__memory_pool_max_block_size = __memory_pool_max_block_size >> 2\n\t\t"
|
||||||
|
"\\macro_name %(\\n_max * 4) \\name\n\t"
|
||||||
|
".endif\n\t"
|
||||||
|
".endm\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build quad blocks
|
||||||
|
* Macro allocates space in memory for the array of k_mem_pool_quad_block
|
||||||
|
* structures and recursively calls itself for the next array, 4 times
|
||||||
|
* larger.
|
||||||
|
* The followig global symbols need to be initialized:
|
||||||
|
* __memory_pool_max_block_size - maximal size of the memory block
|
||||||
|
* __memory_pool_min_block_size - minimal size of the memory block
|
||||||
|
* __memory_pool_quad_block_size - sizeof(struct k_mem_pool_quad_block)
|
||||||
|
*/
|
||||||
|
__asm__(".macro _build_quad_blocks n_max, name\n\t"
|
||||||
|
"_mem_pool_quad_blocks_\\name\\()_\\n_max:\n\t"
|
||||||
|
".skip __memory_pool_quad_block_size * \\n_max >> 2\n\t"
|
||||||
|
".if \\n_max % 4\n\t\t"
|
||||||
|
".skip __memory_pool_quad_block_size\n\t"
|
||||||
|
".endif\n\t"
|
||||||
|
"__do_recurse _build_quad_blocks \\name \\n_max\n\t"
|
||||||
|
".endm\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build block sets and initialize them
|
||||||
|
* Macro initializes the k_mem_pool_block_set structure and
|
||||||
|
* recursively calls itself for the next one.
|
||||||
|
* The followig global symbols need to be initialized:
|
||||||
|
* __memory_pool_max_block_size - maximal size of the memory block
|
||||||
|
* __memory_pool_min_block_size - minimal size of the memory block
|
||||||
|
* __memory_pool_block_set_count, the number of the elements in the
|
||||||
|
* block set array must be set to 0. Macro calculates it's real
|
||||||
|
* value.
|
||||||
|
* Since the macro initializes pointers to an array of k_mem_pool_quad_block
|
||||||
|
* structures, _build_quad_blocks must be called prior it.
|
||||||
|
*/
|
||||||
|
__asm__(".macro _build_block_set n_max, name\n\t"
|
||||||
|
".int __memory_pool_max_block_size\n\t" /* block_size */
|
||||||
|
".if \\n_max % 4\n\t\t"
|
||||||
|
".int \\n_max >> 2 + 1\n\t" /* nr_of_entries */
|
||||||
|
".else\n\t\t"
|
||||||
|
".int \\n_max >> 2\n\t"
|
||||||
|
".endif\n\t"
|
||||||
|
".int _mem_pool_quad_blocks_\\name\\()_\\n_max\n\t" /* quad_block */
|
||||||
|
".int 0\n\t" /* count */
|
||||||
|
"__memory_pool_block_set_count = __memory_pool_block_set_count + 1\n\t"
|
||||||
|
"__do_recurse _build_block_set \\name \\n_max\n\t"
|
||||||
|
".endm\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build a memory pool structure and initialize it
|
||||||
|
* Macro uses __memory_pool_block_set_count global symbol,
|
||||||
|
* block set addresses and buffer address, it may be called only after
|
||||||
|
* _build_block_set
|
||||||
|
*/
|
||||||
|
__asm__(".macro _build_mem_pool name, min_size, max_size, n_max\n\t"
|
||||||
|
".pushsection ._k_memory_pool,\"aw\","
|
||||||
|
_SECTION_TYPE_SIGN "progbits\n\t"
|
||||||
|
".globl \\name\n\t"
|
||||||
|
"\\name:\n\t"
|
||||||
|
".int \\max_size\n\t" /* max_block_size */
|
||||||
|
".int \\min_size\n\t" /* min_block_size */
|
||||||
|
".int \\n_max\n\t" /* nr_of_maxblocks */
|
||||||
|
".int __memory_pool_block_set_count\n\t" /* nr_of_block_sets */
|
||||||
|
".int _mem_pool_block_sets_\\name\n\t" /* block_set */
|
||||||
|
".int _mem_pool_buffer_\\name\n\t" /* bufblock */
|
||||||
|
".int 0\n\t" /* wait_q->head */
|
||||||
|
".int 0\n\t" /* wait_q->next */
|
||||||
|
".popsection\n\t"
|
||||||
|
".endm\n");
|
||||||
|
|
||||||
|
#define _MEMORY_POOL_QUAD_BLOCK_DEFINE(name, min_size, max_size, n_max) \
|
||||||
|
__asm__(".pushsection ._k_memory_pool.struct,\"aw\"," \
|
||||||
|
_SECTION_TYPE_SIGN "progbits\n\t"); \
|
||||||
|
__asm__("__memory_pool_min_block_size = " STRINGIFY(min_size) "\n\t"); \
|
||||||
|
__asm__("__memory_pool_max_block_size = " STRINGIFY(max_size) "\n\t"); \
|
||||||
|
__asm__("_build_quad_blocks " STRINGIFY(n_max) " " \
|
||||||
|
STRINGIFY(name) "\n\t"); \
|
||||||
|
__asm__(".popsection\n\t")
|
||||||
|
|
||||||
|
#define _MEMORY_POOL_BLOCK_SETS_DEFINE(name, min_size, max_size, n_max) \
|
||||||
|
__asm__("__memory_pool_block_set_count = 0\n\t"); \
|
||||||
|
__asm__("__memory_pool_max_block_size = " STRINGIFY(max_size) "\n\t"); \
|
||||||
|
__asm__(".pushsection ._k_memory_pool.struct,\"aw\"," \
|
||||||
|
_SECTION_TYPE_SIGN "progbits\n\t"); \
|
||||||
|
__asm__("_mem_pool_block_sets_" STRINGIFY(name) ":\n\t"); \
|
||||||
|
__asm__("_build_block_set " STRINGIFY(n_max) " " \
|
||||||
|
STRINGIFY(name) "\n\t"); \
|
||||||
|
__asm__("_mem_pool_block_set_count_" STRINGIFY(name) ":\n\t"); \
|
||||||
|
__asm__(".int __memory_pool_block_set_count\n\t"); \
|
||||||
|
__asm__(".popsection\n\t"); \
|
||||||
|
extern uint32_t _mem_pool_block_set_count_##name; \
|
||||||
|
extern struct k_mem_pool_block_set _mem_pool_block_sets_##name[]
|
||||||
|
|
||||||
|
#define _MEMORY_POOL_BUFFER_DEFINE(name, max_size, n_max) \
|
||||||
|
char __noinit _mem_pool_buffer_##name[(max_size) * (n_max)]
|
||||||
|
|
||||||
|
#define K_MEMORY_POOL_DEFINE(name, min_size, max_size, n_max) \
|
||||||
|
_MEMORY_POOL_QUAD_BLOCK_DEFINE(name, min_size, max_size, n_max); \
|
||||||
|
_MEMORY_POOL_BLOCK_SETS_DEFINE(name, min_size, max_size, n_max); \
|
||||||
|
_MEMORY_POOL_BUFFER_DEFINE(name, max_size, n_max); \
|
||||||
|
__asm__("_build_mem_pool " STRINGIFY(name) " " STRINGIFY(min_size) " " \
|
||||||
|
STRINGIFY(max_size) " " STRINGIFY(n_max) "\n\t"); \
|
||||||
|
extern struct k_mem_pool name
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dummy function that assigns the value of sizeof(struct k_mem_pool_quad_block)
|
||||||
|
* to __memory_pool_quad_block_size absolute symbol.
|
||||||
|
* This function does not get called, but compiler calculates the value and
|
||||||
|
* assigns it to the absolute symbol, that, in turn is used by assembler macros.
|
||||||
|
*/
|
||||||
|
static void __attribute__ ((used)) __k_mem_pool_quad_block_size_define(void)
|
||||||
|
{
|
||||||
|
__asm__(".globl __memory_pool_quad_block_size\n\t"
|
||||||
|
"__memory_pool_quad_block_size = %c0\n\t"
|
||||||
|
:
|
||||||
|
: "n"(sizeof(struct k_mem_pool_quad_block)));
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX - review this computation */
|
|
||||||
#define K_MEM_POOL_SIZE(max_block_size, num_max_blocks) \
|
#define K_MEM_POOL_SIZE(max_block_size, num_max_blocks) \
|
||||||
(sizeof(struct k_mem_pool) + ((max_block_size) * (num_max_blocks)))
|
(sizeof(struct k_mem_pool) + ((max_block_size) * (num_max_blocks)))
|
||||||
|
|
||||||
extern void k_mem_pool_init(struct k_mem_pool *mem, int max_block_size,
|
extern int k_mem_pool_alloc(struct k_mem_pool *pool, struct k_mem_block *block,
|
||||||
int num_max_blocks);
|
|
||||||
extern int k_mem_pool_alloc(k_mem_pool_t id, struct k_mem_block *block,
|
|
||||||
int size, int32_t timeout);
|
int size, int32_t timeout);
|
||||||
extern void k_mem_pool_free(struct k_mem_block *block);
|
extern void k_mem_pool_free(struct k_mem_block *block);
|
||||||
extern void k_mem_pool_defrag(k_mem_pool_t id);
|
extern void k_mem_pool_defrag(struct k_mem_pool *pool);
|
||||||
extern void *k_malloc(uint32_t size);
|
extern void *k_malloc(uint32_t size);
|
||||||
extern void k_free(void *p);
|
extern void k_free(void *p);
|
||||||
|
|
||||||
|
|
|
@ -381,9 +381,8 @@ static inline int task_mem_map_alloc(kmemory_map_t map, void **mptr,
|
||||||
/* memory pools */
|
/* memory pools */
|
||||||
|
|
||||||
#define k_block k_mem_block
|
#define k_block k_mem_block
|
||||||
#define kmemory_pool_t k_mem_pool_t
|
#define kmemory_pool_t struct k_mem_pool *
|
||||||
|
#define pool_struct k_mem_pool
|
||||||
#if 0 /* unimplemented object */
|
|
||||||
|
|
||||||
static inline int task_mem_pool_alloc(struct k_block *blockptr,
|
static inline int task_mem_pool_alloc(struct k_block *blockptr,
|
||||||
kmemory_pool_t pool_id,
|
kmemory_pool_t pool_id,
|
||||||
|
@ -398,8 +397,6 @@ static inline int task_mem_pool_alloc(struct k_block *blockptr,
|
||||||
#define task_malloc k_malloc
|
#define task_malloc k_malloc
|
||||||
#define task_free k_free
|
#define task_free k_free
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* message queues */
|
/* message queues */
|
||||||
|
|
||||||
#define kfifo_t struct k_msgq *
|
#define kfifo_t struct k_msgq *
|
||||||
|
|
|
@ -287,4 +287,31 @@ config SEMAPHORE_GROUPS
|
||||||
both decrease the footprint as well as improve the performance of
|
both decrease the footprint as well as improve the performance of
|
||||||
the k_sem_give() routine.
|
the k_sem_give() routine.
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Memory pools auto-defragmentation policy"
|
||||||
|
default MEM_POOL_AD_AFTER_SEARCH_FOR_BIGGERBLOCK
|
||||||
|
help
|
||||||
|
Memory pool auto-defragmentation is performed if a memory
|
||||||
|
block of the requested size can not be found. Defragmentation
|
||||||
|
can be done:
|
||||||
|
Before trying to find a block in the next largest block set.
|
||||||
|
This is an attempt to preserve the memory pool's larger blocks
|
||||||
|
by fragmenting them only when necessary (i.e. at the cost of
|
||||||
|
doing more frequent auto-defragmentations).
|
||||||
|
After trying to find a block in the next largest block set.
|
||||||
|
This is an attempt to limit the cost of doing auto-defragmentations
|
||||||
|
by doing them only when necessary (i.e. at the cost of fragmenting
|
||||||
|
the memory pool's larger blocks).
|
||||||
|
|
||||||
|
config MEM_POOL_AD_NONE
|
||||||
|
bool "No auto-defragmentation"
|
||||||
|
|
||||||
|
config MEM_POOL_AD_BEFORE_SEARCH_FOR_BIGGERBLOCK
|
||||||
|
bool "Before trying to find a block in the next largest block set"
|
||||||
|
|
||||||
|
config MEM_POOL_AD_AFTER_SEARCH_FOR_BIGGERBLOCK
|
||||||
|
bool "After trying to find a block in the next largest block set"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -22,6 +22,7 @@ obj-y += $(strip \
|
||||||
fifo.o \
|
fifo.o \
|
||||||
stack.o \
|
stack.o \
|
||||||
mem_map.o \
|
mem_map.o \
|
||||||
|
mem_pool.o \
|
||||||
msg_q.o \
|
msg_q.o \
|
||||||
mailbox.o \
|
mailbox.o \
|
||||||
mem_pool.o \
|
mem_pool.o \
|
||||||
|
|
|
@ -21,35 +21,623 @@
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include <nano_private.h>
|
#include <nano_private.h>
|
||||||
#include <misc/debug/object_tracing_common.h>
|
#include <misc/debug/object_tracing_common.h>
|
||||||
#include <toolchain.h>
|
#include <sched.h>
|
||||||
#include <sections.h>
|
|
||||||
#include <wait_q.h>
|
#include <wait_q.h>
|
||||||
#include <misc/dlist.h>
|
#include <init.h>
|
||||||
|
|
||||||
void k_mem_pool_init(struct k_mem_pool *mem, int max_block_size,
|
#define _QUAD_BLOCK_AVAILABLE 0x0F
|
||||||
int num_max_blocks)
|
#define _QUAD_BLOCK_ALLOCATED 0x0
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int k_mem_pool_alloc(k_mem_pool_t id, struct k_block *block, int size,
|
extern struct k_mem_pool _k_mem_pool_start[];
|
||||||
int32_t timeout)
|
extern struct k_mem_pool _k_mem_pool_end[];
|
||||||
|
#if defined _HEAP_MEM_POOL
|
||||||
|
static struct k_mem_pool *heap_mem_pool = _HEAP_MEM_POOL;
|
||||||
|
#else
|
||||||
|
static struct k_mem_pool *heap_mem_pool;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void init_one_memory_pool(struct k_mem_pool *pool);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Initialize kernel memory pool subsystem
|
||||||
|
*
|
||||||
|
* Perform any initialization of memory pool that wasn't done at build time.
|
||||||
|
*
|
||||||
|
* @return N/A
|
||||||
|
*/
|
||||||
|
static int init_static_pools(struct device *unused)
|
||||||
{
|
{
|
||||||
|
ARG_UNUSED(unused);
|
||||||
|
struct k_mem_pool *pool;
|
||||||
|
|
||||||
|
/* perform initialization for each memory pool */
|
||||||
|
|
||||||
|
for (pool = _k_mem_pool_start;
|
||||||
|
pool < _k_mem_pool_end;
|
||||||
|
pool++) {
|
||||||
|
init_one_memory_pool(pool);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void k_mem_pool_free(struct k_block *block)
|
/**
|
||||||
|
*
|
||||||
|
* @brief Initialize the memory pool
|
||||||
|
*
|
||||||
|
* Initialize the internal memory accounting structures of the memory pool
|
||||||
|
*
|
||||||
|
* @param pool memory pool descriptor
|
||||||
|
*
|
||||||
|
* @return N/A
|
||||||
|
*/
|
||||||
|
static void init_one_memory_pool(struct k_mem_pool *pool)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* mark block set for largest block size
|
||||||
|
* as owning all of the memory pool buffer space
|
||||||
|
*/
|
||||||
|
|
||||||
|
int remaining_blocks = pool->nr_of_maxblocks;
|
||||||
|
int j = 0;
|
||||||
|
char *memptr = pool->bufblock;
|
||||||
|
|
||||||
|
while (remaining_blocks >= 4) {
|
||||||
|
pool->block_set[0].quad_block[j].mem_blocks = memptr;
|
||||||
|
pool->block_set[0].quad_block[j].mem_status =
|
||||||
|
_QUAD_BLOCK_AVAILABLE;
|
||||||
|
j++;
|
||||||
|
remaining_blocks -= 4;
|
||||||
|
memptr +=
|
||||||
|
OCTET_TO_SIZEOFUNIT(pool->block_set[0].block_size)
|
||||||
|
* 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remaining_blocks != 0) {
|
||||||
|
pool->block_set[0].quad_block[j].mem_blocks = memptr;
|
||||||
|
pool->block_set[0].quad_block[j].mem_status =
|
||||||
|
_QUAD_BLOCK_AVAILABLE >> (4 - remaining_blocks);
|
||||||
|
/* non-existent blocks are marked as unavailable */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* note: all other block sets own no blocks, since their
|
||||||
|
* first quad-block has a NULL memory pointer
|
||||||
|
*/
|
||||||
|
sys_dlist_init(&pool->wait_q);
|
||||||
|
SYS_TRACING_OBJ_INIT(memory_pool, pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
void k_mem_pool_defrag(k_mem_pool_t id)
|
/**
|
||||||
|
*
|
||||||
|
* @brief Determines which block set corresponds to the specified data size
|
||||||
|
*
|
||||||
|
* Finds the block set with the smallest blocks that can hold the specified
|
||||||
|
* amount of data.
|
||||||
|
*
|
||||||
|
* @return block set index
|
||||||
|
*/
|
||||||
|
static int compute_block_set_index(struct k_mem_pool *pool, int data_size)
|
||||||
{
|
{
|
||||||
|
int block_size = pool->min_block_size;
|
||||||
|
int offset = pool->nr_of_block_sets - 1;
|
||||||
|
|
||||||
|
while (data_size > block_size) {
|
||||||
|
block_size *= 4;
|
||||||
|
offset--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Return an allocated block to its block set
|
||||||
|
*
|
||||||
|
* @param ptr pointer to start of block
|
||||||
|
* @param pool memory pool descriptor
|
||||||
|
* @param index block set identifier
|
||||||
|
*
|
||||||
|
* @return N/A
|
||||||
|
*/
|
||||||
|
static void free_existing_block(char *ptr, struct k_mem_pool *pool, int index)
|
||||||
|
{
|
||||||
|
struct k_mem_pool_quad_block *quad_block =
|
||||||
|
pool->block_set[index].quad_block;
|
||||||
|
char *block_ptr;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* search block set's quad-blocks until the block is located,
|
||||||
|
* then mark it as unused
|
||||||
|
*
|
||||||
|
* note: block *must* exist, so no need to do array bounds checking
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (i = 0; ; i++) {
|
||||||
|
__ASSERT((i < pool->block_set[index].nr_of_entries) &&
|
||||||
|
(quad_block[i].mem_blocks != NULL),
|
||||||
|
"Attempt to free unallocated memory pool block\n");
|
||||||
|
|
||||||
|
block_ptr = quad_block[i].mem_blocks;
|
||||||
|
for (j = 0; j < 4; j++) {
|
||||||
|
if (ptr == block_ptr) {
|
||||||
|
quad_block[i].mem_status |= (1 << j);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
block_ptr += OCTET_TO_SIZEOFUNIT(
|
||||||
|
pool->block_set[index].block_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Defragment the specified memory pool block sets
|
||||||
|
*
|
||||||
|
* Reassembles any quad-blocks that are entirely unused into larger blocks
|
||||||
|
* (to the extent permitted).
|
||||||
|
*
|
||||||
|
* @param pool memory pool descriptor
|
||||||
|
* @param start_block_set_index index of smallest block set to defragment
|
||||||
|
* @param last_block_set_index index of largest block set to defragment
|
||||||
|
*
|
||||||
|
* @return N/A
|
||||||
|
*/
|
||||||
|
static void defrag(struct k_mem_pool *pool,
|
||||||
|
int start_block_set_index, int last_block_set_index)
|
||||||
|
{
|
||||||
|
int i, j, k;
|
||||||
|
struct k_mem_pool_quad_block *quad_block;
|
||||||
|
|
||||||
|
/* process block sets from smallest to largest permitted sizes */
|
||||||
|
|
||||||
|
for (j = start_block_set_index; j > last_block_set_index; j--) {
|
||||||
|
|
||||||
|
quad_block = pool->block_set[j].quad_block;
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* block set is done if no more quad-blocks exist */
|
||||||
|
|
||||||
|
if (quad_block[i].mem_blocks == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reassemble current quad-block, if possible */
|
||||||
|
|
||||||
|
if (quad_block[i].mem_status == _QUAD_BLOCK_AVAILABLE) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mark the corresponding block in next larger
|
||||||
|
* block set as free
|
||||||
|
*/
|
||||||
|
|
||||||
|
free_existing_block(
|
||||||
|
quad_block[i].mem_blocks, pool, j - 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* delete the quad-block from this block set
|
||||||
|
* by replacing it with the last quad-block
|
||||||
|
*
|
||||||
|
* (algorithm works even when the deleted
|
||||||
|
* quad-block is the last quad_block)
|
||||||
|
*/
|
||||||
|
|
||||||
|
k = i;
|
||||||
|
while ((k < pool->block_set[j].nr_of_entries) &&
|
||||||
|
(quad_block[k + 1].mem_blocks != NULL)) {
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
|
||||||
|
quad_block[i].mem_blocks =
|
||||||
|
quad_block[k].mem_blocks;
|
||||||
|
quad_block[i].mem_status =
|
||||||
|
quad_block[k].mem_status;
|
||||||
|
|
||||||
|
quad_block[k].mem_blocks = NULL;
|
||||||
|
|
||||||
|
/* loop & process replacement quad_block[i] */
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* block set is done if at end of quad-block array */
|
||||||
|
|
||||||
|
} while (i < pool->block_set[j].nr_of_entries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Allocate block from an existing block set
|
||||||
|
*
|
||||||
|
* @param block_set pointer to block set
|
||||||
|
* @param unused_block_index the index of first unused quad-block
|
||||||
|
* when allocation fails, it is the number of quad
|
||||||
|
* blocks in the block set
|
||||||
|
*
|
||||||
|
* @return pointer to allocated block, or NULL if none available
|
||||||
|
*/
|
||||||
|
static char *get_existing_block(struct k_mem_pool_block_set *block_set,
|
||||||
|
int *unused_block_index)
|
||||||
|
{
|
||||||
|
char *found = NULL;
|
||||||
|
int i = 0;
|
||||||
|
int status;
|
||||||
|
int free_bit;
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* give up if no more quad-blocks exist */
|
||||||
|
|
||||||
|
if (block_set->quad_block[i].mem_blocks == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate a block from current quad-block, if possible */
|
||||||
|
|
||||||
|
status = block_set->quad_block[i].mem_status;
|
||||||
|
if (status != _QUAD_BLOCK_ALLOCATED) {
|
||||||
|
/* identify first free block */
|
||||||
|
free_bit = find_lsb_set(status) - 1;
|
||||||
|
|
||||||
|
/* compute address of free block */
|
||||||
|
found = block_set->quad_block[i].mem_blocks +
|
||||||
|
(OCTET_TO_SIZEOFUNIT(free_bit *
|
||||||
|
block_set->block_size));
|
||||||
|
|
||||||
|
/* mark block as unavailable (using XOR to invert) */
|
||||||
|
block_set->quad_block[i].mem_status ^=
|
||||||
|
1 << free_bit;
|
||||||
|
#ifdef CONFIG_OBJECT_MONITOR
|
||||||
|
block_set->count++;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move on to next quad-block; give up if at end of array */
|
||||||
|
|
||||||
|
} while (++i < block_set->nr_of_entries);
|
||||||
|
|
||||||
|
*unused_block_index = i;
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Allocate a block, recursively fragmenting larger blocks if necessary
|
||||||
|
*
|
||||||
|
* @param pool memory pool descriptor
|
||||||
|
* @param index index of block set currently being examined
|
||||||
|
* @param start_index index of block set for which allocation is being done
|
||||||
|
*
|
||||||
|
* @return pointer to allocated block, or NULL if none available
|
||||||
|
*/
|
||||||
|
static char *get_block_recursive(struct k_mem_pool *pool,
|
||||||
|
int index, int start_index)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *found, *larger_block;
|
||||||
|
struct k_mem_pool_block_set *fr_table;
|
||||||
|
|
||||||
|
/* give up if we've exhausted the set of maximum size blocks */
|
||||||
|
|
||||||
|
if (index < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try allocating a block from the current block set */
|
||||||
|
|
||||||
|
fr_table = pool->block_set;
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
found = get_existing_block(&(fr_table[index]), &i);
|
||||||
|
if (found != NULL) {
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_MEM_POOL_AD_BEFORE_SEARCH_FOR_BIGGERBLOCK
|
||||||
|
/*
|
||||||
|
* do a partial defragmentation of memory pool & try allocating again
|
||||||
|
* - do this on initial invocation only, not recursive ones
|
||||||
|
* (since there is no benefit in repeating the defrag)
|
||||||
|
* - defrag only the blocks smaller than the desired size,
|
||||||
|
* and only until the size needed is reached
|
||||||
|
*
|
||||||
|
* note: defragging at this time tries to preserve the memory pool's
|
||||||
|
* larger blocks by fragmenting them only when necessary
|
||||||
|
* (i.e. at the cost of doing more frequent auto-defragmentations)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (index == start_index) {
|
||||||
|
defrag(pool, pool->nr_of_block_sets - 1, start_index);
|
||||||
|
found = get_existing_block(&(fr_table[index]), &i);
|
||||||
|
if (found != NULL) {
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* try allocating a block from the next largest block set */
|
||||||
|
|
||||||
|
larger_block = get_block_recursive(pool, index - 1, start_index);
|
||||||
|
if (larger_block != NULL) {
|
||||||
|
/*
|
||||||
|
* add a new quad-block to the current block set,
|
||||||
|
* then mark one of its 4 blocks as used and return it
|
||||||
|
*
|
||||||
|
* note: "i" was earlier set to indicate the first unused
|
||||||
|
* quad-block entry in the current block set
|
||||||
|
*/
|
||||||
|
|
||||||
|
fr_table[index].quad_block[i].mem_blocks = larger_block;
|
||||||
|
fr_table[index].quad_block[i].mem_status =
|
||||||
|
_QUAD_BLOCK_AVAILABLE & (~0x1);
|
||||||
|
#ifdef CONFIG_OBJECT_MONITOR
|
||||||
|
fr_table[index].count++;
|
||||||
|
#endif
|
||||||
|
return larger_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_MEM_POOL_AD_AFTER_SEARCH_FOR_BIGGERBLOCK
|
||||||
|
/*
|
||||||
|
* do a partial defragmentation of memory pool & try allocating again
|
||||||
|
* - do this on initial invocation only, not recursive ones
|
||||||
|
* (since there is no benefit in repeating the defrag)
|
||||||
|
* - defrag only the blocks smaller than the desired size,
|
||||||
|
* and only until the size needed is reached
|
||||||
|
*
|
||||||
|
* note: defragging at this time tries to limit the cost of doing
|
||||||
|
* auto-defragmentations by doing them only when necessary
|
||||||
|
* (i.e. at the cost of fragmenting the memory pool's larger blocks)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (index == start_index) {
|
||||||
|
defrag(pool, pool->nr_of_block_sets - 1, start_index);
|
||||||
|
found = get_existing_block(&(fr_table[index]), &i);
|
||||||
|
if (found != NULL) {
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NULL; /* can't find (or create) desired block */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Examine threads that are waiting for memory pool blocks.
|
||||||
|
*
|
||||||
|
* This routine attempts to satisfy any incomplete block allocation requests for
|
||||||
|
* the specified memory pool. It can be invoked either by the explicit freeing
|
||||||
|
* of a used block or as a result of defragmenting the pool (which may create
|
||||||
|
* one or more new, larger blocks).
|
||||||
|
*
|
||||||
|
* @return N/A
|
||||||
|
*/
|
||||||
|
static void block_waiters_check(struct k_mem_pool *pool)
|
||||||
|
{
|
||||||
|
char *found_block;
|
||||||
|
struct k_thread *waiter;
|
||||||
|
struct k_thread *next_waiter;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
unsigned int key = irq_lock();
|
||||||
|
waiter = (struct k_thread *)sys_dlist_peek_head(&pool->wait_q);
|
||||||
|
|
||||||
|
/* loop all waiters */
|
||||||
|
while (waiter != NULL) {
|
||||||
|
uint32_t req_size = (uint32_t)(waiter->swap_data);
|
||||||
|
|
||||||
|
/* locate block set to try allocating from */
|
||||||
|
offset = compute_block_set_index(pool, req_size);
|
||||||
|
|
||||||
|
/* allocate block (fragmenting a larger block, if needed) */
|
||||||
|
found_block = get_block_recursive(pool, offset, offset);
|
||||||
|
|
||||||
|
next_waiter = (struct k_thread *)sys_dlist_peek_next(
|
||||||
|
&pool->wait_q, &waiter->k_q_node);
|
||||||
|
|
||||||
|
/* if success : remove task from list and reschedule */
|
||||||
|
if (found_block != NULL) {
|
||||||
|
/* return found block */
|
||||||
|
_set_thread_return_value_with_data(waiter, 0,
|
||||||
|
found_block);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Schedule the thread. Threads will be rescheduled
|
||||||
|
* outside the function by k_sched_unlock()
|
||||||
|
*/
|
||||||
|
_unpend_thread(waiter);
|
||||||
|
_timeout_abort(waiter);
|
||||||
|
_ready_thread(waiter);
|
||||||
|
}
|
||||||
|
waiter = next_waiter;
|
||||||
|
}
|
||||||
|
irq_unlock(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Perform defragment memory pool request
|
||||||
|
*
|
||||||
|
* @return N/A
|
||||||
|
*/
|
||||||
|
void k_mem_pool_defrag(k_mem_pool_t pool)
|
||||||
|
{
|
||||||
|
k_sched_lock();
|
||||||
|
|
||||||
|
/* do complete defragmentation of memory pool (i.e. all block sets) */
|
||||||
|
defrag(pool, pool->nr_of_block_sets - 1, 0);
|
||||||
|
|
||||||
|
/* reschedule anybody waiting for a block */
|
||||||
|
block_waiters_check(pool);
|
||||||
|
k_sched_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Perform allocate memory pool block request
|
||||||
|
*
|
||||||
|
* @return N/A
|
||||||
|
*/
|
||||||
|
int k_mem_pool_alloc(k_mem_pool_t pool, struct k_mem_block *block,
|
||||||
|
int size, int32_t timeout)
|
||||||
|
{
|
||||||
|
char *found_block;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
k_sched_lock();
|
||||||
|
/* locate block set to try allocating from */
|
||||||
|
offset = compute_block_set_index(pool, size);
|
||||||
|
|
||||||
|
/* allocate block (fragmenting a larger block, if needed) */
|
||||||
|
found_block = get_block_recursive(pool, offset, offset);
|
||||||
|
|
||||||
|
|
||||||
|
if (found_block != NULL) {
|
||||||
|
k_sched_unlock();
|
||||||
|
block->pool_id = pool;
|
||||||
|
block->addr_in_pool = found_block;
|
||||||
|
block->data = found_block;
|
||||||
|
block->req_size = size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* no suitable block is currently available,
|
||||||
|
* so either wait for one to appear or indicate failure
|
||||||
|
*/
|
||||||
|
if (likely(timeout != TICKS_NONE)) {
|
||||||
|
int result;
|
||||||
|
unsigned int key = irq_lock();
|
||||||
|
_sched_unlock_no_reschedule();
|
||||||
|
|
||||||
|
_current->swap_data = (void *)size;
|
||||||
|
_pend_current_thread(&pool->wait_q, timeout);
|
||||||
|
result = _Swap(key);
|
||||||
|
if (result == 0) {
|
||||||
|
block->pool_id = pool;
|
||||||
|
block->addr_in_pool = _current->swap_data;
|
||||||
|
block->data = _current->swap_data;
|
||||||
|
block->req_size = size;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
k_sched_unlock();
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define MALLOC_ALIGN (sizeof(uint32_t))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate memory from heap pool
|
||||||
|
*
|
||||||
|
* This routine provides traditional malloc semantics; internally it uses
|
||||||
|
* the microkernel pool APIs on a dedicated HEAP pool
|
||||||
|
*
|
||||||
|
* @param size Size of memory requested by the caller.
|
||||||
|
*
|
||||||
|
* @retval address of the block if successful otherwise returns NULL
|
||||||
|
*/
|
||||||
void *k_malloc(uint32_t size)
|
void *k_malloc(uint32_t size)
|
||||||
{
|
{
|
||||||
return NULL;
|
uint32_t new_size;
|
||||||
|
uint32_t *aligned_addr;
|
||||||
|
struct k_mem_block mem_block;
|
||||||
|
|
||||||
|
__ASSERT(heap_mem_pool != NULL,
|
||||||
|
"Try to allocate a block in undefined heap\n");
|
||||||
|
|
||||||
|
/* The address pool returns, may not be aligned. Also
|
||||||
|
* pool_free requires both start address and size. So
|
||||||
|
* we end up needing 2 slots to save the size and
|
||||||
|
* start address in addition to padding space
|
||||||
|
*/
|
||||||
|
new_size = size + (sizeof(uint32_t) << 1) + MALLOC_ALIGN - 1;
|
||||||
|
|
||||||
|
if (k_mem_pool_alloc(heap_mem_pool, &mem_block, new_size,
|
||||||
|
TICKS_NONE) != 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the next aligned address following the address returned by pool*/
|
||||||
|
aligned_addr = (uint32_t *) ROUND_UP(mem_block.addr_in_pool,
|
||||||
|
MALLOC_ALIGN);
|
||||||
|
|
||||||
|
/* Save the size requested to the pool API, to be used while freeing */
|
||||||
|
*aligned_addr = new_size;
|
||||||
|
|
||||||
|
/* Save the original unaligned_addr pointer too */
|
||||||
|
aligned_addr++;
|
||||||
|
*((void **) aligned_addr) = mem_block.addr_in_pool;
|
||||||
|
|
||||||
|
/* return the subsequent address */
|
||||||
|
return ++aligned_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void k_free(void *p)
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Perform return memory pool block request
|
||||||
|
*
|
||||||
|
* @param blockptr address of the memory block to be freed
|
||||||
|
*
|
||||||
|
* Marks a block belonging to a pool as free; if there are waiters that can use
|
||||||
|
* the the block it is passed to a waiting task.
|
||||||
|
*
|
||||||
|
* @return N/A
|
||||||
|
*/
|
||||||
|
void k_mem_pool_free(struct k_mem_block *blockptr)
|
||||||
{
|
{
|
||||||
|
int offset;
|
||||||
|
struct k_mem_pool *pool = blockptr->pool_id;
|
||||||
|
|
||||||
|
k_sched_lock();
|
||||||
|
/* determine block set that block belongs to */
|
||||||
|
offset = compute_block_set_index(pool, blockptr->req_size);
|
||||||
|
|
||||||
|
/* mark the block as unused */
|
||||||
|
free_existing_block(blockptr->addr_in_pool, pool, offset);
|
||||||
|
|
||||||
|
/* reschedule anybody waiting for a block */
|
||||||
|
block_waiters_check(pool);
|
||||||
|
k_sched_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free memory allocated through task_malloc
|
||||||
|
*
|
||||||
|
* @param ptr pointer to be freed
|
||||||
|
*
|
||||||
|
* @return NA
|
||||||
|
*/
|
||||||
|
void k_free(void *ptr)
|
||||||
|
{
|
||||||
|
struct k_mem_block mem_block;
|
||||||
|
|
||||||
|
__ASSERT(heap_mem_pool != NULL,
|
||||||
|
"Try to free a block in undefined heap\n");
|
||||||
|
|
||||||
|
mem_block.pool_id = heap_mem_pool;
|
||||||
|
|
||||||
|
/* Fetch the pointer returned by the pool API */
|
||||||
|
mem_block.addr_in_pool = *((void **) ((uint32_t *)ptr - 1));
|
||||||
|
mem_block.data = *((void **) ((uint32_t *)ptr - 1));
|
||||||
|
/* Further fetch the size asked from pool */
|
||||||
|
mem_block.req_size = *((uint32_t *)ptr - 2);
|
||||||
|
|
||||||
|
k_mem_pool_free(&mem_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_INIT(init_static_pools, PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|
||||||
|
|
|
@ -393,7 +393,7 @@ class SizeCalculator:
|
||||||
alloc_sections = ["bss", "noinit"]
|
alloc_sections = ["bss", "noinit"]
|
||||||
rw_sections = ["datas", "initlevel", "_k_mem_map_ptr", "_k_pipe_ptr",
|
rw_sections = ["datas", "initlevel", "_k_mem_map_ptr", "_k_pipe_ptr",
|
||||||
"_k_task_ptr", "_k_task_list", "_k_event_list",
|
"_k_task_ptr", "_k_task_list", "_k_event_list",
|
||||||
"exceptions"]
|
"_k_memory_pool", "exceptions"]
|
||||||
# These get copied into RAM only on non-XIP
|
# These get copied into RAM only on non-XIP
|
||||||
ro_sections = ["text", "ctors", "init_array", "reset",
|
ro_sections = ["text", "ctors", "init_array", "reset",
|
||||||
"rodata", "devconfig"]
|
"rodata", "devconfig"]
|
||||||
|
|
162
scripts/sysgen
162
scripts/sysgen
|
@ -802,91 +802,102 @@ def kernel_main_c_pools():
|
||||||
|
|
||||||
kernel_main_c_out("\nint _k_mem_pool_count = %d;\n" % (total_pools))
|
kernel_main_c_out("\nint _k_mem_pool_count = %d;\n" % (total_pools))
|
||||||
|
|
||||||
if (total_pools == 0):
|
if kernel_type == 'micro':
|
||||||
kernel_main_c_out("\nstruct pool_struct * _k_mem_pool_list = NULL;\n")
|
if (total_pools == 0):
|
||||||
return
|
kernel_main_c_out("\nstruct pool_struct * _k_mem_pool_list = NULL;\n")
|
||||||
# Heap pool if present can be indexed using the below variable
|
return
|
||||||
if (heap_pos_in_pool_list != -1):
|
# Heap pool if present can be indexed using the below variable
|
||||||
kernel_main_c_out("\nconst kmemory_pool_t _heap_mem_pool_id = %d;\n" \
|
if (heap_pos_in_pool_list != -1):
|
||||||
%(heap_pos_in_pool_list))
|
kernel_main_c_out("\nconst kmemory_pool_t _heap_mem_pool_id = %d;\n" \
|
||||||
|
%(heap_pos_in_pool_list))
|
||||||
|
|
||||||
# start accumulating memory pool descriptor info
|
# start accumulating memory pool descriptor info
|
||||||
|
|
||||||
pool_descriptors = "\nstruct pool_struct _k_mem_pool_list[%d] =\n{\n" % \
|
pool_descriptors = "\nstruct pool_struct _k_mem_pool_list[%d] =\n{\n" % \
|
||||||
(total_pools)
|
(total_pools)
|
||||||
ident = 0x00010000
|
ident = 0x00010000
|
||||||
|
|
||||||
for pool in pool_list:
|
for pool in pool_list:
|
||||||
|
|
||||||
kernel_main_c_out("\n")
|
kernel_main_c_out("\n")
|
||||||
|
|
||||||
# create local variables relating to current pool
|
# create local variables relating to current pool
|
||||||
|
|
||||||
min_block_size = pool[1]
|
min_block_size = pool[1]
|
||||||
max_block_size = pool[2]
|
max_block_size = pool[2]
|
||||||
num_maximal_blocks = pool[3]
|
num_maximal_blocks = pool[3]
|
||||||
total_memory = max_block_size * num_maximal_blocks
|
total_memory = max_block_size * num_maximal_blocks
|
||||||
buffer = "__" + pool[0] + "_buffer"
|
buffer = "__" + pool[0] + "_buffer"
|
||||||
frag_table = "block_sets_%#010x" % ident
|
frag_table = "block_sets_%#010x" % ident
|
||||||
|
|
||||||
# determine block sizes used by pool (including actual minimum size)
|
# determine block sizes used by pool (including actual minimum size)
|
||||||
|
|
||||||
block_size_list = [max_block_size]
|
block_size_list = [max_block_size]
|
||||||
while (ident != 0): # loop forever
|
while (ident != 0): # loop forever
|
||||||
min_block_size_actual = block_size_list[len(block_size_list) - 1]
|
min_block_size_actual = block_size_list[len(block_size_list) - 1]
|
||||||
min_block_size_proposed = min_block_size_actual / 4
|
min_block_size_proposed = min_block_size_actual / 4
|
||||||
if (min_block_size_proposed < min_block_size):
|
if (min_block_size_proposed < min_block_size):
|
||||||
break
|
break
|
||||||
block_size_list.append(min_block_size_proposed)
|
block_size_list.append(min_block_size_proposed)
|
||||||
frag_levels = len(block_size_list)
|
frag_levels = len(block_size_list)
|
||||||
|
|
||||||
# determine size of quad-block arrays,
|
# determine size of quad-block arrays,
|
||||||
# from the largest block size to the smallest block size
|
# from the largest block size to the smallest block size
|
||||||
# - each array must be big enough to track the status of
|
# - each array must be big enough to track the status of
|
||||||
# the entire memory pool buffer
|
# the entire memory pool buffer
|
||||||
# - each array entry tracks the status of 4 consecutive blocks
|
# - each array entry tracks the status of 4 consecutive blocks
|
||||||
# - need to do rounding up with array for largest block size
|
# - need to do rounding up with array for largest block size
|
||||||
# in case the # of largest size blocks isn't a multiple of 4
|
# in case the # of largest size blocks isn't a multiple of 4
|
||||||
# (i.e. it's final array entry may be partly unused)
|
# (i.e. it's final array entry may be partly unused)
|
||||||
|
|
||||||
quad_block_sizes = [(num_maximal_blocks + 3) / 4]
|
quad_block_sizes = [(num_maximal_blocks + 3) / 4]
|
||||||
quad_block_size_to_use = num_maximal_blocks
|
quad_block_size_to_use = num_maximal_blocks
|
||||||
for index in range(1, frag_levels):
|
for index in range(1, frag_levels):
|
||||||
quad_block_sizes.append(quad_block_size_to_use)
|
quad_block_sizes.append(quad_block_size_to_use)
|
||||||
quad_block_size_to_use *= 4
|
quad_block_size_to_use *= 4
|
||||||
|
|
||||||
# generate array of quad-blocks for each block set
|
# generate array of quad-blocks for each block set
|
||||||
|
|
||||||
for index in range(0, frag_levels):
|
for index in range(0, frag_levels):
|
||||||
kernel_main_c_out(
|
kernel_main_c_out(
|
||||||
"struct pool_quad_block quad_blocks_%#010x_%d[%d];\n" %
|
"struct pool_quad_block quad_blocks_%#010x_%d[%d];\n" %
|
||||||
(ident, index, quad_block_sizes[index]))
|
(ident, index, quad_block_sizes[index]))
|
||||||
|
|
||||||
# generate array of block sets for memory pool
|
# generate array of block sets for memory pool
|
||||||
|
|
||||||
kernel_main_c_out("\nstruct pool_block_set %s[%d] =\n{\n" %
|
kernel_main_c_out("\nstruct pool_block_set %s[%d] =\n{\n" %
|
||||||
(frag_table, frag_levels))
|
(frag_table, frag_levels))
|
||||||
for index in range(0, frag_levels):
|
for index in range(0, frag_levels):
|
||||||
kernel_main_c_out(" { %d, %d, quad_blocks_%#010x_%d},\n" %
|
kernel_main_c_out(" { %d, %d, quad_blocks_%#010x_%d},\n" %
|
||||||
(block_size_list[index], quad_block_sizes[index],
|
(block_size_list[index], quad_block_sizes[index],
|
||||||
ident, index))
|
ident, index))
|
||||||
kernel_main_c_out("};\n")
|
kernel_main_c_out("};\n")
|
||||||
|
|
||||||
# generate memory pool buffer
|
# generate memory pool buffer
|
||||||
|
|
||||||
kernel_main_c_out("\nchar __noinit %s[%d];\n" % (buffer, total_memory))
|
kernel_main_c_out("\nchar __noinit %s[%d];\n" % (buffer, total_memory))
|
||||||
|
|
||||||
# append memory pool descriptor info
|
# append memory pool descriptor info
|
||||||
|
|
||||||
pool_descriptors += " {%d, %d, %d, %d, NULL, %s, %s},\n" % \
|
pool_descriptors += " {%d, %d, %d, %d, NULL, %s, %s},\n" % \
|
||||||
(max_block_size, min_block_size_actual,
|
(max_block_size, min_block_size_actual,
|
||||||
num_maximal_blocks, frag_levels, frag_table, buffer)
|
num_maximal_blocks, frag_levels, frag_table, buffer)
|
||||||
|
|
||||||
ident += 1
|
ident += 1
|
||||||
|
|
||||||
# generate memory pool descriptor info
|
# generate memory pool descriptor info
|
||||||
|
|
||||||
pool_descriptors += "};\n"
|
pool_descriptors += "};\n"
|
||||||
|
elif kernel_type == 'unified':
|
||||||
|
pool_descriptors = ""
|
||||||
|
for pool in pool_list:
|
||||||
|
kernel_main_c_out("\n")
|
||||||
|
min_block_size = pool[1]
|
||||||
|
max_block_size = pool[2]
|
||||||
|
num_maximal_blocks = pool[3]
|
||||||
|
pool_descriptors += "K_MEMORY_POOL_DEFINE(_k_mem_pool_obj_%s, %d, %d, %d);\n" % \
|
||||||
|
(pool[0], min_block_size, max_block_size,
|
||||||
|
num_maximal_blocks)
|
||||||
kernel_main_c_out(pool_descriptors)
|
kernel_main_c_out(pool_descriptors)
|
||||||
|
|
||||||
|
|
||||||
|
@ -967,11 +978,11 @@ def kernel_main_c_generate():
|
||||||
kernel_main_c_mailboxes()
|
kernel_main_c_mailboxes()
|
||||||
kernel_main_c_tasks()
|
kernel_main_c_tasks()
|
||||||
kernel_main_c_pipes()
|
kernel_main_c_pipes()
|
||||||
|
kernel_main_c_pools()
|
||||||
|
|
||||||
if kernel_type == 'micro':
|
if kernel_type == 'micro':
|
||||||
kernel_main_c_kargs()
|
kernel_main_c_kargs()
|
||||||
kernel_main_c_timers()
|
kernel_main_c_timers()
|
||||||
kernel_main_c_pools()
|
|
||||||
kernel_main_c_node_init()
|
kernel_main_c_node_init()
|
||||||
kernel_main_c_priorities()
|
kernel_main_c_priorities()
|
||||||
|
|
||||||
|
@ -1117,6 +1128,7 @@ def generate_sysgen_h_obj_ids():
|
||||||
mbox_struct = 'k_mbox'
|
mbox_struct = 'k_mbox'
|
||||||
mbox_type = 'struct k_mbox *'
|
mbox_type = 'struct k_mbox *'
|
||||||
event_type = 'struct k_event *'
|
event_type = 'struct k_event *'
|
||||||
|
mem_pool_type = 'struct k_mem_pool'
|
||||||
# add missing object types
|
# add missing object types
|
||||||
|
|
||||||
# mutex object ids
|
# mutex object ids
|
||||||
|
@ -1208,12 +1220,22 @@ def generate_sysgen_h_obj_ids():
|
||||||
sysgen_h_data += \
|
sysgen_h_data += \
|
||||||
"#define %s (&_k_event_obj_%s)\n\n" % (name, name)
|
"#define %s (&_k_event_obj_%s)\n\n" % (name, name)
|
||||||
|
|
||||||
# all other object ids
|
# memory pool object ids
|
||||||
|
|
||||||
obj_types = [
|
if kernel_type == 'micro':
|
||||||
[pool_list, 0],
|
obj_types = [
|
||||||
]
|
[pool_list, 0],
|
||||||
sysgen_h_data += generate_obj_id_lines(obj_types)
|
]
|
||||||
|
sysgen_h_data += generate_obj_id_lines(obj_types)
|
||||||
|
elif (kernel_type == 'unified'):
|
||||||
|
for mem_pool in pool_list:
|
||||||
|
name = mem_pool[0];
|
||||||
|
sysgen_h_data += \
|
||||||
|
"extern %s _k_mem_pool_obj_%s;\n" % (mem_pool_type, name)
|
||||||
|
sysgen_h_data += \
|
||||||
|
"#define %s ((%s *)&_k_mem_pool_obj_%s)\n" % (name, mem_pool_type, name)
|
||||||
|
|
||||||
|
# all other object ids
|
||||||
|
|
||||||
|
|
||||||
sysgen_h_footer_include_guard_str = \
|
sysgen_h_footer_include_guard_str = \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue