Linux Audio

Check our new training course

Loading...
/* 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 */