summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorAllan Stephens <allan.stephens@windriver.com>2016-10-13 15:44:48 -0500
committerAnas Nashif <nashif@linux.intel.com>2016-10-25 00:10:34 +0000
commit480a131ad94f8ddb375ec7cef5c7f7c0bb3e6a06 (patch)
tree3e827b4f65e5793f1fbaffa733c003930304b096 /kernel
parent904cf972632de023cedc49e801c4c071cc35f79d (diff)
unified: Support heap memory pool
Fleshes out the prototype heap memory pool support to make it fully operational. Noteworthy changes are listed below: Tweaks arguments to k_malloc() and k_free() to be more like malloc() and free(). Similarly, modifies k_free() to take no action when passed a NULL pointer. Now stores the complete block descriptor at the start of any block allocated from the heap memory pool. This increases memory overhead by 4 bytes per block, but streamlines the allocation and freeing algorithms. It also ensures that the routines will work if the block descriptor internals are changed in the future. Now allows the heap memory pool to be defined using the HEAP_MEM_POOL_SIZE configuration option. This will be the official configuration approach in the unified kernel. Also allows the heap memory pool to be defined using the (undocumented) HEAP_SIZE entry in the MDEF. This is provided for legacy reasons only. Co-locates memory pool initialization code to keep the line that causes memory pool initialization to be done during booting right next to the routine that does the initialization. Change-Id: Ifea9d88142fb434d4bea38bb1fcc4856a3853d8d Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/unified/Kconfig10
-rw-r--r--kernel/unified/mem_pool.c122
2 files changed, 75 insertions, 57 deletions
diff --git a/kernel/unified/Kconfig b/kernel/unified/Kconfig
index d8afd2341..ff803fab6 100644
--- a/kernel/unified/Kconfig
+++ b/kernel/unified/Kconfig
@@ -319,4 +319,14 @@ config MEM_POOL_AD_AFTER_SEARCH_FOR_BIGGERBLOCK
endchoice
+config HEAP_MEM_POOL_SIZE
+ int
+ prompt "Heap memory pool size (in bytes)"
+ default 0
+ help
+ This option specifies the size of the heap memory pool used when
+ dynamically allocating memory using k_malloc(). Supported values
+ are: 256, 1024, 4096, and 16384. A size of zero means that no
+ heap memory pool is defined.
+
endmenu
diff --git a/kernel/unified/mem_pool.c b/kernel/unified/mem_pool.c
index 8bf8b066c..3d57b1a22 100644
--- a/kernel/unified/mem_pool.c
+++ b/kernel/unified/mem_pool.c
@@ -24,17 +24,14 @@
#include <ksched.h>
#include <wait_q.h>
#include <init.h>
+#include <stdlib.h>
+#include <string.h>
#define _QUAD_BLOCK_AVAILABLE 0x0F
#define _QUAD_BLOCK_ALLOCATED 0x0
extern struct k_mem_pool _k_mem_pool_start[];
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);
@@ -61,6 +58,8 @@ static int init_static_pools(struct device *unused)
return 0;
}
+SYS_INIT(init_static_pools, PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
+
/**
*
* @brief Initialize the memory pool
@@ -523,45 +522,6 @@ int k_mem_pool_alloc(struct k_mem_pool *pool, struct k_mem_block *block,
return -ENOMEM;
}
-
-#define MALLOC_ALIGN (sizeof(uint32_t))
-
-void *k_malloc(size_t size)
-{
- 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,
- K_NO_WAIT) != 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_mem_pool_free(struct k_mem_block *block)
{
int offset;
@@ -579,22 +539,70 @@ void k_mem_pool_free(struct k_mem_block *block)
k_sched_unlock();
}
-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");
+/*
+ * Heap memory pool support
+ */
+
+#if (CONFIG_HEAP_MEM_POOL_SIZE > 0)
+
+/*
+ * Case 1: Heap is defined using HEAP_MEM_POOL_SIZE configuration option.
+ *
+ * This module defines the heap memory pool and the _HEAP_MEM_POOL symbol
+ * that has the address of the associated memory pool struct.
+ */
+
+K_MEM_POOL_DEFINE(_heap_mem_pool, 64, CONFIG_HEAP_MEM_POOL_SIZE, 1, 4);
+#define _HEAP_MEM_POOL (&_heap_mem_pool)
+
+#else
- mem_block.pool_id = heap_mem_pool;
+/*
+ * Case 2: Heap is defined using HEAP_SIZE item type in MDEF.
+ *
+ * Sysgen defines the heap memory pool and the _heap_mem_pool_ptr variable
+ * that has the address of the associated memory pool struct. This module
+ * defines the _HEAP_MEM_POOL symbol as an alias for _heap_mem_pool_ptr.
+ *
+ * Note: If the MDEF does not define the heap memory pool k_malloc() will
+ * compile successfully, but will trigger a link error if it is used.
+ */
- /* 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);
+extern struct k_mem_pool * const _heap_mem_pool_ptr;
+#define _HEAP_MEM_POOL _heap_mem_pool_ptr
- k_mem_pool_free(&mem_block);
+#endif /* CONFIG_HEAP_MEM_POOL_SIZE */
+
+
+void *k_malloc(size_t size)
+{
+ struct k_mem_block block;
+
+ /*
+ * get a block large enough to hold an initial (hidden) block
+ * descriptor, as well as the space the caller requested
+ */
+ size += sizeof(struct k_mem_block);
+ if (k_mem_pool_alloc(_HEAP_MEM_POOL, &block, size, K_NO_WAIT) != 0) {
+ return NULL;
+ }
+
+ /* save the block descriptor info at the start of the actual block */
+ memcpy(block.data, &block, sizeof(struct k_mem_block));
+
+ /* return address of the user area part of the block to the caller */
+ return (char *)block.data + sizeof(struct k_mem_block);
}
-SYS_INIT(init_static_pools, PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
+
+void k_free(void *ptr)
+{
+ if (ptr != NULL) {
+ /* point to hidden block descriptor at start of block */
+ ptr = (char *)ptr - sizeof(struct k_mem_block);
+
+ /* return block to the heap memory pool */
+ k_mem_pool_free(ptr);
+ }
+}