Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | /* * 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(memory_slab, ztest_unit_test(test_mslab)); ztest_run_test_suite(memory_slab); } |