From fb20912cb57c1aa0f66c516115bf173b5df93d07 Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Mon, 19 Dec 2016 20:28:07 -0800 Subject: [PATCH] tests: kernel: test_slab: Porting memory map tests to unified In unified kernel, memory maps are renamed as memory slabs. This change ports tests/legacy/kernel/test_map stuff to use unified APIs. Change-Id: Ibf4d60fb53e45a119e6828a09f2638ee7def76b7 Signed-off-by: Jithu Joseph Signed-off-by: Anas Nashif --- tests/kernel/mem_slab/Makefile | 4 + tests/kernel/mem_slab/README.txt | 94 +++++++ tests/kernel/mem_slab/prj.conf | 1 + tests/kernel/mem_slab/src/Makefile | 3 + tests/kernel/mem_slab/src/slab.c | 436 +++++++++++++++++++++++++++++ tests/kernel/mem_slab/testcase.ini | 3 + 6 files changed, 541 insertions(+) create mode 100644 tests/kernel/mem_slab/Makefile create mode 100644 tests/kernel/mem_slab/README.txt create mode 100644 tests/kernel/mem_slab/prj.conf create mode 100644 tests/kernel/mem_slab/src/Makefile create mode 100644 tests/kernel/mem_slab/src/slab.c create mode 100644 tests/kernel/mem_slab/testcase.ini diff --git a/tests/kernel/mem_slab/Makefile b/tests/kernel/mem_slab/Makefile new file mode 100644 index 00000000000..4de50f93d4d --- /dev/null +++ b/tests/kernel/mem_slab/Makefile @@ -0,0 +1,4 @@ +BOARD ?= qemu_x86 +CONF_FILE = prj.conf + +include ${ZEPHYR_BASE}/Makefile.inc diff --git a/tests/kernel/mem_slab/README.txt b/tests/kernel/mem_slab/README.txt new file mode 100644 index 00000000000..0a5f554ef07 --- /dev/null +++ b/tests/kernel/mem_slab/README.txt @@ -0,0 +1,94 @@ +Title: Memory Slab APIs + +Description: + +This test verifies that the kernel memory slab APIs operate as expected. + +-------------------------------------------------------------------------------- + +Building and Running Project: + +This microkernel project outputs to the console. It can be built and executed +on QEMU as follows: + + make qemu + +-------------------------------------------------------------------------------- + +Troubleshooting: + +Problems caused by out-dated project information can be addressed by +issuing one of the following commands then rebuilding the project: + + make clean # discard results of previous builds + # but keep existing configuration info +or + make pristine # discard results of previous builds + # and restore pre-defined configuration info + +-------------------------------------------------------------------------------- + +Sample Output: + +tc_start() - Test Kernel memory slabs +Starts RegressionTask +=================================================================== +(1) - Allocate and free 2 blocks in +=================================================================== +Function testSlabGetAllBlocks +MAP_LgBlks used 0 blocks + k_mem_slab_alloc OK, p[0] = 0x00104e00 +MAP_LgBlks used 1 blocks + k_mem_slab_alloc OK, p[1] = 0x00104a00 +MAP_LgBlks used 2 blocks + k_mem_slab_alloc RC_FAIL expected as all (2) blocks are used. +=================================================================== +printPointers: p[0] = 0x00104e00, p[1] = 0x00104a00, +=================================================================== +Function testSlabFreeAllBlocks +MAP_LgBlks used 2 blocks + block ptr to free p[0] = 0x00104e00 +MAP_LgBlks freed 1 block +MAP_LgBlks used 1 blocks + block ptr to free p[1] = 0x00104a00 +MAP_LgBlks freed 2 block +MAP_LgBlks used 0 blocks +=================================================================== +Starts HelperTask +=================================================================== +(2) - Allocate 2 blocks in +=================================================================== +Function testSlabGetAllBlocks +MAP_LgBlks used 0 blocks + k_mem_slab_alloc OK, p[0] = 0x00104a00 +MAP_LgBlks used 1 blocks + k_mem_slab_alloc OK, p[1] = 0x00104e00 +MAP_LgBlks used 2 blocks + k_mem_slab_alloc RC_FAIL expected as all (2) blocks are used. +=================================================================== +=================================================================== +(3) - Further allocation results in timeout in +=================================================================== +RegressionTask: k_mem_slab_alloc times out which is expected +RegressionTask: start to wait for block +=================================================================== +(4) - Free a block in to unblock the other task from alloc timeout +=================================================================== +HelperTask: About to free a memory block +RegressionTask: k_mem_slab_alloc OK, block allocated at 0x00104a00 +RegressionTask: start to wait for block +=================================================================== +(5) freeing the next block +=================================================================== +HelperTask: About to free another memory block +RegressionTask: k_mem_slab_alloc OK, block allocated at 0x00104e00 +HelperTask: freed all blocks allocated by this task +=================================================================== +PASS - HelperTask. +RegressionTask: Used 2 block +RegressionTask: 1 block freed, used 1 block +=================================================================== +PASS - RegressionTask. +=================================================================== +PROJECT EXECUTION SUCCESSFUL + diff --git a/tests/kernel/mem_slab/prj.conf b/tests/kernel/mem_slab/prj.conf new file mode 100644 index 00000000000..d8f773ce3c9 --- /dev/null +++ b/tests/kernel/mem_slab/prj.conf @@ -0,0 +1 @@ +# nothing yet diff --git a/tests/kernel/mem_slab/src/Makefile b/tests/kernel/mem_slab/src/Makefile new file mode 100644 index 00000000000..4cdbcd278fa --- /dev/null +++ b/tests/kernel/mem_slab/src/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -I${ZEPHYR_BASE}/tests/include + +obj-y = slab.o diff --git a/tests/kernel/mem_slab/src/slab.c b/tests/kernel/mem_slab/src/slab.c new file mode 100644 index 00000000000..a931b49b03d --- /dev/null +++ b/tests/kernel/mem_slab/src/slab.c @@ -0,0 +1,436 @@ +/* map.c - test memory slab APIs */ + +/* + * Copyright (c) 2012-2014 Wind River Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief Test memory slab APIs + * + * This module tests the following map routines: + * + * k_mem_slab_alloc + * task_mem_map_free + * task_mem_map_used_get + * + * @note + * One should ensure that the block is released to the same map from which it + * was allocated, and is only released once. Using an invalid pointer will + * have unpredictable side effects. + */ + +#include +#include +#include + +/* size of stack area used by each thread */ +#define STACKSIZE 2048 + +/* Number of memory blocks. The minimum number of blocks needed to run the + * test is 2 + */ +#define NUMBLOCKS 2 + +static int tcRC = TC_PASS; /* test case return code */ + +int testSlabGetAllBlocks(void **P); +int testSlabFreeAllBlocks(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 Verify return value + * + * This routine verifies current value against expected value + * and returns true if they are the same. + * + * @param expectRetValue expect value + * @param currentRetValue current value + * + * @return true, false + */ + +bool verifyRetValue(int expectRetValue, int currentRetValue) +{ + return (expectRetValue == currentRetValue); + +} /* verifyRetValue */ + +/** + * + * @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 HelperTask(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("Starts %s\n", __func__); + PRINT_LINE; + TC_PRINT("(2) - Allocate %d blocks in <%s>\n", NUMBLOCKS, __func__); + PRINT_LINE; + + /* Test k_mem_slab_alloc */ + tcRC = testSlabGetAllBlocks(ptr); + if (tcRC == TC_FAIL) { + TC_ERROR("Failed testSlabGetAllBlocks function\n"); + goto exitTest1; /* terminate test */ + } + + 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. + */ + PRINT_LINE; + TC_PRINT("(4) - Free a block in <%s> to unblock the other task " + "from alloc timeout\n", __func__); + PRINT_LINE; + + 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); + PRINT_LINE; + TC_PRINT("(5) <%s> freeing the next block\n", __func__); + PRINT_LINE; + 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__); + +exitTest1: + + TC_END_RESULT(tcRC); + k_sem_give(&SEM_HELPERDONE); +} /* HelperTask */ + + +/** + * + * @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 + */ + +int testSlabGetAllBlocks(void **p) +{ + int retValue; /* task_mem_map_xxx interface return value */ + void *errPtr; /* Pointer to block */ + + TC_PRINT("Function %s\n", __func__); + + /* Number of blocks in the map is defined in MDEF file */ + for (int i = 0; i < NUMBLOCKS; i++) { + /* Verify number of used blocks in the map */ + retValue = k_mem_slab_num_used_get(&MAP_LgBlks); + if (verifyRetValue(i, retValue)) { + TC_PRINT("MAP_LgBlks used %d blocks\n", retValue); + } else { + TC_ERROR("Failed task_mem_map_used_get for " + "MAP_LgBlks, i=%d, retValue=%d\n", + i, retValue); + return TC_FAIL; + } + + /* Get memory block */ + retValue = k_mem_slab_alloc(&MAP_LgBlks, &p[i], K_NO_WAIT); + if (verifyRetValue(RC_OK, retValue)) { + TC_PRINT(" k_mem_slab_alloc OK, p[%d] = %p\n", + i, p[i]); + } else { + TC_ERROR("Failed k_mem_slab_alloc, i=%d, " + "retValue %d\n", i, retValue); + return TC_FAIL; + } + + } /* for */ + + /* Verify number of used blocks in the map - expect all blocks are + * used + */ + retValue = k_mem_slab_num_used_get(&MAP_LgBlks); + if (verifyRetValue(NUMBLOCKS, retValue)) { + TC_PRINT("MAP_LgBlks used %d blocks\n", retValue); + } else { + TC_ERROR("Failed task_mem_map_used_get for MAP_LgBlks, " + "retValue %d\n", retValue); + return TC_FAIL; + } + + /* Try to get one more block and it should fail */ + retValue = k_mem_slab_alloc(&MAP_LgBlks, &errPtr, K_NO_WAIT); + if (verifyRetValue(-ENOMEM, retValue)) { + TC_PRINT(" k_mem_slab_alloc RC_FAIL expected as all (%d) " + "blocks are used.\n", NUMBLOCKS); + } else { + TC_ERROR("Failed k_mem_slab_alloc, expect RC_FAIL, got %d\n", + retValue); + return TC_FAIL; + } + + PRINT_LINE; + + return TC_PASS; +} /* testSlabGetAllBlocks */ + +/** + * + * @brief Free all memeory 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 + */ + +int testSlabFreeAllBlocks(void **p) +{ + int retValue; /* task_mem_map_xxx interface return value */ + + TC_PRINT("Function %s\n", __func__); + + /* Number of blocks in the map is defined in MDEF file */ + for (int i = 0; i < NUMBLOCKS; i++) { + /* Verify number of used blocks in the map */ + retValue = k_mem_slab_num_used_get(&MAP_LgBlks); + if (verifyRetValue(NUMBLOCKS - i, retValue)) { + TC_PRINT("MAP_LgBlks used %d blocks\n", retValue); + } else { + TC_ERROR("Failed task_mem_map_used_get for " + "MAP_LgBlks, expect %d, got %d\n", + NUMBLOCKS - i, retValue); + return TC_FAIL; + } + + 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 + */ + + retValue = k_mem_slab_num_used_get(&MAP_LgBlks); + if (verifyRetValue(0, retValue)) { + TC_PRINT("MAP_LgBlks used %d blocks\n", retValue); + } else { + TC_ERROR("Failed task_mem_map_used_get for MAP_LgBlks, " + "retValue %d\n", retValue); + return TC_FAIL; + } + + PRINT_LINE; + return TC_PASS; +} /* testSlabFreeAllBlocks */ + +/** + * + * @brief Print the pointers + * + * This routine prints out the pointers. + * + * @param pointer pointer to pointer of allocated blocks + * + * @return N/A + */ +void printPointers(void **pointer) +{ + TC_PRINT("%s: ", __func__); + for (int i = 0; i < NUMBLOCKS; i++) { + TC_PRINT("p[%d] = %p, ", i, pointer[i]); + } + + TC_PRINT("\n"); + PRINT_LINE; + +} /* printPointers */ + +/** + * + * @brief Main task to test task_mem_map_xxx interfaces + * + * This routine calls testSlabGetAllBlocks() to get all memory blocks from the + * map and calls testSlabFreeAllBlocks() 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 RegressionTask(void) +{ + int retValue; /* 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_START("Test Kernel memory slabs"); + TC_PRINT("Starts %s\n", __func__); + PRINT_LINE; + TC_PRINT("(1) - Allocate and free %d blocks " + "in <%s>\n", NUMBLOCKS, __func__); + PRINT_LINE; + + /* Test k_mem_slab_alloc */ + tcRC = testSlabGetAllBlocks(ptr); + if (tcRC == TC_FAIL) { + TC_ERROR("Failed testSlabGetAllBlocks function\n"); + goto exitTest; /* terminate test */ + } + + printPointers(ptr); + /* Test task_mem_map_free */ + tcRC = testSlabFreeAllBlocks(ptr); + if (tcRC == TC_FAIL) { + TC_ERROR("Failed testSlabFreeAllBlocks function\n"); + goto exitTest; /* terminate test */ + } + + k_sem_give(&SEM_REGRESSDONE); /* Allow HelperTask to run */ + /* Wait for HelperTask to finish */ + k_sem_take(&SEM_HELPERDONE, K_FOREVER); + + /* + * Part 3 of test. + * + * HelperTask got all memory blocks. There is no free block left. + * The call will timeout. Note that control does not switch back to + * HelperTask as it is waiting for SEM_REGRESSDONE. + */ + + PRINT_LINE; + TC_PRINT("(3) - Further allocation results in timeout " + "in <%s>\n", __func__); + PRINT_LINE; + + retValue = k_mem_slab_alloc(&MAP_LgBlks, &b, 20); + if (verifyRetValue(-EAGAIN, retValue)) { + TC_PRINT("%s: k_mem_slab_alloc times out which is " + "expected\n", __func__); + } else { + TC_ERROR("Failed k_mem_slab_alloc, retValue %d\n", retValue); + tcRC = TC_FAIL; + goto exitTest; /* terminate test */ + } + + TC_PRINT("%s: start to wait for block\n", __func__); + k_sem_give(&SEM_REGRESSDONE); /* Allow HelperTask to run part 4 */ + retValue = k_mem_slab_alloc(&MAP_LgBlks, &b, 50); + if (verifyRetValue(RC_OK, retValue)) { + TC_PRINT("%s: k_mem_slab_alloc OK, block allocated at %p\n", + __func__, b); + } else { + TC_ERROR("Failed k_mem_slab_alloc, retValue %d\n", retValue); + tcRC = TC_FAIL; + goto exitTest; /* terminate test */ + } + + /* Wait for HelperTask 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 HelperTask to run part 5 */ + retValue = k_mem_slab_alloc(&MAP_LgBlks, &b, K_FOREVER); + if (verifyRetValue(RC_OK, retValue)) { + TC_PRINT("%s: k_mem_slab_alloc OK, block allocated at %p\n", + __func__, b); + } else { + TC_ERROR("Failed k_mem_slab_alloc, retValue %d\n", retValue); + tcRC = TC_FAIL; + goto exitTest; /* terminate test */ + } + + /* Wait for HelperTask 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)); + +exitTest: + + TC_END_RESULT(tcRC); + TC_END_REPORT(tcRC); +} /* RegressionTask */ + +K_THREAD_DEFINE(HELPERTASK, STACKSIZE, HelperTask, NULL, NULL, NULL, + 7, 0, K_NO_WAIT); + +K_THREAD_DEFINE(REGRESSTASK, STACKSIZE, RegressionTask, NULL, NULL, NULL, + 5, 0, K_NO_WAIT); diff --git a/tests/kernel/mem_slab/testcase.ini b/tests/kernel/mem_slab/testcase.ini new file mode 100644 index 00000000000..4ff0ab2de22 --- /dev/null +++ b/tests/kernel/mem_slab/testcase.ini @@ -0,0 +1,3 @@ +[test] +tags = bat_commit core +