blob: 7fc6946779cc13920f4c93dc034326bc9fa96003 [file] [log] [blame]
/*
* Copyright (c) 2020 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/ztest.h>
#include <zephyr/irq_offload.h>
#include "test_kheap.h"
#define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
struct k_thread tdata;
K_HEAP_DEFINE(k_heap_test, HEAP_SIZE);
#define ALLOC_SIZE_1 1024
#define ALLOC_SIZE_2 1536
#define ALLOC_SIZE_3 2049
static void tIsr_kheap_alloc_nowait(void *data)
{
ARG_UNUSED(data);
char *p = (char *)k_heap_alloc(&k_heap_test, ALLOC_SIZE_1, K_NO_WAIT);
zassert_not_null(p, "k_heap_alloc operation failed");
k_heap_free(&k_heap_test, p);
}
static void thread_alloc_heap(void *p1, void *p2, void *p3)
{
char *p;
k_timeout_t timeout = Z_TIMEOUT_MS(200);
p = (char *)k_heap_alloc(&k_heap_test, ALLOC_SIZE_2, K_NO_WAIT);
zassert_is_null(p, "k_heap_alloc should fail but did not");
p = (char *)k_heap_alloc(&k_heap_test, ALLOC_SIZE_2, timeout);
zassert_not_null(p, "k_heap_alloc failed to allocate memory");
k_heap_free(&k_heap_test, p);
}
static void thread_alloc_heap_null(void *p1, void *p2, void *p3)
{
char *p;
k_timeout_t timeout = Z_TIMEOUT_MS(200);
p = (char *)k_heap_alloc(&k_heap_test, ALLOC_SIZE_2, K_NO_WAIT);
zassert_is_null(p, "k_heap_alloc should fail but did not");
p = (char *)k_heap_alloc(&k_heap_test, ALLOC_SIZE_2, timeout);
zassert_is_null(p, "k_heap_alloc should fail but did not");
k_heap_free(&k_heap_test, p);
}
/*test cases*/
/* These need to be adjacent in BSS */
volatile uint32_t heap_guard0;
K_HEAP_DEFINE(tiny_heap, 1);
volatile uint32_t heap_guard1;
/** @brief Test a minimum-size static k_heap
* @ingroup kernel_kheap_api_tests
*
* @details Create a minimum size (1-byte) static heap, verify that it
* works to allocate that byte at runtime and that it doesn't overflow
* its memory bounds.
*/
ZTEST(k_heap_api, test_k_heap_min_size)
{
const uint32_t guard_bits = 0x5a5a5a5a;
/* Make sure static initialization didn't scribble on them */
zassert_true(heap_guard0 == 0 && heap_guard1 == 0,
"static heap initialization overran buffer");
heap_guard0 = guard_bits;
heap_guard1 = guard_bits;
char *p0 = k_heap_alloc(&tiny_heap, 1, K_NO_WAIT);
char *p1 = k_heap_alloc(&tiny_heap, 1, K_NO_WAIT);
zassert_not_null(p0, "allocation failed");
zassert_is_null(p1, "second allocation unexpectedly succeeded");
*p0 = 0xff;
k_heap_free(&tiny_heap, p0);
zassert_equal(heap_guard0, guard_bits, "heap overran buffer");
zassert_equal(heap_guard1, guard_bits, "heap overran buffer");
}
/**
* @brief Test to demonstrate k_heap_alloc() and k_heap_free() API usage
*
* @ingroup kernel_kheap_api_tests
*
* @details The test allocates 1024 bytes from 2048 byte heap,
* and checks if allocation is successful or not
*
* @see k_heap_malloc(), k_heap_Free()
*/
ZTEST(k_heap_api, test_k_heap_alloc)
{
k_timeout_t timeout = Z_TIMEOUT_US(TIMEOUT);
char *p = (char *)k_heap_alloc(&k_heap_test, ALLOC_SIZE_1, timeout);
zassert_not_null(p, "k_heap_alloc operation failed");
for (int i = 0; i < ALLOC_SIZE_1; i++) {
p[i] = '0';
}
k_heap_free(&k_heap_test, p);
}
/**
* @brief Test to demonstrate k_heap_alloc() and k_heap_free() API usage
*
* @ingroup kernel_kheap_api_tests
*
* @details The test allocates 2049 bytes, which is greater than the heap
* size(2048 bytes), and checks for NULL return from k_heap_alloc
*
* @see k_heap_malloc(), k_heap_Free()
*/
ZTEST(k_heap_api, test_k_heap_alloc_fail)
{
k_timeout_t timeout = Z_TIMEOUT_US(TIMEOUT);
char *p = (char *)k_heap_alloc(&k_heap_test, ALLOC_SIZE_3, timeout);
zassert_is_null(p, NULL);
k_heap_free(&k_heap_test, p);
}
/**
* @brief Test to demonstrate k_heap_free() API functionality.
*
* @ingroup kernel_kheap_api_tests
*
* @details The test validates k_heap_free()
* API, by using below steps
* 1. allocate the memory from the heap,
* 2. free the allocated memory
* 3. allocate memory more than the first allocation.
* the allocation in the 3rd step should succeed if k_heap_free()
* works as expected
*
* @see k_heap_alloc, k_heap_free()
*/
ZTEST(k_heap_api, test_k_heap_free)
{
k_timeout_t timeout = Z_TIMEOUT_US(TIMEOUT);
char *p = (char *)k_heap_alloc(&k_heap_test, ALLOC_SIZE_1, timeout);
zassert_not_null(p, "k_heap_alloc operation failed");
k_heap_free(&k_heap_test, p);
p = (char *)k_heap_alloc(&k_heap_test, ALLOC_SIZE_2, timeout);
zassert_not_null(p, "k_heap_alloc operation failed");
for (int i = 0; i < ALLOC_SIZE_2; i++) {
p[i] = '0';
}
k_heap_free(&k_heap_test, p);
}
/**
* @brief Validate allocation and free heap memory in isr context.
*
* @details The test validates k_heap_alloc() in isr context, the timeout
* param should be K_NO_WAIT, because this situation isn't allow to wait.
*
* @ingroup kernel_heap_tests
*/
ZTEST(k_heap_api, test_kheap_alloc_in_isr_nowait)
{
irq_offload((irq_offload_routine_t)tIsr_kheap_alloc_nowait, NULL);
}
/**
* @brief Validate the k_heap support wait between different threads.
*
* @details In main thread alloc a buffer from the heap, then run the
* child thread. If there isn't enough space in the heap, the child thread
* will wait timeout long until main thread free the buffer to heap.
*
* @ingroup kernel_heap_tests
*/
ZTEST(k_heap_api, test_k_heap_alloc_pending)
{
/*
* Allocate first to make sure subsequent allocations
* either fail (K_NO_WAIT) or pend.
*/
char *p = (char *)k_heap_alloc(&k_heap_test, ALLOC_SIZE_2, K_NO_WAIT);
zassert_not_null(p, "k_heap_alloc operation failed");
/* Create a thread which will pend on allocation */
k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
thread_alloc_heap, NULL, NULL, NULL,
K_PRIO_PREEMPT(5), 0, K_NO_WAIT);
/* Sleep long enough for child thread to go into pending */
k_msleep(5);
/*
* Free memory so the child thread can finish memory allocation
* without failing.
*/
k_heap_free(&k_heap_test, p);
k_thread_join(tid, K_FOREVER);
}
/**
* @brief Validate the k_heap alloc_pending_null support.
*
* @details In main thread alloc two buffer from the heap, then run the
* child thread which alloc a buffer larger than remaining space. The child thread
* will wait timeout long until main thread free one of the buffer to heap, space in
* the heap is still not enough and then return null after timeout.
*
* @ingroup kernel_heap_tests
*/
ZTEST(k_heap_api, test_k_heap_alloc_pending_null)
{
/*
* Allocate first to make sure subsequent allocations
* either fail (K_NO_WAIT) or pend.
*/
char *p = (char *)k_heap_alloc(&k_heap_test, ALLOC_SIZE_1, K_NO_WAIT);
char *q = (char *)k_heap_alloc(&k_heap_test, 512, K_NO_WAIT);
zassert_not_null(p, "k_heap_alloc operation failed");
zassert_not_null(q, "k_heap_alloc operation failed");
/* Create a thread which will pend on allocation */
k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
thread_alloc_heap_null, NULL, NULL, NULL,
K_PRIO_PREEMPT(5), 0, K_NO_WAIT);
/* Sleep long enough for child thread to go into pending */
k_msleep(5);
/*
* Free some memory but new thread will still not be able
* to finish memory allocation without error.
*/
k_heap_free(&k_heap_test, q);
k_thread_join(tid, K_FOREVER);
k_heap_free(&k_heap_test, p);
}