mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-03 07:11:56 +00:00
The block alignment must be enforced for statically allocated slabs as well as runtime initialized ones. It is best to implement this check only once in create_free_list() which is invoked by both k_mem_slab_init() and init_mem_slab_module(), where pointers are about to be set for the first time. It is then unnecessary to perform this test on every slab allocation as the alignment won't change at that point. And not only the block size needs to be aligned, but the buffer as well. Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
132 lines
3.0 KiB
C
132 lines
3.0 KiB
C
/*
|
|
* Copyright (c) 2016 Wind River Systems, Inc.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <kernel.h>
|
|
#include <kernel_structs.h>
|
|
#include <debug/object_tracing_common.h>
|
|
#include <toolchain.h>
|
|
#include <linker/sections.h>
|
|
#include <wait_q.h>
|
|
#include <misc/dlist.h>
|
|
#include <ksched.h>
|
|
#include <init.h>
|
|
|
|
static struct k_spinlock lock;
|
|
|
|
#ifdef CONFIG_OBJECT_TRACING
|
|
struct k_mem_slab *_trace_list_k_mem_slab;
|
|
#endif /* CONFIG_OBJECT_TRACING */
|
|
|
|
/**
|
|
* @brief Initialize kernel memory slab subsystem.
|
|
*
|
|
* 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 slab.
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static void create_free_list(struct k_mem_slab *slab)
|
|
{
|
|
u32_t j;
|
|
char *p;
|
|
|
|
/* blocks must be word aligned */
|
|
__ASSERT(((slab->block_size | (uintptr_t)slab->buffer)
|
|
& (sizeof(void *) - 1)) == 0,
|
|
"slab at %p not word aligned", slab);
|
|
|
|
slab->free_list = NULL;
|
|
p = slab->buffer;
|
|
|
|
for (j = 0U; j < slab->num_blocks; j++) {
|
|
*(char **)p = slab->free_list;
|
|
slab->free_list = p;
|
|
p += slab->block_size;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Complete initialization of statically defined memory slabs.
|
|
*
|
|
* Perform any initialization that wasn't done at build time.
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static int init_mem_slab_module(struct device *dev)
|
|
{
|
|
ARG_UNUSED(dev);
|
|
|
|
Z_STRUCT_SECTION_FOREACH(k_mem_slab, slab) {
|
|
create_free_list(slab);
|
|
SYS_TRACING_OBJ_INIT(k_mem_slab, slab);
|
|
z_object_init(slab);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
SYS_INIT(init_mem_slab_module, PRE_KERNEL_1,
|
|
CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
|
|
|
|
void k_mem_slab_init(struct k_mem_slab *slab, void *buffer,
|
|
size_t block_size, u32_t num_blocks)
|
|
{
|
|
slab->num_blocks = num_blocks;
|
|
slab->block_size = block_size;
|
|
slab->buffer = buffer;
|
|
slab->num_used = 0U;
|
|
create_free_list(slab);
|
|
z_waitq_init(&slab->wait_q);
|
|
SYS_TRACING_OBJ_INIT(k_mem_slab, slab);
|
|
|
|
z_object_init(slab);
|
|
}
|
|
|
|
int k_mem_slab_alloc(struct k_mem_slab *slab, void **mem, s32_t timeout)
|
|
{
|
|
k_spinlock_key_t key = k_spin_lock(&lock);
|
|
int result;
|
|
|
|
if (slab->free_list != NULL) {
|
|
/* take a free block */
|
|
*mem = slab->free_list;
|
|
slab->free_list = *(char **)(slab->free_list);
|
|
slab->num_used++;
|
|
result = 0;
|
|
} else if (timeout == K_NO_WAIT) {
|
|
/* don't wait for a free block to become available */
|
|
*mem = NULL;
|
|
result = -ENOMEM;
|
|
} else {
|
|
/* wait for a free block or timeout */
|
|
result = z_pend_curr(&lock, key, &slab->wait_q, timeout);
|
|
if (result == 0) {
|
|
*mem = _current->base.swap_data;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
k_spin_unlock(&lock, key);
|
|
|
|
return result;
|
|
}
|
|
|
|
void k_mem_slab_free(struct k_mem_slab *slab, void **mem)
|
|
{
|
|
k_spinlock_key_t key = k_spin_lock(&lock);
|
|
struct k_thread *pending_thread = z_unpend_first_thread(&slab->wait_q);
|
|
|
|
if (pending_thread != NULL) {
|
|
z_set_thread_return_value_with_data(pending_thread, 0, *mem);
|
|
z_ready_thread(pending_thread);
|
|
z_reschedule(&lock, key);
|
|
} else {
|
|
**(char ***)mem = slab->free_list;
|
|
slab->free_list = *(char **)mem;
|
|
slab->num_used--;
|
|
k_spin_unlock(&lock, key);
|
|
}
|
|
}
|