blob: 0c8bdbc0c7be21428eedcf45ca1c42851e4562ac [file] [log] [blame]
/* map.c - test microkernel memory map 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 microkernel memory map APIs
*
* This module tests the following map routines:
*
* task_mem_map_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 <tc_util.h>
#include <stdbool.h>
#include <zephyr.h>
#define NUMBLOCKS 2 /*
* Number of memory blocks. This number
* has to be aligned with the number in MDEF file
* The minimum number of blocks needed to run the
* test is 2
*/
static int tcRC = TC_PASS; /* test case return code */
int testMapGetAllBlocks(void **P);
int testMapFreeAllBlocks(void **P);
#ifdef TEST_PRIV_MEM_MAPS
DEFINE_MEM_MAP(MAP_LgBlks, 2, 1024);
#endif
/**
*
* @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 map. 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 */
/* Wait for part 1 to complete */
task_sem_take(SEM_REGRESSDONE, TICKS_UNLIMITED);
/* Part 2 of test */
TC_PRINT("Starts %s\n", __func__);
/* Test task_mem_map_alloc */
tcRC = testMapGetAllBlocks(ptr);
if (tcRC == TC_FAIL) {
TC_ERROR("Failed testMapGetAllBlocks function\n");
goto exitTest1; /* terminate test */
}
task_sem_give(SEM_HELPERDONE); /* Indicate part 2 is complete */
/* Wait for part 3 to complete */
task_sem_take(SEM_REGRESSDONE, TICKS_UNLIMITED);
/*
* 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("%s: About to free a memory block\n", __func__);
task_mem_map_free(MAP_LgBlks, &ptr[0]);
task_sem_give(SEM_HELPERDONE);
/* Part 5 of test */
task_sem_take(SEM_REGRESSDONE, TICKS_UNLIMITED);
TC_PRINT("%s: About to free another memory block\n", __func__);
task_mem_map_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++) {
task_mem_map_free(MAP_LgBlks, &ptr[i]);
}
TC_PRINT("%s: freed all blocks allocated by this task\n", __func__);
exitTest1:
TC_END_RESULT(tcRC);
task_sem_give(SEM_HELPERDONE);
} /* HelperTask */
/**
*
* @brief Get all blocks from the memory map
*
* Get all blocks from the memory map. 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:
*
* task_mem_map_alloc(), task_mem_map_used_get()
*
* @param p pointer to pointer of allocated blocks
*
* @return TC_PASS, TC_FAIL
*/
int testMapGetAllBlocks(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 = task_mem_map_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 = task_mem_map_alloc(MAP_LgBlks, &p[i], TICKS_NONE);
if (verifyRetValue(RC_OK, retValue)) {
TC_PRINT(" task_mem_map_alloc OK, p[%d] = %p\n", i, p[i]);
} else {
TC_ERROR("Failed task_mem_map_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 = task_mem_map_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 = task_mem_map_alloc(MAP_LgBlks, &errPtr, TICKS_NONE);
if (verifyRetValue(RC_FAIL, retValue)) {
TC_PRINT(" task_mem_map_alloc RC_FAIL expected as all (%d) blocks are used.\n",
NUMBLOCKS);
} else {
TC_ERROR("Failed task_mem_map_alloc, expect RC_FAIL, got %d\n", retValue);
return TC_FAIL;
}
PRINT_LINE;
return TC_PASS;
} /* testMapGetAllBlocks */
/**
*
* @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:
*
* task_mem_map_free(), task_mem_map_used_get()
*
* @param p pointer to pointer of allocated blocks
*
* @return TC_PASS, TC_FAIL
*/
int testMapFreeAllBlocks(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 = task_mem_map_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 */
task_mem_map_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 = task_mem_map_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;
} /* testMapFreeAllBlocks */
/**
*
* @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 testMapGetAllBlocks() to get all memory blocks from the
* map and calls testMapFreeAllBlocks() to free all memory blocks. It also
* tries to wait (with and without timeout) for a memory block.
*
* This routine tests the following:
*
* task_mem_map_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 */
/* Part 1 of test */
TC_START("Test Microkernel Memory Maps");
TC_PRINT("Starts %s\n", __func__);
/* Test task_mem_map_alloc */
tcRC = testMapGetAllBlocks(ptr);
if (tcRC == TC_FAIL) {
TC_ERROR("Failed testMapGetAllBlocks function\n");
goto exitTest; /* terminate test */
}
printPointers(ptr);
/* Test task_mem_map_free */
tcRC = testMapFreeAllBlocks(ptr);
if (tcRC == TC_FAIL) {
TC_ERROR("Failed testMapFreeAllBlocks function\n");
goto exitTest; /* terminate test */
}
printPointers(ptr);
task_sem_give(SEM_REGRESSDONE); /* Allow HelperTask to run */
/* Wait for HelperTask to finish */
task_sem_take(SEM_HELPERDONE, TICKS_UNLIMITED);
/*
* 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.
*/
retValue = task_mem_map_alloc(MAP_LgBlks, &b, 2);
if (verifyRetValue(RC_TIME, retValue)) {
TC_PRINT("%s: task_mem_map_alloc timeout expected\n", __func__);
} else {
TC_ERROR("Failed task_mem_map_alloc, retValue %d\n", retValue);
tcRC = TC_FAIL;
goto exitTest; /* terminate test */
}
TC_PRINT("%s: start to wait for block\n", __func__);
task_sem_give(SEM_REGRESSDONE); /* Allow HelperTask to run part 4 */
retValue = task_mem_map_alloc(MAP_LgBlks, &b, 5);
if (verifyRetValue(RC_OK, retValue)) {
TC_PRINT("%s: task_mem_map_alloc OK, block allocated at %p\n",
__func__, b);
} else {
TC_ERROR("Failed task_mem_map_alloc, retValue %d\n", retValue);
tcRC = TC_FAIL;
goto exitTest; /* terminate test */
}
/* Wait for HelperTask to complete */
task_sem_take(SEM_HELPERDONE, TICKS_UNLIMITED);
TC_PRINT("%s: start to wait for block\n", __func__);
task_sem_give(SEM_REGRESSDONE); /* Allow HelperTask to run part 5 */
retValue = task_mem_map_alloc(MAP_LgBlks, &b, TICKS_UNLIMITED);
if (verifyRetValue(RC_OK, retValue)) {
TC_PRINT("%s: task_mem_map_alloc OK, block allocated at %p\n",
__func__, b);
} else {
TC_ERROR("Failed task_mem_map_alloc, retValue %d\n", retValue);
tcRC = TC_FAIL;
goto exitTest; /* terminate test */
}
/* Wait for HelperTask to complete */
task_sem_take(SEM_HELPERDONE, TICKS_UNLIMITED);
/* Free memory block */
TC_PRINT("%s: Used %d block\n", __func__, task_mem_map_used_get(MAP_LgBlks));
task_mem_map_free(MAP_LgBlks, &b);
TC_PRINT("%s: 1 block freed, used %d block\n",
__func__, task_mem_map_used_get(MAP_LgBlks));
exitTest:
TC_END_RESULT(tcRC);
TC_END_REPORT(tcRC);
} /* RegressionTask */