blob: ae7644231d9344cbb0339039daf08a4e8e82b408 [file] [log] [blame]
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Test memory slab APIs
*
* This module tests the following memory slab routines:
*
* k_mem_slab_alloc
* k_mem_slab_free
* k_mem_slab_num_used_get
*
* @note
* One should ensure that the block is released to the same memory slab from
* which it was allocated, and is only released once. Using an invalid pointer
* will have unpredictable side effects.
*/
#include <tc_util.h>
#include <stdbool.h>
#include <zephyr.h>
#include <ztest.h>
/* size of stack area used by each thread */
#define STACKSIZE (1024 + CONFIG_TEST_EXTRA_STACKSIZE)
/* Number of memory blocks. The minimum number of blocks needed to run the
* test is 2
*/
#define NUMBLOCKS 4
void test_slab_get_all_blocks(void **p);
void test_slab_free_all_blocks(void **p);
K_SEM_DEFINE(SEM_HELPERDONE, 0, 1);
K_SEM_DEFINE(SEM_REGRESSDONE, 0, 1);
K_MEM_SLAB_DEFINE(map_lgblks, 1024, NUMBLOCKS, 4);
/**
*
* @brief Helper task
*
* This routine gets all blocks from the memory slab. It uses semaphores
* SEM_REGRESDONE and SEM_HELPERDONE to synchronize between different parts
* of the test.
*
* @return N/A
*/
void helper_thread(void)
{
void *ptr[NUMBLOCKS]; /* Pointer to memory block */
memset(ptr, 0, sizeof(ptr)); /* keep static checkers happy */
/* Wait for part 1 to complete */
k_sem_take(&SEM_REGRESSDONE, K_FOREVER);
/* Part 2 of test */
TC_PRINT("(2) - Allocate %d blocks in <%s>\n", NUMBLOCKS, __func__);
/* Test k_mem_slab_alloc */
test_slab_get_all_blocks(ptr);
k_sem_give(&SEM_HELPERDONE); /* Indicate part 2 is complete */
/* Wait for part 3 to complete */
k_sem_take(&SEM_REGRESSDONE, K_FOREVER);
/*
* Part 4 of test.
* Free the first memory block. RegressionTask is currently blocked
* waiting (with a timeout) for a memory block. Freeing the memory
* block will unblock RegressionTask.
*/
TC_PRINT("(4) - Free a block in <%s> to unblock the other task "
"from alloc timeout\n", __func__);
TC_PRINT("%s: About to free a memory block\n", __func__);
k_mem_slab_free(&map_lgblks, &ptr[0]);
k_sem_give(&SEM_HELPERDONE);
/* Part 5 of test */
k_sem_take(&SEM_REGRESSDONE, K_FOREVER);
TC_PRINT("(5) <%s> freeing the next block\n", __func__);
TC_PRINT("%s: About to free another memory block\n", __func__);
k_mem_slab_free(&map_lgblks, &ptr[1]);
/*
* Free all the other blocks. The first 2 blocks are freed by this task
*/
for (int i = 2; i < NUMBLOCKS; i++) {
k_mem_slab_free(&map_lgblks, &ptr[i]);
}
TC_PRINT("%s: freed all blocks allocated by this task\n", __func__);
k_sem_give(&SEM_HELPERDONE);
} /* helper thread */
/**
*
* @brief Get all blocks from the memory slab
*
* Get all blocks from the memory slab. It also tries to get one more block
* from the map after the map is empty to verify the error return code.
*
* This routine tests the following:
*
* k_mem_slab_alloc(), k_mem_slab_num_used_get()
*
* @param p pointer to pointer of allocated blocks
*
* @return TC_PASS, TC_FAIL
*/
void test_slab_get_all_blocks(void **p)
{
void *errptr; /* Pointer to block */
for (int i = 0; i < NUMBLOCKS; i++) {
/* Verify number of used blocks in the map */
zassert_equal(k_mem_slab_num_used_get(&map_lgblks), i,
"Failed k_mem_slab_num_used_get");
/* Get memory block */
zassert_equal(k_mem_slab_alloc(&map_lgblks, &p[i], K_NO_WAIT), 0,
"Failed k_mem_slab_alloc");
} /* for */
/*
* Verify number of used blocks in the map - expect all blocks are
* used
*/
zassert_equal(k_mem_slab_num_used_get(&map_lgblks), NUMBLOCKS,
"Failed k_mem_slab_num_used_get");
/* Try to get one more block and it should fail */
zassert_equal(k_mem_slab_alloc(&map_lgblks, &errptr, K_NO_WAIT), -ENOMEM,
"Failed k_mem_slab_alloc");
} /* test_slab_get_all_blocks */
/**
*
* @brief Free all memory blocks
*
* This routine frees all memory blocks and also verifies that the number of
* blocks used are correct.
*
* This routine tests the following:
*
* k_mem_slab_free(&), k_mem_slab_num_used_get(&)
*
* @param p pointer to pointer of allocated blocks
*
* @return TC_PASS, TC_FAIL
*/
void test_slab_free_all_blocks(void **p)
{
for (int i = 0; i < NUMBLOCKS; i++) {
/* Verify number of used blocks in the map */
zassert_equal(k_mem_slab_num_used_get(&map_lgblks), NUMBLOCKS - i,
"Failed k_mem_slab_num_used_get");
TC_PRINT(" block ptr to free p[%d] = %p\n", i, p[i]);
/* Free memory block */
k_mem_slab_free(&map_lgblks, &p[i]);
TC_PRINT("map_lgblks freed %d block\n", i + 1);
} /* for */
/*
* Verify number of used blocks in the map
* - should be 0 as no blocks are used
*/
zassert_equal(k_mem_slab_num_used_get(&map_lgblks), 0,
"Failed k_mem_slab_num_used_get");
} /* test_slab_free_all_blocks */
/**
*
* @brief Main task to test memory slab interfaces
*
* This routine calls test_slab_get_all_blocks() to get all memory blocks from
* the map and calls test_slab_free_all_blocks() to free all memory blocks.
* It also tries to wait (with and without timeout) for a memory block.
*
* This routine tests the following:
*
* k_mem_slab_alloc
*
* @return N/A
*/
void test_mslab(void)
{
int ret_value; /* task_mem_map_xxx interface return value */
void *b; /* Pointer to memory block */
void *ptr[NUMBLOCKS]; /* Pointer to memory block */
/* not strictly necessary, but keeps coverity checks happy */
memset(ptr, 0, sizeof(ptr));
/* Part 1 of test */
TC_PRINT("(1) - Allocate and free %d blocks "
"in <%s>\n", NUMBLOCKS, __func__);
/* Test k_mem_slab_alloc */
test_slab_get_all_blocks(ptr);
/* Test task_mem_map_free */
test_slab_free_all_blocks(ptr);
k_sem_give(&SEM_REGRESSDONE); /* Allow helper thread to run */
/* Wait for helper thread to finish */
k_sem_take(&SEM_HELPERDONE, K_FOREVER);
/*
* Part 3 of test.
*
* helper thread got all memory blocks. There is no free block left.
* The call will timeout. Note that control does not switch back to
* helper thread as it is waiting for SEM_REGRESSDONE.
*/
TC_PRINT("(3) - Further allocation results in timeout "
"in <%s>\n", __func__);
ret_value = k_mem_slab_alloc(&map_lgblks, &b, 20);
zassert_equal(-EAGAIN, ret_value,
"Failed k_mem_slab_alloc, retValue %d\n", ret_value);
TC_PRINT("%s: start to wait for block\n", __func__);
k_sem_give(&SEM_REGRESSDONE); /* Allow helper thread to run part 4 */
ret_value = k_mem_slab_alloc(&map_lgblks, &b, 50);
zassert_equal(0, ret_value,
"Failed k_mem_slab_alloc, ret_value %d\n", ret_value);
/* Wait for helper thread to complete */
k_sem_take(&SEM_HELPERDONE, K_FOREVER);
TC_PRINT("%s: start to wait for block\n", __func__);
k_sem_give(&SEM_REGRESSDONE); /* Allow helper thread to run part 5 */
ret_value = k_mem_slab_alloc(&map_lgblks, &b, K_FOREVER);
zassert_equal(0, ret_value,
"Failed k_mem_slab_alloc, ret_value %d\n", ret_value);
/* Wait for helper thread to complete */
k_sem_take(&SEM_HELPERDONE, K_FOREVER);
/* Free memory block */
TC_PRINT("%s: Used %d block\n", __func__,
k_mem_slab_num_used_get(&map_lgblks));
k_mem_slab_free(&map_lgblks, &b);
TC_PRINT("%s: 1 block freed, used %d block\n",
__func__, k_mem_slab_num_used_get(&map_lgblks));
}
K_THREAD_DEFINE(HELPER, STACKSIZE, helper_thread, NULL, NULL, NULL,
7, 0, K_NO_WAIT);
/*test case main entry*/
void test_main(void)
{
ztest_test_suite(test_memory_slab,
ztest_unit_test(test_mslab));
ztest_run_test_suite(test_memory_slab);
}