| /* |
| * Copyright (c) 2016 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /** |
| * @addtogroup t_mpool |
| * @{ |
| * @defgroup t_mpool_api test_mpool_api |
| * @brief TestPurpose: verify memory pool APIs. |
| * @details All TESTPOINTs extracted from kernel-doc comments in <kernel.h> |
| * - API coverage |
| * -# K_MEM_POOL_DEFINE |
| * -# k_mem_pool_alloc |
| * -# k_mem_pool_free |
| * -# k_mem_pool_defrag |
| * @} |
| */ |
| |
| #include <ztest.h> |
| #include "test_mpool.h" |
| |
| /** TESTPOINT: Statically define and initialize a memory pool*/ |
| K_MEM_POOL_DEFINE(kmpool, BLK_SIZE_MIN, BLK_SIZE_MAX, BLK_NUM_MAX, BLK_ALIGN); |
| |
| void tmpool_alloc_free(void *data) |
| { |
| ARG_UNUSED(data); |
| struct k_mem_block block[BLK_NUM_MIN]; |
| |
| for (int i = 0; i < BLK_NUM_MIN; i++) { |
| /** |
| * TESTPOINT: This routine allocates a memory block from a |
| * memory pool. |
| */ |
| /** |
| * TESTPOINT: @retval 0 Memory allocated. The @a data field of |
| * the block descriptor is set to the starting address of the |
| * memory block. |
| */ |
| assert_true(k_mem_pool_alloc(&kmpool, &block[i], BLK_SIZE_MIN, |
| K_NO_WAIT) == 0, NULL); |
| assert_not_null(block[i].data, NULL); |
| } |
| |
| for (int i = 0; i < BLK_NUM_MIN; i++) { |
| /** |
| * TESTPOINT: This routine releases a previously allocated |
| * memory block back to its memory pool. |
| */ |
| k_mem_pool_free(&block[i]); |
| block[i].data = NULL; |
| } |
| |
| /** |
| * TESTPOINT: The memory pool's buffer contains @a n_max blocks that are |
| * @a max_size bytes long. |
| */ |
| for (int i = 0; i < BLK_NUM_MAX; i++) { |
| assert_true(k_mem_pool_alloc(&kmpool, &block[i], BLK_SIZE_MAX, |
| K_NO_WAIT) == 0, NULL); |
| assert_not_null(block[i].data, NULL); |
| } |
| |
| for (int i = 0; i < BLK_NUM_MAX; i++) { |
| k_mem_pool_free(&block[i]); |
| block[i].data = NULL; |
| } |
| } |
| |
| /*test cases*/ |
| void test_mpool_alloc_free_thread(void) |
| { |
| tmpool_alloc_free(NULL); |
| } |
| |
| void test_mpool_alloc_size(void) |
| { |
| struct k_mem_block block[BLK_NUM_MIN]; |
| size_t size = BLK_SIZE_MAX; |
| int i = 0; |
| |
| /**TESTPOINT: The memory pool allows blocks to be repeatedly partitioned |
| * into quarters, down to blocks of @a min_size bytes long. |
| */ |
| while (size >= BLK_SIZE_MIN) { |
| assert_true(k_mem_pool_alloc(&kmpool, &block[i], size, |
| K_NO_WAIT) == 0, NULL); |
| assert_not_null(block[i].data, NULL); |
| assert_true((uint32_t)(block[i].data) % BLK_ALIGN == 0, NULL); |
| i++; |
| size = size >> 2; |
| } |
| while (i--) { |
| k_mem_pool_free(&block[i]); |
| block[i].data = NULL; |
| } |
| |
| i = 0; |
| size = BLK_SIZE_MIN; |
| /**TESTPOINT: To ensure that all blocks in the buffer are similarly |
| * aligned to this boundary, min_size must also be a multiple of align. |
| */ |
| while (size <= BLK_SIZE_MAX) { |
| assert_true(k_mem_pool_alloc(&kmpool, &block[i], size, |
| K_NO_WAIT) == 0, NULL); |
| assert_not_null(block[i].data, NULL); |
| assert_true((uint32_t)(block[i].data) % BLK_ALIGN == 0, NULL); |
| i++; |
| size = size << 2; |
| } |
| while (i--) { |
| k_mem_pool_free(&block[i]); |
| block[i].data = NULL; |
| } |
| } |
| |
| void test_mpool_alloc_timeout(void) |
| { |
| struct k_mem_block block[BLK_NUM_MIN], fblock; |
| int64_t tms; |
| |
| for (int i = 0; i < BLK_NUM_MIN; i++) { |
| assert_equal(k_mem_pool_alloc(&kmpool, &block[i], BLK_SIZE_MIN, |
| K_NO_WAIT), 0, NULL); |
| } |
| |
| /** TESTPOINT: Use K_NO_WAIT to return without waiting*/ |
| /** TESTPOINT: @retval -ENOMEM Returned without waiting*/ |
| assert_equal(k_mem_pool_alloc(&kmpool, &fblock, BLK_SIZE_MIN, |
| K_NO_WAIT), -ENOMEM, NULL); |
| /** TESTPOINT: @retval -EAGAIN Waiting period timed out*/ |
| tms = k_uptime_get(); |
| assert_equal(k_mem_pool_alloc(&kmpool, &fblock, BLK_SIZE_MIN, TIMEOUT), |
| -EAGAIN, NULL); |
| /** |
| * TESTPOINT: Maximum time to wait for operation to complete (in |
| * milliseconds) |
| */ |
| assert_true(k_uptime_delta(&tms) >= TIMEOUT, NULL); |
| |
| for (int i = 0; i < BLK_NUM_MIN; i++) { |
| k_mem_pool_free(&block[i]); |
| block[i].data = NULL; |
| } |
| } |
| |
| void test_mpool_defrag(void) |
| { |
| struct k_mem_block block[BLK_NUM_MIN]; |
| |
| /*fragment the memory pool into small blocks*/ |
| for (int i = 0; i < BLK_NUM_MIN; i++) { |
| assert_true(k_mem_pool_alloc(&kmpool, &block[i], BLK_SIZE_MIN, |
| K_NO_WAIT) == 0, NULL); |
| } |
| /*free the small blocks in the 1st half of the pool*/ |
| for (int i = 0; i < (BLK_NUM_MIN >> 1); i++) { |
| k_mem_pool_free(&block[i]); |
| } |
| /*request a big block, the pool has "adjacent free blocks" to merge*/ |
| assert_true(k_mem_pool_alloc(&kmpool, &block[0], BLK_SIZE_MAX, |
| K_FOREVER) == 0, NULL); |
| /*free the small blocks in the 2nd half of the pool*/ |
| for (int i = (BLK_NUM_MIN >> 1); i < BLK_NUM_MIN; i++) { |
| k_mem_pool_free(&block[i]); |
| } |
| /** |
| * TESTPOINT: This routine instructs a memory pool to concatenate unused |
| * memory blocks into larger blocks wherever possible. |
| */ |
| /*do manual de-fragment*/ |
| k_mem_pool_defrag(&kmpool); |
| /*request a big block, the pool is de-fragmented*/ |
| assert_true(k_mem_pool_alloc(&kmpool, &block[1], BLK_SIZE_MAX, |
| K_NO_WAIT) == 0, NULL); |
| /*free the big blocks*/ |
| for (int i = 0; i < BLK_NUM_MAX; i++) { |
| k_mem_pool_free(&block[i]); |
| } |
| } |