mirror of https://github.com/rusefi/ChibiOS.git
Improved RT and NIL test suite.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10614 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
parent
fb355909fa
commit
3b3afb7d55
|
@ -1,52 +1,52 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.cdt.debug.gdbjtag.launchConfigurationType">
|
||||
<stringAttribute key="bad_container_name" value="\RT-STM32F091RC-NUCLEO64\debug"/>
|
||||
<intAttribute key="org.eclipse.cdt.debug.gdbjtag.core.delay" value="1"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.doHalt" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.doReset" value="true"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.imageFileName" value=""/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.imageOffset" value=""/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.initCommands" value="set remotetimeout 20 monitor reset init monitor sleep 50 "/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.ipAddress" value="localhost"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.jtagDevice" value="Generic TCP/IP"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.loadImage" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.loadSymbols" value="true"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.pcRegister" value=""/>
|
||||
<intAttribute key="org.eclipse.cdt.debug.gdbjtag.core.portNumber" value="3333"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.runCommands" value=""/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setPcRegister" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setResume" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setStopAt" value="true"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.stopAt" value="main"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.symbolsFileName" value=""/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.symbolsOffset" value=""/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useFileForImage" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useFileForSymbols" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useProjBinaryForImage" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useProjBinaryForSymbols" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useRemoteTarget" value="true"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.mi.core.DEBUG_NAME" value="arm-none-eabi-gdb"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.mi.core.commandFactory" value="Standard"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.mi.core.protocol" value="mi"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.mi.core.verboseMode" value="false"/>
|
||||
<stringAttribute key="org.eclipse.cdt.dsf.gdb.DEBUG_NAME" value="arm-none-eabi-gdb"/>
|
||||
<intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="2"/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_REGISTER_GROUPS" value=""/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.FORMAT" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?><contentList/>"/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.GLOBAL_VARIABLES" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <globalVariableList/> "/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.MEMORY_BLOCKS" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <memoryBlockExpressionList/> "/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="./build/ch.elf"/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="RT-STM32F091RC-NUCLEO64"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_AUTO_ATTR" value="true"/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value="0.1984968159"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/RT-STM32F091RC-NUCLEO64"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="4"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
||||
</listAttribute>
|
||||
</launchConfiguration>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.cdt.debug.gdbjtag.launchConfigurationType">
|
||||
<stringAttribute key="bad_container_name" value="\RT-STM32F091RC-NUCLEO64\debug"/>
|
||||
<intAttribute key="org.eclipse.cdt.debug.gdbjtag.core.delay" value="1"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.doHalt" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.doReset" value="true"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.imageFileName" value=""/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.imageOffset" value=""/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.initCommands" value="set remotetimeout 20 monitor reset init monitor sleep 50 "/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.ipAddress" value="localhost"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.jtagDevice" value="Generic TCP/IP"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.loadImage" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.loadSymbols" value="true"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.pcRegister" value=""/>
|
||||
<intAttribute key="org.eclipse.cdt.debug.gdbjtag.core.portNumber" value="3333"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.runCommands" value=""/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setPcRegister" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setResume" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setStopAt" value="true"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.stopAt" value="main"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.symbolsFileName" value=""/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.symbolsOffset" value=""/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useFileForImage" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useFileForSymbols" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useProjBinaryForImage" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useProjBinaryForSymbols" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useRemoteTarget" value="true"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.mi.core.DEBUG_NAME" value="arm-none-eabi-gdb"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.mi.core.commandFactory" value="Standard"/>
|
||||
<stringAttribute key="org.eclipse.cdt.debug.mi.core.protocol" value="mi"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.debug.mi.core.verboseMode" value="false"/>
|
||||
<stringAttribute key="org.eclipse.cdt.dsf.gdb.DEBUG_NAME" value="arm-none-eabi-gdb"/>
|
||||
<intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="2"/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_REGISTER_GROUPS" value=""/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.FORMAT" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?><contentList/>"/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.GLOBAL_VARIABLES" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <globalVariableList/> "/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.MEMORY_BLOCKS" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <memoryBlockExpressionList/> "/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="./build/ch.elf"/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="RT-STM32F091RC-NUCLEO64"/>
|
||||
<booleanAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_AUTO_ATTR" value="true"/>
|
||||
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value="0.1984968159"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/RT-STM32F091RC-NUCLEO64"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="4"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
||||
</listAttribute>
|
||||
</launchConfiguration>
|
||||
|
|
|
@ -89,6 +89,8 @@
|
|||
*****************************************************************************
|
||||
|
||||
*** Next ***
|
||||
- NEW: Improved RT and NIL test suite to report version numbers and
|
||||
configuration settings.
|
||||
- NEW: Added a multi-target demo applications for PAL, SPI and USB-CDC
|
||||
showcasing how to manage a project with multiple target boards/devices
|
||||
and handle portability issues.
|
||||
|
|
|
@ -77,6 +77,156 @@ THD_FUNCTION(test_support, arg) {
|
|||
</global_code>
|
||||
</global_data_and_code>
|
||||
<sequences>
|
||||
<sequence>
|
||||
<type index="0">
|
||||
<value>Internal Tests</value>
|
||||
</type>
|
||||
<brief>
|
||||
<value>Information.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>This sequence reports configuration and version information about the NIL kernel.</value>
|
||||
</description>
|
||||
<condition>
|
||||
<value />
|
||||
</condition>
|
||||
<shared_code>
|
||||
<value><![CDATA[#include "ch.h"]]></value>
|
||||
</shared_code>
|
||||
<cases>
|
||||
<case>
|
||||
<brief>
|
||||
<value>Kernel Info.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>The version numbers are reported.</value>
|
||||
</description>
|
||||
<condition>
|
||||
<value />
|
||||
</condition>
|
||||
<various_code>
|
||||
<setup_code>
|
||||
<value />
|
||||
</setup_code>
|
||||
<teardown_code>
|
||||
<value />
|
||||
</teardown_code>
|
||||
<local_variables>
|
||||
<value />
|
||||
</local_variables>
|
||||
</various_code>
|
||||
<steps>
|
||||
<step>
|
||||
<description>
|
||||
<value>Prints the version string.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[test_println("*** Product: ChibiOS/NIL");
|
||||
test_print("*** Stable Flag: ");
|
||||
test_printn(CH_KERNEL_STABLE);
|
||||
test_println("");
|
||||
test_print("*** Version String: ");
|
||||
test_println(CH_KERNEL_VERSION);
|
||||
test_print("*** Major Number: ");
|
||||
test_printn(CH_KERNEL_MAJOR);
|
||||
test_println("");
|
||||
test_print("*** Minor Number: ");
|
||||
test_printn(CH_KERNEL_MINOR);
|
||||
test_println("");
|
||||
test_print("*** Patch Number: ");
|
||||
test_printn(CH_KERNEL_PATCH);
|
||||
test_println("");]]></value>
|
||||
</code>
|
||||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
<case>
|
||||
<brief>
|
||||
<value>Kernel Settings.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>The static kernel settings are reported.</value>
|
||||
</description>
|
||||
<condition>
|
||||
<value />
|
||||
</condition>
|
||||
<various_code>
|
||||
<setup_code>
|
||||
<value />
|
||||
</setup_code>
|
||||
<teardown_code>
|
||||
<value />
|
||||
</teardown_code>
|
||||
<local_variables>
|
||||
<value />
|
||||
</local_variables>
|
||||
</various_code>
|
||||
<steps>
|
||||
<step>
|
||||
<description>
|
||||
<value>Prints the configuration options settings.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[test_print("*** CH_CFG_NUM_THREADS: ");
|
||||
test_printn(CH_CFG_NUM_THREADS);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_ST_RESOLUTION: ");
|
||||
test_printn(CH_CFG_ST_RESOLUTION);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_ST_FREQUENCY: ");
|
||||
test_printn(CH_CFG_ST_FREQUENCY);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_ST_TIMEDELTA: ");
|
||||
test_printn(CH_CFG_ST_TIMEDELTA);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_SEMAPHORES: ");
|
||||
test_printn(CH_CFG_USE_SEMAPHORES);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MUTEXES: ");
|
||||
test_printn(CH_CFG_USE_MUTEXES);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_EVENTS: ");
|
||||
test_printn(CH_CFG_USE_EVENTS);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MAILBOXES: ");
|
||||
test_printn(CH_CFG_USE_MAILBOXES);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MEMCORE: ");
|
||||
test_printn(CH_CFG_USE_MEMCORE);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_HEAP: ");
|
||||
test_printn(CH_CFG_USE_HEAP);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MEMPOOLS: ");
|
||||
test_printn(CH_CFG_USE_MEMPOOLS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_STATISTICS: ");
|
||||
test_printn(CH_DBG_STATISTICS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_SYSTEM_STATE_CHECK: ");
|
||||
test_printn(CH_DBG_SYSTEM_STATE_CHECK);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_ENABLE_CHECKS: ");
|
||||
test_printn(CH_DBG_ENABLE_CHECKS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_ENABLE_ASSERTS: ");
|
||||
test_printn(CH_DBG_ENABLE_ASSERTS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_ENABLE_STACK_CHECK: ");
|
||||
test_printn(CH_DBG_ENABLE_STACK_CHECK);
|
||||
test_println("");]]></value>
|
||||
</code>
|
||||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
</cases>
|
||||
</sequence>
|
||||
<sequence>
|
||||
<type index="0">
|
||||
<value>Internal Tests</value>
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* - @subpage test_sequence_004
|
||||
* - @subpage test_sequence_005
|
||||
* - @subpage test_sequence_006
|
||||
* - @subpage test_sequence_007
|
||||
* .
|
||||
*/
|
||||
|
||||
|
@ -50,18 +51,19 @@
|
|||
*/
|
||||
const testcase_t * const *test_suite[] = {
|
||||
test_sequence_001,
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
test_sequence_002,
|
||||
#endif
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
test_sequence_003,
|
||||
#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
|
||||
test_sequence_004,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
||||
test_sequence_004,
|
||||
#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
|
||||
test_sequence_005,
|
||||
#endif
|
||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
||||
test_sequence_006,
|
||||
#endif
|
||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
test_sequence_007,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "test_sequence_004.h"
|
||||
#include "test_sequence_005.h"
|
||||
#include "test_sequence_006.h"
|
||||
#include "test_sequence_007.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
|
|
|
@ -22,13 +22,13 @@
|
|||
* @file test_sequence_001.c
|
||||
* @brief Test Sequence 001 code.
|
||||
*
|
||||
* @page test_sequence_001 [1] Threads Functionality
|
||||
* @page test_sequence_001 [1] Information
|
||||
*
|
||||
* File: @ref test_sequence_001.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/NIL functionalities related to
|
||||
* threading.
|
||||
* This sequence reports configuration and version information about
|
||||
* the NIL kernel.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_001_001
|
||||
|
@ -47,123 +47,115 @@
|
|||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_001_001 [1.1] System Tick Counter functionality
|
||||
* @page test_001_001 [1.1] Kernel Info
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The functionality of the API @p chVTGetSystemTimeX() is tested.
|
||||
* The version numbers are reported.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [1.1.1] A System Tick Counter increment is expected, the test
|
||||
* simply hangs if it does not happen.
|
||||
* - [1.1.1] Prints the version string.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_001_001_execute(void) {
|
||||
|
||||
/* [1.1.1] A System Tick Counter increment is expected, the test
|
||||
simply hangs if it does not happen.*/
|
||||
/* [1.1.1] Prints the version string.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
systime_t time = chVTGetSystemTimeX();
|
||||
while (time == chVTGetSystemTimeX()) {
|
||||
}
|
||||
test_println("*** Product: ChibiOS/NIL");
|
||||
test_print("*** Stable Flag: ");
|
||||
test_printn(CH_KERNEL_STABLE);
|
||||
test_println("");
|
||||
test_print("*** Version String: ");
|
||||
test_println(CH_KERNEL_VERSION);
|
||||
test_print("*** Major Number: ");
|
||||
test_printn(CH_KERNEL_MAJOR);
|
||||
test_println("");
|
||||
test_print("*** Minor Number: ");
|
||||
test_printn(CH_KERNEL_MINOR);
|
||||
test_println("");
|
||||
test_print("*** Patch Number: ");
|
||||
test_printn(CH_KERNEL_PATCH);
|
||||
test_println("");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_001_001 = {
|
||||
"System Tick Counter functionality",
|
||||
"Kernel Info",
|
||||
NULL,
|
||||
NULL,
|
||||
test_001_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_001_002 [1.2] Thread Sleep functionality
|
||||
* @page test_001_002 [1.2] Kernel Settings
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The functionality of @p chThdSleep() and derivatives is tested.
|
||||
* The static kernel settings are reported.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [1.2.1] The current system time is read then a sleep is performed
|
||||
* for 100 system ticks and on exit the system time is verified
|
||||
* again.
|
||||
* - [1.2.2] The current system time is read then a sleep is performed
|
||||
* for 100000 microseconds and on exit the system time is verified
|
||||
* again.
|
||||
* - [1.2.3] The current system time is read then a sleep is performed
|
||||
* for 100 milliseconds and on exit the system time is verified
|
||||
* again.
|
||||
* - [1.2.4] The current system time is read then a sleep is performed
|
||||
* for 1 second and on exit the system time is verified again.
|
||||
* - [1.2.5] Function chThdSleepUntil() is tested with a timeline of
|
||||
* "now" + 100 ticks.
|
||||
* - [1.2.1] Prints the configuration options settings.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_001_002_execute(void) {
|
||||
systime_t time;
|
||||
|
||||
/* [1.2.1] The current system time is read then a sleep is performed
|
||||
for 100 system ticks and on exit the system time is verified
|
||||
again.*/
|
||||
/* [1.2.1] Prints the configuration options settings.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleep(100);
|
||||
test_assert_time_window(time + 100,
|
||||
time + 100 + 1,
|
||||
"out of time window");
|
||||
}
|
||||
|
||||
/* [1.2.2] The current system time is read then a sleep is performed
|
||||
for 100000 microseconds and on exit the system time is verified
|
||||
again.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepMicroseconds(100000);
|
||||
test_assert_time_window(time + US2ST(100000),
|
||||
time + US2ST(100000) + 1,
|
||||
"out of time window");
|
||||
}
|
||||
|
||||
/* [1.2.3] The current system time is read then a sleep is performed
|
||||
for 100 milliseconds and on exit the system time is verified
|
||||
again.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepMilliseconds(100);
|
||||
test_assert_time_window(time + MS2ST(100),
|
||||
time + MS2ST(100) + 1,
|
||||
"out of time window");
|
||||
}
|
||||
|
||||
/* [1.2.4] The current system time is read then a sleep is performed
|
||||
for 1 second and on exit the system time is verified again.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepSeconds(1);
|
||||
test_assert_time_window(time + S2ST(1),
|
||||
time + S2ST(1) + 1,
|
||||
"out of time window");
|
||||
}
|
||||
|
||||
/* [1.2.5] Function chThdSleepUntil() is tested with a timeline of
|
||||
"now" + 100 ticks.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepUntil(time + 100);
|
||||
test_assert_time_window(time + 100,
|
||||
time + 100 + 1,
|
||||
"out of time window");
|
||||
test_print("*** CH_CFG_NUM_THREADS: ");
|
||||
test_printn(CH_CFG_NUM_THREADS);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_ST_RESOLUTION: ");
|
||||
test_printn(CH_CFG_ST_RESOLUTION);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_ST_FREQUENCY: ");
|
||||
test_printn(CH_CFG_ST_FREQUENCY);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_ST_TIMEDELTA: ");
|
||||
test_printn(CH_CFG_ST_TIMEDELTA);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_SEMAPHORES: ");
|
||||
test_printn(CH_CFG_USE_SEMAPHORES);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MUTEXES: ");
|
||||
test_printn(CH_CFG_USE_MUTEXES);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_EVENTS: ");
|
||||
test_printn(CH_CFG_USE_EVENTS);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MAILBOXES: ");
|
||||
test_printn(CH_CFG_USE_MAILBOXES);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MEMCORE: ");
|
||||
test_printn(CH_CFG_USE_MEMCORE);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_HEAP: ");
|
||||
test_printn(CH_CFG_USE_HEAP);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MEMPOOLS: ");
|
||||
test_printn(CH_CFG_USE_MEMPOOLS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_STATISTICS: ");
|
||||
test_printn(CH_DBG_STATISTICS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_SYSTEM_STATE_CHECK: ");
|
||||
test_printn(CH_DBG_SYSTEM_STATE_CHECK);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_ENABLE_CHECKS: ");
|
||||
test_printn(CH_DBG_ENABLE_CHECKS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_ENABLE_ASSERTS: ");
|
||||
test_printn(CH_DBG_ENABLE_ASSERTS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_ENABLE_STACK_CHECK: ");
|
||||
test_printn(CH_DBG_ENABLE_STACK_CHECK);
|
||||
test_println("");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_001_002 = {
|
||||
"Thread Sleep functionality",
|
||||
"Kernel Settings",
|
||||
NULL,
|
||||
NULL,
|
||||
test_001_002_execute
|
||||
|
@ -174,7 +166,7 @@ static const testcase_t test_001_002 = {
|
|||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Threads Functionality.
|
||||
* @brief Information.
|
||||
*/
|
||||
const testcase_t * const test_sequence_001[] = {
|
||||
&test_001_001,
|
||||
|
|
|
@ -22,238 +22,162 @@
|
|||
* @file test_sequence_002.c
|
||||
* @brief Test Sequence 002 code.
|
||||
*
|
||||
* @page test_sequence_002 [2] Semaphores
|
||||
* @page test_sequence_002 [2] Threads Functionality
|
||||
*
|
||||
* File: @ref test_sequence_002.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/NIL functionalities related to
|
||||
* counter semaphores.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
* threading.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_002_001
|
||||
* - @subpage test_002_002
|
||||
* - @subpage test_002_003
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
static semaphore_t sem1;
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_002_001 [2.1] Semaphore primitives, no state change
|
||||
* @page test_002_001 [2.1] System Tick Counter functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Wait, Signal and Reset primitives are tested. The testing thread
|
||||
* does not trigger a state change.
|
||||
* The functionality of the API @p chVTGetSystemTimeX() is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [2.1.1] The function chSemWait() is invoked, after return the
|
||||
* counter and the returned message are tested.
|
||||
* - [2.1.2] The function chSemSignal() is invoked, after return the
|
||||
* counter is tested.
|
||||
* - [2.1.3] The function chSemReset() is invoked, after return the
|
||||
* counter is tested.
|
||||
* - [2.1.1] A System Tick Counter increment is expected, the test
|
||||
* simply hangs if it does not happen.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_002_001_setup(void) {
|
||||
chSemObjectInit(&sem1, 1);
|
||||
}
|
||||
|
||||
static void test_002_001_teardown(void) {
|
||||
chSemReset(&sem1, 0);
|
||||
}
|
||||
|
||||
static void test_002_001_execute(void) {
|
||||
|
||||
/* [2.1.1] The function chSemWait() is invoked, after return the
|
||||
counter and the returned message are tested.*/
|
||||
/* [2.1.1] A System Tick Counter increment is expected, the test
|
||||
simply hangs if it does not happen.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
msg_t msg;
|
||||
|
||||
msg = chSemWait(&sem1);
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_OK == msg, "wrong returned message");
|
||||
}
|
||||
|
||||
/* [2.1.2] The function chSemSignal() is invoked, after return the
|
||||
counter is tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chSemSignal(&sem1);
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 1, "wrong counter value");
|
||||
}
|
||||
|
||||
/* [2.1.3] The function chSemReset() is invoked, after return the
|
||||
counter is tested.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chSemReset(&sem1, 2);
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value");
|
||||
systime_t time = chVTGetSystemTimeX();
|
||||
while (time == chVTGetSystemTimeX()) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_002_001 = {
|
||||
"Semaphore primitives, no state change",
|
||||
test_002_001_setup,
|
||||
test_002_001_teardown,
|
||||
"System Tick Counter functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
test_002_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_002_002 [2.2] Semaphore primitives, with state change
|
||||
* @page test_002_002 [2.2] Thread Sleep functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Wait, Signal and Reset primitives are tested. The testing thread
|
||||
* triggers a state change.
|
||||
* The functionality of @p chThdSleep() and derivatives is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [2.2.1] The function chSemWait() is invoked, after return the
|
||||
* counter and the returned message are tested. The semaphore is
|
||||
* signaled by another thread.
|
||||
* - [2.2.2] The function chSemWait() is invoked, after return the
|
||||
* counter and the returned message are tested. The semaphore is
|
||||
* reset by another thread.
|
||||
* - [2.2.1] The current system time is read then a sleep is performed
|
||||
* for 100 system ticks and on exit the system time is verified
|
||||
* again.
|
||||
* - [2.2.2] The current system time is read then a sleep is performed
|
||||
* for 100000 microseconds and on exit the system time is verified
|
||||
* again.
|
||||
* - [2.2.3] The current system time is read then a sleep is performed
|
||||
* for 100 milliseconds and on exit the system time is verified
|
||||
* again.
|
||||
* - [2.2.4] The current system time is read then a sleep is performed
|
||||
* for 1 second and on exit the system time is verified again.
|
||||
* - [2.2.5] Function chThdSleepUntil() is tested with a timeline of
|
||||
* "now" + 100 ticks.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_002_002_setup(void) {
|
||||
chSemObjectInit(&gsem1, 0);
|
||||
}
|
||||
|
||||
static void test_002_002_teardown(void) {
|
||||
chSemReset(&gsem1, 0);
|
||||
}
|
||||
|
||||
static void test_002_002_execute(void) {
|
||||
systime_t time;
|
||||
|
||||
/* [2.2.1] The function chSemWait() is invoked, after return the
|
||||
counter and the returned message are tested. The semaphore is
|
||||
signaled by another thread.*/
|
||||
/* [2.2.1] The current system time is read then a sleep is performed
|
||||
for 100 system ticks and on exit the system time is verified
|
||||
again.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
msg_t msg;
|
||||
|
||||
msg = chSemWait(&gsem1);
|
||||
test_assert_lock(chSemGetCounterI(&gsem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_OK == msg, "wrong returned message");
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleep(100);
|
||||
test_assert_time_window(time + 100,
|
||||
time + 100 + 1,
|
||||
"out of time window");
|
||||
}
|
||||
|
||||
/* [2.2.2] The function chSemWait() is invoked, after return the
|
||||
counter and the returned message are tested. The semaphore is
|
||||
reset by another thread.*/
|
||||
/* [2.2.2] The current system time is read then a sleep is performed
|
||||
for 100000 microseconds and on exit the system time is verified
|
||||
again.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
msg_t msg;
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepMicroseconds(100000);
|
||||
test_assert_time_window(time + US2ST(100000),
|
||||
time + US2ST(100000) + 1,
|
||||
"out of time window");
|
||||
}
|
||||
|
||||
msg = chSemWait(&gsem2);
|
||||
test_assert_lock(chSemGetCounterI(&gsem2) == 0,"wrong counter value");
|
||||
test_assert(MSG_RESET == msg, "wrong returned message");
|
||||
/* [2.2.3] The current system time is read then a sleep is performed
|
||||
for 100 milliseconds and on exit the system time is verified
|
||||
again.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepMilliseconds(100);
|
||||
test_assert_time_window(time + MS2ST(100),
|
||||
time + MS2ST(100) + 1,
|
||||
"out of time window");
|
||||
}
|
||||
|
||||
/* [2.2.4] The current system time is read then a sleep is performed
|
||||
for 1 second and on exit the system time is verified again.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepSeconds(1);
|
||||
test_assert_time_window(time + S2ST(1),
|
||||
time + S2ST(1) + 1,
|
||||
"out of time window");
|
||||
}
|
||||
|
||||
/* [2.2.5] Function chThdSleepUntil() is tested with a timeline of
|
||||
"now" + 100 ticks.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepUntil(time + 100);
|
||||
test_assert_time_window(time + 100,
|
||||
time + 100 + 1,
|
||||
"out of time window");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_002_002 = {
|
||||
"Semaphore primitives, with state change",
|
||||
test_002_002_setup,
|
||||
test_002_002_teardown,
|
||||
"Thread Sleep functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
test_002_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_002_003 [2.3] Semaphores timeout
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Timeout on semaphores is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [2.3.1] The function chSemWaitTimeout() is invoked a first time,
|
||||
* after return the system time, the counter and the returned message
|
||||
* are tested.
|
||||
* - [2.3.2] The function chSemWaitTimeout() is invoked again, after
|
||||
* return the system time, the counter and the returned message are
|
||||
* tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_002_003_setup(void) {
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static void test_002_003_teardown(void) {
|
||||
chSemReset(&sem1, 0);
|
||||
}
|
||||
|
||||
static void test_002_003_execute(void) {
|
||||
systime_t time;
|
||||
msg_t msg;
|
||||
|
||||
/* [2.3.1] The function chSemWaitTimeout() is invoked a first time,
|
||||
after return the system time, the counter and the returned message
|
||||
are tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chSemWaitTimeout(&sem1, MS2ST(1000));
|
||||
test_assert_time_window(time + MS2ST(1000),
|
||||
time + MS2ST(1000) + 1,
|
||||
"out of time window");
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong timeout message");
|
||||
}
|
||||
|
||||
/* [2.3.2] The function chSemWaitTimeout() is invoked again, after
|
||||
return the system time, the counter and the returned message are
|
||||
tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chSemWaitTimeout(&sem1, MS2ST(1000));
|
||||
test_assert_time_window(time + MS2ST(1000),
|
||||
time + MS2ST(1000) + 1,
|
||||
"out of time window");
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong timeout message");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_002_003 = {
|
||||
"Semaphores timeout",
|
||||
test_002_003_setup,
|
||||
test_002_003_teardown,
|
||||
test_002_003_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Semaphores.
|
||||
* @brief Threads Functionality.
|
||||
*/
|
||||
const testcase_t * const test_sequence_002[] = {
|
||||
&test_002_001,
|
||||
&test_002_002,
|
||||
&test_002_003,
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
|
|
@ -22,178 +22,238 @@
|
|||
* @file test_sequence_003.c
|
||||
* @brief Test Sequence 003 code.
|
||||
*
|
||||
* @page test_sequence_003 [3] Suspend/Resume and Event Flags
|
||||
* @page test_sequence_003 [3] Semaphores
|
||||
*
|
||||
* File: @ref test_sequence_003.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/NIL functionalities related to
|
||||
* threads suspend/resume and event flags.
|
||||
* counter semaphores.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_003_001
|
||||
* - @subpage test_003_002
|
||||
* - @subpage test_003_003
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
static thread_reference_t tr1;
|
||||
#include "ch.h"
|
||||
|
||||
static semaphore_t sem1;
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_003_001 [3.1] Suspend and Resume functionality
|
||||
* @page test_003_001 [3.1] Semaphore primitives, no state change
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
|
||||
* tested.
|
||||
* Wait, Signal and Reset primitives are tested. The testing thread
|
||||
* does not trigger a state change.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [3.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
* is remotely resumed with message @p MSG_OK. On return the message
|
||||
* and the state of the reference are tested.
|
||||
* - [3.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
* is not resumed so a timeout must occur. On return the message and
|
||||
* the state of the reference are tested.
|
||||
* - [3.1.1] The function chSemWait() is invoked, after return the
|
||||
* counter and the returned message are tested.
|
||||
* - [3.1.2] The function chSemSignal() is invoked, after return the
|
||||
* counter is tested.
|
||||
* - [3.1.3] The function chSemReset() is invoked, after return the
|
||||
* counter is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_003_001_setup(void) {
|
||||
tr1 = NULL;
|
||||
chSemObjectInit(&sem1, 1);
|
||||
}
|
||||
|
||||
static void test_003_001_teardown(void) {
|
||||
chSemReset(&sem1, 0);
|
||||
}
|
||||
|
||||
static void test_003_001_execute(void) {
|
||||
systime_t time;
|
||||
msg_t msg;
|
||||
|
||||
/* [3.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
is remotely resumed with message @p MSG_OK. On return the message
|
||||
and the state of the reference are tested.*/
|
||||
/* [3.1.1] The function chSemWait() is invoked, after return the
|
||||
counter and the returned message are tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chSysLock();
|
||||
msg = chThdSuspendTimeoutS(>r1, TIME_INFINITE);
|
||||
chSysUnlock();
|
||||
test_assert(NULL == gtr1, "not NULL");
|
||||
test_assert(MSG_OK == msg,"wrong returned message");
|
||||
msg_t msg;
|
||||
|
||||
msg = chSemWait(&sem1);
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_OK == msg, "wrong returned message");
|
||||
}
|
||||
|
||||
/* [3.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
is not resumed so a timeout must occur. On return the message and
|
||||
the state of the reference are tested.*/
|
||||
/* [3.1.2] The function chSemSignal() is invoked, after return the
|
||||
counter is tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chSysLock();
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chThdSuspendTimeoutS(&tr1, MS2ST(1000));
|
||||
chSysUnlock();
|
||||
test_assert_time_window(time + MS2ST(1000),
|
||||
time + MS2ST(1000) + 1,
|
||||
"out of time window");
|
||||
test_assert(NULL == tr1, "not NULL");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong returned message");
|
||||
chSemSignal(&sem1);
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 1, "wrong counter value");
|
||||
}
|
||||
|
||||
/* [3.1.3] The function chSemReset() is invoked, after return the
|
||||
counter is tested.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chSemReset(&sem1, 2);
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_003_001 = {
|
||||
"Suspend and Resume functionality",
|
||||
"Semaphore primitives, no state change",
|
||||
test_003_001_setup,
|
||||
NULL,
|
||||
test_003_001_teardown,
|
||||
test_003_001_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_003_002 [3.2] Events Flags functionality
|
||||
* @page test_003_002 [3.2] Semaphore primitives, with state change
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Event flags functionality is tested.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_EVENTS
|
||||
* .
|
||||
* Wait, Signal and Reset primitives are tested. The testing thread
|
||||
* triggers a state change.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [3.2.1] A set of event flags are set on the current thread then
|
||||
* the function chEvtWaitAnyTimeout() is invoked, the function is
|
||||
* supposed to return immediately because the event flags are already
|
||||
* pending, after return the events mask is tested.
|
||||
* - [3.2.2] The pending event flags mask is cleared then the function
|
||||
* chEvtWaitAnyTimeout() is invoked, after return the events mask is
|
||||
* tested. The thread is signaled by another thread.
|
||||
* - [3.2.3] The function chEvtWaitAnyTimeout() is invoked, no event
|
||||
* can wakeup the thread, the function must return because timeout.
|
||||
* - [3.2.1] The function chSemWait() is invoked, after return the
|
||||
* counter and the returned message are tested. The semaphore is
|
||||
* signaled by another thread.
|
||||
* - [3.2.2] The function chSemWait() is invoked, after return the
|
||||
* counter and the returned message are tested. The semaphore is
|
||||
* reset by another thread.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_003_002_execute(void) {
|
||||
systime_t time;
|
||||
eventmask_t events;
|
||||
static void test_003_002_setup(void) {
|
||||
chSemObjectInit(&gsem1, 0);
|
||||
}
|
||||
|
||||
/* [3.2.1] A set of event flags are set on the current thread then
|
||||
the function chEvtWaitAnyTimeout() is invoked, the function is
|
||||
supposed to return immediately because the event flags are already
|
||||
pending, after return the events mask is tested.*/
|
||||
static void test_003_002_teardown(void) {
|
||||
chSemReset(&gsem1, 0);
|
||||
}
|
||||
|
||||
static void test_003_002_execute(void) {
|
||||
|
||||
/* [3.2.1] The function chSemWait() is invoked, after return the
|
||||
counter and the returned message are tested. The semaphore is
|
||||
signaled by another thread.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chEvtSignal(chThdGetSelfX(), 0x55);
|
||||
events = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000));
|
||||
test_assert((eventmask_t)0 != events, "timed out");
|
||||
test_assert((eventmask_t)0x55 == events, "wrong events mask");
|
||||
msg_t msg;
|
||||
|
||||
msg = chSemWait(&gsem1);
|
||||
test_assert_lock(chSemGetCounterI(&gsem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_OK == msg, "wrong returned message");
|
||||
}
|
||||
|
||||
/* [3.2.2] The pending event flags mask is cleared then the function
|
||||
chEvtWaitAnyTimeout() is invoked, after return the events mask is
|
||||
tested. The thread is signaled by another thread.*/
|
||||
/* [3.2.2] The function chSemWait() is invoked, after return the
|
||||
counter and the returned message are tested. The semaphore is
|
||||
reset by another thread.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdGetSelfX()->epmask = 0;
|
||||
events = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000));
|
||||
test_assert((eventmask_t)0 != events, "timed out");
|
||||
test_assert((eventmask_t)0x55 == events, "wrong events mask");
|
||||
}
|
||||
msg_t msg;
|
||||
|
||||
/* [3.2.3] The function chEvtWaitAnyTimeout() is invoked, no event
|
||||
can wakeup the thread, the function must return because timeout.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
events = chEvtWaitAnyTimeout(0, MS2ST(1000));
|
||||
test_assert_time_window(time + MS2ST(1000),
|
||||
time + MS2ST(1000) + 1,
|
||||
"out of time window");
|
||||
test_assert((eventmask_t)0 == events, "wrong events mask");
|
||||
msg = chSemWait(&gsem2);
|
||||
test_assert_lock(chSemGetCounterI(&gsem2) == 0,"wrong counter value");
|
||||
test_assert(MSG_RESET == msg, "wrong returned message");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_003_002 = {
|
||||
"Events Flags functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
"Semaphore primitives, with state change",
|
||||
test_003_002_setup,
|
||||
test_003_002_teardown,
|
||||
test_003_002_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_EVENTS */
|
||||
|
||||
/**
|
||||
* @page test_003_003 [3.3] Semaphores timeout
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Timeout on semaphores is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [3.3.1] The function chSemWaitTimeout() is invoked a first time,
|
||||
* after return the system time, the counter and the returned message
|
||||
* are tested.
|
||||
* - [3.3.2] The function chSemWaitTimeout() is invoked again, after
|
||||
* return the system time, the counter and the returned message are
|
||||
* tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_003_003_setup(void) {
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static void test_003_003_teardown(void) {
|
||||
chSemReset(&sem1, 0);
|
||||
}
|
||||
|
||||
static void test_003_003_execute(void) {
|
||||
systime_t time;
|
||||
msg_t msg;
|
||||
|
||||
/* [3.3.1] The function chSemWaitTimeout() is invoked a first time,
|
||||
after return the system time, the counter and the returned message
|
||||
are tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chSemWaitTimeout(&sem1, MS2ST(1000));
|
||||
test_assert_time_window(time + MS2ST(1000),
|
||||
time + MS2ST(1000) + 1,
|
||||
"out of time window");
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong timeout message");
|
||||
}
|
||||
|
||||
/* [3.3.2] The function chSemWaitTimeout() is invoked again, after
|
||||
return the system time, the counter and the returned message are
|
||||
tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chSemWaitTimeout(&sem1, MS2ST(1000));
|
||||
test_assert_time_window(time + MS2ST(1000),
|
||||
time + MS2ST(1000) + 1,
|
||||
"out of time window");
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong timeout message");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_003_003 = {
|
||||
"Semaphores timeout",
|
||||
test_003_003_setup,
|
||||
test_003_003_teardown,
|
||||
test_003_003_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Suspend/Resume and Event Flags.
|
||||
* @brief Semaphores.
|
||||
*/
|
||||
const testcase_t * const test_sequence_003[] = {
|
||||
&test_003_001,
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
&test_003_002,
|
||||
#endif
|
||||
&test_003_003,
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
|
|
@ -22,387 +22,178 @@
|
|||
* @file test_sequence_004.c
|
||||
* @brief Test Sequence 004 code.
|
||||
*
|
||||
* @page test_sequence_004 [4] Mailboxes
|
||||
* @page test_sequence_004 [4] Suspend/Resume and Event Flags
|
||||
*
|
||||
* File: @ref test_sequence_004.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/NIL functionalities related to
|
||||
* mailboxes.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_MAILBOXES
|
||||
* .
|
||||
* threads suspend/resume and event flags.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_004_001
|
||||
* - @subpage test_004_002
|
||||
* - @subpage test_004_003
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
#define ALLOWED_DELAY MS2ST(5)
|
||||
#define MB_SIZE 4
|
||||
|
||||
static msg_t mb_buffer[MB_SIZE];
|
||||
static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE);
|
||||
static thread_reference_t tr1;
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_004_001 [4.1] Mailbox normal API, non-blocking tests
|
||||
* @page test_004_001 [4.1] Suspend and Resume functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The mailbox normal API is tested without triggering blocking
|
||||
* conditions.
|
||||
* The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
|
||||
* tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.1.1] Testing the mailbox size.
|
||||
* - [4.1.2] Resetting the mailbox, conditions are checked, no errors
|
||||
* expected.
|
||||
* - [4.1.3] Testing the behavior of API when the mailbox is in reset
|
||||
* state then return in active state.
|
||||
* - [4.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
|
||||
* once, no errors expected.
|
||||
* - [4.1.5] Testing intermediate conditions. Data pointers must be
|
||||
* aligned, semaphore counters are checked.
|
||||
* - [4.1.6] Emptying the mailbox using chMBFetch(), no errors
|
||||
* expected.
|
||||
* - [4.1.7] Posting and then fetching one more message, no errors
|
||||
* expected.
|
||||
* - [4.1.8] Testing final conditions. Data pointers must be aligned to
|
||||
* buffer start, semaphore counters are checked.
|
||||
* - [4.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
* is remotely resumed with message @p MSG_OK. On return the message
|
||||
* and the state of the reference are tested.
|
||||
* - [4.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
* is not resumed so a timeout must occur. On return the message and
|
||||
* the state of the reference are tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_004_001_setup(void) {
|
||||
chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
|
||||
}
|
||||
|
||||
static void test_004_001_teardown(void) {
|
||||
chMBReset(&mb1);
|
||||
tr1 = NULL;
|
||||
}
|
||||
|
||||
static void test_004_001_execute(void) {
|
||||
msg_t msg1, msg2;
|
||||
unsigned i;
|
||||
systime_t time;
|
||||
msg_t msg;
|
||||
|
||||
/* [4.1.1] Testing the mailbox size.*/
|
||||
/* [4.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
is remotely resumed with message @p MSG_OK. On return the message
|
||||
and the state of the reference are tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
|
||||
chSysLock();
|
||||
msg = chThdSuspendTimeoutS(>r1, TIME_INFINITE);
|
||||
chSysUnlock();
|
||||
test_assert(NULL == gtr1, "not NULL");
|
||||
test_assert(MSG_OK == msg,"wrong returned message");
|
||||
}
|
||||
|
||||
/* [4.1.2] Resetting the mailbox, conditions are checked, no errors
|
||||
expected.*/
|
||||
/* [4.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
is not resumed so a timeout must occur. On return the message and
|
||||
the state of the reference are tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chMBReset(&mb1);
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
}
|
||||
|
||||
/* [4.1.3] Testing the behavior of API when the mailbox is in reset
|
||||
state then return in active state.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
msg1 = chMBPost(&mb1, (msg_t)0, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_RESET, "not in reset state");
|
||||
msg1 = chMBPostAhead(&mb1, (msg_t)0, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_RESET, "not in reset state");
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_RESET, "not in reset state");
|
||||
chMBResumeX(&mb1);
|
||||
}
|
||||
|
||||
/* [4.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
|
||||
once, no errors expected.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
for (i = 0; i < MB_SIZE - 1; i++) {
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [4.1.5] Testing intermediate conditions. Data pointers must be
|
||||
aligned, semaphore counters are checked.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
|
||||
test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
|
||||
}
|
||||
|
||||
/* [4.1.6] Emptying the mailbox using chMBFetch(), no errors
|
||||
expected.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
test_emit_token(msg2);
|
||||
}
|
||||
test_assert_sequence("ABCD", "wrong get sequence");
|
||||
}
|
||||
|
||||
/* [4.1.7] Posting and then fetching one more message, no errors
|
||||
expected.*/
|
||||
test_set_step(7);
|
||||
{
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [4.1.8] Testing final conditions. Data pointers must be aligned to
|
||||
buffer start, semaphore counters are checked.*/
|
||||
test_set_step(8);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
chSysLock();
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chThdSuspendTimeoutS(&tr1, MS2ST(1000));
|
||||
chSysUnlock();
|
||||
test_assert_time_window(time + MS2ST(1000),
|
||||
time + MS2ST(1000) + 1,
|
||||
"out of time window");
|
||||
test_assert(NULL == tr1, "not NULL");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong returned message");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_004_001 = {
|
||||
"Mailbox normal API, non-blocking tests",
|
||||
"Suspend and Resume functionality",
|
||||
test_004_001_setup,
|
||||
test_004_001_teardown,
|
||||
NULL,
|
||||
test_004_001_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_004_002 [4.2] Mailbox I-Class API, non-blocking tests
|
||||
* @page test_004_002 [4.2] Events Flags functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The mailbox I-Class API is tested without triggering blocking
|
||||
* conditions.
|
||||
* Event flags functionality is tested.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_EVENTS
|
||||
* .
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.2.1] Testing the mailbox size.
|
||||
* - [4.2.2] Resetting the mailbox, conditions are checked, no errors
|
||||
* expected.
|
||||
* - [4.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
|
||||
* once, no errors expected.
|
||||
* - [4.2.4] Testing intermediate conditions. Data pointers must be
|
||||
* aligned, semaphore counters are checked.
|
||||
* - [4.2.5] Emptying the mailbox using chMBFetchI(), no errors
|
||||
* expected.
|
||||
* - [4.2.6] Posting and then fetching one more message, no errors
|
||||
* expected.
|
||||
* - [4.2.7] Testing final conditions. Data pointers must be aligned to
|
||||
* buffer start, semaphore counters are checked.
|
||||
* - [4.2.1] A set of event flags are set on the current thread then
|
||||
* the function chEvtWaitAnyTimeout() is invoked, the function is
|
||||
* supposed to return immediately because the event flags are already
|
||||
* pending, after return the events mask is tested.
|
||||
* - [4.2.2] The pending event flags mask is cleared then the function
|
||||
* chEvtWaitAnyTimeout() is invoked, after return the events mask is
|
||||
* tested. The thread is signaled by another thread.
|
||||
* - [4.2.3] The function chEvtWaitAnyTimeout() is invoked, no event
|
||||
* can wakeup the thread, the function must return because timeout.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_004_002_setup(void) {
|
||||
chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
|
||||
}
|
||||
|
||||
static void test_004_002_teardown(void) {
|
||||
chMBReset(&mb1);
|
||||
}
|
||||
|
||||
static void test_004_002_execute(void) {
|
||||
msg_t msg1, msg2;
|
||||
unsigned i;
|
||||
systime_t time;
|
||||
eventmask_t events;
|
||||
|
||||
/* [4.2.1] Testing the mailbox size.*/
|
||||
/* [4.2.1] A set of event flags are set on the current thread then
|
||||
the function chEvtWaitAnyTimeout() is invoked, the function is
|
||||
supposed to return immediately because the event flags are already
|
||||
pending, after return the events mask is tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
|
||||
time = chVTGetSystemTimeX();
|
||||
chEvtSignal(chThdGetSelfX(), 0x55);
|
||||
events = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000));
|
||||
test_assert((eventmask_t)0 != events, "timed out");
|
||||
test_assert((eventmask_t)0x55 == events, "wrong events mask");
|
||||
}
|
||||
|
||||
/* [4.2.2] Resetting the mailbox, conditions are checked, no errors
|
||||
expected.*/
|
||||
/* [4.2.2] The pending event flags mask is cleared then the function
|
||||
chEvtWaitAnyTimeout() is invoked, after return the events mask is
|
||||
tested. The thread is signaled by another thread.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chSysLock();
|
||||
chMBResetI(&mb1);
|
||||
chSysUnlock();
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
chMBResumeX(&mb1);
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdGetSelfX()->epmask = 0;
|
||||
events = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000));
|
||||
test_assert((eventmask_t)0 != events, "timed out");
|
||||
test_assert((eventmask_t)0x55 == events, "wrong events mask");
|
||||
}
|
||||
|
||||
/* [4.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
|
||||
once, no errors expected.*/
|
||||
/* [4.2.3] The function chEvtWaitAnyTimeout() is invoked, no event
|
||||
can wakeup the thread, the function must return because timeout.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
for (i = 0; i < MB_SIZE - 1; i++) {
|
||||
chSysLock();
|
||||
msg1 = chMBPostI(&mb1, 'B' + i);
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
chSysLock();
|
||||
msg1 = chMBPostAheadI(&mb1, 'A');
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [4.2.4] Testing intermediate conditions. Data pointers must be
|
||||
aligned, semaphore counters are checked.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
|
||||
test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
|
||||
}
|
||||
|
||||
/* [4.2.5] Emptying the mailbox using chMBFetchI(), no errors
|
||||
expected.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
chSysLock();
|
||||
msg1 = chMBFetchI(&mb1, &msg2);
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
test_emit_token(msg2);
|
||||
}
|
||||
test_assert_sequence("ABCD", "wrong get sequence");
|
||||
}
|
||||
|
||||
/* [4.2.6] Posting and then fetching one more message, no errors
|
||||
expected.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [4.2.7] Testing final conditions. Data pointers must be aligned to
|
||||
buffer start, semaphore counters are checked.*/
|
||||
test_set_step(7);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
time = chVTGetSystemTimeX();
|
||||
events = chEvtWaitAnyTimeout(0, MS2ST(1000));
|
||||
test_assert_time_window(time + MS2ST(1000),
|
||||
time + MS2ST(1000) + 1,
|
||||
"out of time window");
|
||||
test_assert((eventmask_t)0 == events, "wrong events mask");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_004_002 = {
|
||||
"Mailbox I-Class API, non-blocking tests",
|
||||
test_004_002_setup,
|
||||
test_004_002_teardown,
|
||||
"Events Flags functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
test_004_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_004_003 [4.3] Mailbox timeouts
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The mailbox API is tested for timeouts.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.3.1] Filling the mailbox.
|
||||
* - [4.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
|
||||
* chMBPostAheadI() timeout.
|
||||
* - [4.3.3] Resetting the mailbox.
|
||||
* - [4.3.4] Testing chMBFetch() and chMBFetchI() timeout.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_004_003_setup(void) {
|
||||
chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
|
||||
}
|
||||
|
||||
static void test_004_003_teardown(void) {
|
||||
chMBReset(&mb1);
|
||||
}
|
||||
|
||||
static void test_004_003_execute(void) {
|
||||
msg_t msg1, msg2;
|
||||
unsigned i;
|
||||
|
||||
/* [4.3.1] Filling the mailbox.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
}
|
||||
|
||||
/* [4.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
|
||||
chMBPostAheadI() timeout.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
msg1 = chMBPost(&mb1, 'X', 1);
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBPostI(&mb1, 'X');
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
msg1 = chMBPostAhead(&mb1, 'X', 1);
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBPostAheadI(&mb1, 'X');
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [4.3.3] Resetting the mailbox.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chMBReset(&mb1);;
|
||||
chMBResumeX(&mb1);
|
||||
}
|
||||
|
||||
/* [4.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
msg1 = chMBFetch(&mb1, &msg2, 1);
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBFetchI(&mb1, &msg2);
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_004_003 = {
|
||||
"Mailbox timeouts",
|
||||
test_004_003_setup,
|
||||
test_004_003_teardown,
|
||||
test_004_003_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_EVENTS */
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Mailboxes.
|
||||
* @brief Suspend/Resume and Event Flags.
|
||||
*/
|
||||
const testcase_t * const test_sequence_004[] = {
|
||||
&test_004_001,
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
&test_004_002,
|
||||
&test_004_003,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_MAILBOXES */
|
||||
|
|
|
@ -22,18 +22,18 @@
|
|||
* @file test_sequence_005.c
|
||||
* @brief Test Sequence 005 code.
|
||||
*
|
||||
* @page test_sequence_005 [5] Memory Pools
|
||||
* @page test_sequence_005 [5] Mailboxes
|
||||
*
|
||||
* File: @ref test_sequence_005.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/NIL functionalities related to
|
||||
* memory pools.
|
||||
* mailboxes.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_MEMPOOLS
|
||||
* - CH_CFG_USE_MAILBOXES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
|
@ -43,254 +43,366 @@
|
|||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
#define MEMORY_POOL_SIZE 4
|
||||
#define ALLOWED_DELAY MS2ST(5)
|
||||
#define MB_SIZE 4
|
||||
|
||||
static uint32_t objects[MEMORY_POOL_SIZE];
|
||||
static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL);
|
||||
|
||||
#if CH_CFG_USE_SEMAPHORES
|
||||
static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t));
|
||||
#endif
|
||||
|
||||
static void *null_provider(size_t size, unsigned align) {
|
||||
|
||||
(void)size;
|
||||
(void)align;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
static msg_t mb_buffer[MB_SIZE];
|
||||
static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE);
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_005_001 [5.1] Loading and emptying a memory pool
|
||||
* @page test_005_001 [5.1] Mailbox normal API, non-blocking tests
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The memory pool functionality is tested by loading and emptying it,
|
||||
* all conditions are tested.
|
||||
* The mailbox normal API is tested without triggering blocking
|
||||
* conditions.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [5.1.1] Adding the objects to the pool using chPoolLoadArray().
|
||||
* - [5.1.2] Emptying the pool using chPoolAlloc().
|
||||
* - [5.1.3] Now must be empty.
|
||||
* - [5.1.4] Adding the objects to the pool using chPoolFree().
|
||||
* - [5.1.5] Emptying the pool using chPoolAlloc() again.
|
||||
* - [5.1.6] Now must be empty again.
|
||||
* - [5.1.7] Covering the case where a provider is unable to return
|
||||
* more memory.
|
||||
* - [5.1.1] Testing the mailbox size.
|
||||
* - [5.1.2] Resetting the mailbox, conditions are checked, no errors
|
||||
* expected.
|
||||
* - [5.1.3] Testing the behavior of API when the mailbox is in reset
|
||||
* state then return in active state.
|
||||
* - [5.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
|
||||
* once, no errors expected.
|
||||
* - [5.1.5] Testing intermediate conditions. Data pointers must be
|
||||
* aligned, semaphore counters are checked.
|
||||
* - [5.1.6] Emptying the mailbox using chMBFetch(), no errors
|
||||
* expected.
|
||||
* - [5.1.7] Posting and then fetching one more message, no errors
|
||||
* expected.
|
||||
* - [5.1.8] Testing final conditions. Data pointers must be aligned to
|
||||
* buffer start, semaphore counters are checked.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_005_001_setup(void) {
|
||||
chPoolObjectInit(&mp1, sizeof (uint32_t), NULL);
|
||||
chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
|
||||
}
|
||||
|
||||
static void test_005_001_teardown(void) {
|
||||
chMBReset(&mb1);
|
||||
}
|
||||
|
||||
static void test_005_001_execute(void) {
|
||||
msg_t msg1, msg2;
|
||||
unsigned i;
|
||||
|
||||
/* [5.1.1] Adding the objects to the pool using chPoolLoadArray().*/
|
||||
/* [5.1.1] Testing the mailbox size.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE);
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
|
||||
}
|
||||
|
||||
/* [5.1.2] Emptying the pool using chPoolAlloc().*/
|
||||
/* [5.1.2] Resetting the mailbox, conditions are checked, no errors
|
||||
expected.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
|
||||
chMBReset(&mb1);
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
}
|
||||
|
||||
/* [5.1.3] Now must be empty.*/
|
||||
/* [5.1.3] Testing the behavior of API when the mailbox is in reset
|
||||
state then return in active state.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
|
||||
msg1 = chMBPost(&mb1, (msg_t)0, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_RESET, "not in reset state");
|
||||
msg1 = chMBPostAhead(&mb1, (msg_t)0, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_RESET, "not in reset state");
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_RESET, "not in reset state");
|
||||
chMBResumeX(&mb1);
|
||||
}
|
||||
|
||||
/* [5.1.4] Adding the objects to the pool using chPoolFree().*/
|
||||
/* [5.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
|
||||
once, no errors expected.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
chPoolFree(&mp1, &objects[i]);
|
||||
for (i = 0; i < MB_SIZE - 1; i++) {
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [5.1.5] Emptying the pool using chPoolAlloc() again.*/
|
||||
/* [5.1.5] Testing intermediate conditions. Data pointers must be
|
||||
aligned, semaphore counters are checked.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
|
||||
test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
|
||||
}
|
||||
|
||||
/* [5.1.6] Now must be empty again.*/
|
||||
/* [5.1.6] Emptying the mailbox using chMBFetch(), no errors
|
||||
expected.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
test_emit_token(msg2);
|
||||
}
|
||||
test_assert_sequence("ABCD", "wrong get sequence");
|
||||
}
|
||||
|
||||
/* [5.1.7] Covering the case where a provider is unable to return
|
||||
more memory.*/
|
||||
/* [5.1.7] Posting and then fetching one more message, no errors
|
||||
expected.*/
|
||||
test_set_step(7);
|
||||
{
|
||||
chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider);
|
||||
test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory");
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [5.1.8] Testing final conditions. Data pointers must be aligned to
|
||||
buffer start, semaphore counters are checked.*/
|
||||
test_set_step(8);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_005_001 = {
|
||||
"Loading and emptying a memory pool",
|
||||
"Mailbox normal API, non-blocking tests",
|
||||
test_005_001_setup,
|
||||
NULL,
|
||||
test_005_001_teardown,
|
||||
test_005_001_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_005_002 [5.2] Loading and emptying a guarded memory pool without waiting
|
||||
* @page test_005_002 [5.2] Mailbox I-Class API, non-blocking tests
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The memory pool functionality is tested by loading and emptying it,
|
||||
* all conditions are tested.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
* The mailbox I-Class API is tested without triggering blocking
|
||||
* conditions.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [5.2.1] Adding the objects to the pool using
|
||||
* chGuardedPoolLoadArray().
|
||||
* - [5.2.2] Emptying the pool using chGuardedPoolAllocTimeout().
|
||||
* - [5.2.3] Now must be empty.
|
||||
* - [5.2.4] Adding the objects to the pool using chGuardedPoolFree().
|
||||
* - [5.2.5] Emptying the pool using chGuardedPoolAllocTimeout() again.
|
||||
* - [5.2.6] Now must be empty again.
|
||||
* - [5.2.1] Testing the mailbox size.
|
||||
* - [5.2.2] Resetting the mailbox, conditions are checked, no errors
|
||||
* expected.
|
||||
* - [5.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
|
||||
* once, no errors expected.
|
||||
* - [5.2.4] Testing intermediate conditions. Data pointers must be
|
||||
* aligned, semaphore counters are checked.
|
||||
* - [5.2.5] Emptying the mailbox using chMBFetchI(), no errors
|
||||
* expected.
|
||||
* - [5.2.6] Posting and then fetching one more message, no errors
|
||||
* expected.
|
||||
* - [5.2.7] Testing final conditions. Data pointers must be aligned to
|
||||
* buffer start, semaphore counters are checked.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_005_002_setup(void) {
|
||||
chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
|
||||
chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
|
||||
}
|
||||
|
||||
static void test_005_002_teardown(void) {
|
||||
chMBReset(&mb1);
|
||||
}
|
||||
|
||||
static void test_005_002_execute(void) {
|
||||
msg_t msg1, msg2;
|
||||
unsigned i;
|
||||
|
||||
/* [5.2.1] Adding the objects to the pool using
|
||||
chGuardedPoolLoadArray().*/
|
||||
/* [5.2.1] Testing the mailbox size.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE);
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
|
||||
}
|
||||
|
||||
/* [5.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/
|
||||
/* [5.2.2] Resetting the mailbox, conditions are checked, no errors
|
||||
expected.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
|
||||
chSysLock();
|
||||
chMBResetI(&mb1);
|
||||
chSysUnlock();
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
chMBResumeX(&mb1);
|
||||
}
|
||||
|
||||
/* [5.2.3] Now must be empty.*/
|
||||
/* [5.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
|
||||
once, no errors expected.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
|
||||
for (i = 0; i < MB_SIZE - 1; i++) {
|
||||
chSysLock();
|
||||
msg1 = chMBPostI(&mb1, 'B' + i);
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
chSysLock();
|
||||
msg1 = chMBPostAheadI(&mb1, 'A');
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [5.2.4] Adding the objects to the pool using
|
||||
chGuardedPoolFree().*/
|
||||
/* [5.2.4] Testing intermediate conditions. Data pointers must be
|
||||
aligned, semaphore counters are checked.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
chGuardedPoolFree(&gmp1, &objects[i]);
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
|
||||
test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
|
||||
}
|
||||
|
||||
/* [5.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
|
||||
again.*/
|
||||
/* [5.2.5] Emptying the mailbox using chMBFetchI(), no errors
|
||||
expected.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
chSysLock();
|
||||
msg1 = chMBFetchI(&mb1, &msg2);
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
test_emit_token(msg2);
|
||||
}
|
||||
test_assert_sequence("ABCD", "wrong get sequence");
|
||||
}
|
||||
|
||||
/* [5.2.6] Now must be empty again.*/
|
||||
/* [5.2.6] Posting and then fetching one more message, no errors
|
||||
expected.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [5.2.7] Testing final conditions. Data pointers must be aligned to
|
||||
buffer start, semaphore counters are checked.*/
|
||||
test_set_step(7);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_005_002 = {
|
||||
"Loading and emptying a guarded memory pool without waiting",
|
||||
"Mailbox I-Class API, non-blocking tests",
|
||||
test_005_002_setup,
|
||||
NULL,
|
||||
test_005_002_teardown,
|
||||
test_005_002_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_005_003 [5.3] Guarded Memory Pools timeout
|
||||
* @page test_005_003 [5.3] Mailbox timeouts
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The timeout features for the Guarded Memory Pools is tested.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
* The mailbox API is tested for timeouts.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [5.3.1] Trying to allocate with 100mS timeout, must fail because
|
||||
* the pool is empty.
|
||||
* - [5.3.1] Filling the mailbox.
|
||||
* - [5.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
|
||||
* chMBPostAheadI() timeout.
|
||||
* - [5.3.3] Resetting the mailbox.
|
||||
* - [5.3.4] Testing chMBFetch() and chMBFetchI() timeout.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_005_003_setup(void) {
|
||||
chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
|
||||
chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
|
||||
}
|
||||
|
||||
static void test_005_003_teardown(void) {
|
||||
chMBReset(&mb1);
|
||||
}
|
||||
|
||||
static void test_005_003_execute(void) {
|
||||
msg_t msg1, msg2;
|
||||
unsigned i;
|
||||
|
||||
/* [5.3.1] Trying to allocate with 100mS timeout, must fail because
|
||||
the pool is empty.*/
|
||||
/* [5.3.1] Filling the mailbox.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty");
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
}
|
||||
|
||||
/* [5.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
|
||||
chMBPostAheadI() timeout.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
msg1 = chMBPost(&mb1, 'X', 1);
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBPostI(&mb1, 'X');
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
msg1 = chMBPostAhead(&mb1, 'X', 1);
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBPostAheadI(&mb1, 'X');
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [5.3.3] Resetting the mailbox.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chMBReset(&mb1);;
|
||||
chMBResumeX(&mb1);
|
||||
}
|
||||
|
||||
/* [5.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
msg1 = chMBFetch(&mb1, &msg2, 1);
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBFetchI(&mb1, &msg2);
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_005_003 = {
|
||||
"Guarded Memory Pools timeout",
|
||||
"Mailbox timeouts",
|
||||
test_005_003_setup,
|
||||
NULL,
|
||||
test_005_003_teardown,
|
||||
test_005_003_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Memory Pools.
|
||||
* @brief Mailboxes.
|
||||
*/
|
||||
const testcase_t * const test_sequence_005[] = {
|
||||
&test_005_001,
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&test_005_002,
|
||||
#endif
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&test_005_003,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_MEMPOOLS */
|
||||
#endif /* CH_CFG_USE_MAILBOXES */
|
||||
|
|
|
@ -22,252 +22,275 @@
|
|||
* @file test_sequence_006.c
|
||||
* @brief Test Sequence 006 code.
|
||||
*
|
||||
* @page test_sequence_006 [6] Memory Heaps
|
||||
* @page test_sequence_006 [6] Memory Pools
|
||||
*
|
||||
* File: @ref test_sequence_006.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/NIL functionalities related to
|
||||
* memory heaps.
|
||||
* memory pools.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_HEAP
|
||||
* - CH_CFG_USE_MEMPOOLS
|
||||
* .
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_006_001
|
||||
* - @subpage test_006_002
|
||||
* - @subpage test_006_003
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
#define ALLOC_SIZE 16
|
||||
#define HEAP_SIZE (ALLOC_SIZE * 8)
|
||||
#define MEMORY_POOL_SIZE 4
|
||||
|
||||
static memory_heap_t test_heap;
|
||||
static CH_HEAP_AREA(myheap, HEAP_SIZE);
|
||||
static uint32_t objects[MEMORY_POOL_SIZE];
|
||||
static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL);
|
||||
|
||||
#if CH_CFG_USE_SEMAPHORES
|
||||
static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t));
|
||||
#endif
|
||||
|
||||
static void *null_provider(size_t size, unsigned align) {
|
||||
|
||||
(void)size;
|
||||
(void)align;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_006_001 [6.1] Allocation and fragmentation
|
||||
* @page test_006_001 [6.1] Loading and emptying a memory pool
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Series of allocations/deallocations are performed in carefully
|
||||
* designed sequences in order to stimulate all the possible code paths
|
||||
* inside the allocator. The test expects to find the heap back to the
|
||||
* initial status after each sequence.
|
||||
* The memory pool functionality is tested by loading and emptying it,
|
||||
* all conditions are tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [6.1.1] Testing initial conditions, the heap must not be
|
||||
* fragmented and one free block present.
|
||||
* - [6.1.2] Trying to allocate an block bigger than available space,
|
||||
* an error is expected.
|
||||
* - [6.1.3] Single block allocation using chHeapAlloc() then the block
|
||||
* is freed using chHeapFree(), must not fail.
|
||||
* - [6.1.4] Using chHeapStatus() to assess the heap state. There must
|
||||
* be at least one free block of sufficient size.
|
||||
* - [6.1.5] Allocating then freeing in the same order.
|
||||
* - [6.1.6] Allocating then freeing in reverse order.
|
||||
* - [6.1.7] Small fragments handling. Checking the behavior when
|
||||
* allocating blocks with size not multiple of alignment unit.
|
||||
* - [6.1.8] Skipping a fragment, the first fragment in the list is too
|
||||
* small so the allocator must pick the second one.
|
||||
* - [6.1.9] Allocating the whole available space.
|
||||
* - [6.1.10] Testing final conditions. The heap geometry must be the
|
||||
* same than the one registered at beginning.
|
||||
* - [6.1.1] Adding the objects to the pool using chPoolLoadArray().
|
||||
* - [6.1.2] Emptying the pool using chPoolAlloc().
|
||||
* - [6.1.3] Now must be empty.
|
||||
* - [6.1.4] Adding the objects to the pool using chPoolFree().
|
||||
* - [6.1.5] Emptying the pool using chPoolAlloc() again.
|
||||
* - [6.1.6] Now must be empty again.
|
||||
* - [6.1.7] Covering the case where a provider is unable to return
|
||||
* more memory.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_006_001_setup(void) {
|
||||
chHeapObjectInit(&test_heap, myheap, sizeof(myheap));
|
||||
chPoolObjectInit(&mp1, sizeof (uint32_t), NULL);
|
||||
}
|
||||
|
||||
static void test_006_001_execute(void) {
|
||||
void *p1, *p2, *p3;
|
||||
size_t n, sz;
|
||||
unsigned i;
|
||||
|
||||
/* [6.1.1] Testing initial conditions, the heap must not be
|
||||
fragmented and one free block present.*/
|
||||
/* [6.1.1] Adding the objects to the pool using chPoolLoadArray().*/
|
||||
test_set_step(1);
|
||||
{
|
||||
test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented");
|
||||
chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE);
|
||||
}
|
||||
|
||||
/* [6.1.2] Trying to allocate an block bigger than available space,
|
||||
an error is expected.*/
|
||||
/* [6.1.2] Emptying the pool using chPoolAlloc().*/
|
||||
test_set_step(2);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, HEAP_SIZE * 2);
|
||||
test_assert(p1 == NULL, "allocation not failed");
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
|
||||
}
|
||||
|
||||
/* [6.1.3] Single block allocation using chHeapAlloc() then the block
|
||||
is freed using chHeapFree(), must not fail.*/
|
||||
/* [6.1.3] Now must be empty.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
test_assert(p1 != NULL, "allocation failed");
|
||||
chHeapFree(p1);
|
||||
test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
|
||||
}
|
||||
|
||||
/* [6.1.4] Using chHeapStatus() to assess the heap state. There must
|
||||
be at least one free block of sufficient size.*/
|
||||
/* [6.1.4] Adding the objects to the pool using chPoolFree().*/
|
||||
test_set_step(4);
|
||||
{
|
||||
size_t total_size, largest_size;
|
||||
|
||||
n = chHeapStatus(&test_heap, &total_size, &largest_size);
|
||||
test_assert(n == 1, "missing free block");
|
||||
test_assert(total_size >= ALLOC_SIZE, "unexpected heap state");
|
||||
test_assert(total_size == largest_size, "unexpected heap state");
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
chPoolFree(&mp1, &objects[i]);
|
||||
}
|
||||
|
||||
/* [6.1.5] Allocating then freeing in the same order.*/
|
||||
/* [6.1.5] Emptying the pool using chPoolAlloc() again.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p1); /* Does not merge.*/
|
||||
chHeapFree(p2); /* Merges backward.*/
|
||||
chHeapFree(p3); /* Merges both sides.*/
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
|
||||
}
|
||||
|
||||
/* [6.1.6] Allocating then freeing in reverse order.*/
|
||||
/* [6.1.6] Now must be empty again.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p3); /* Merges forward.*/
|
||||
chHeapFree(p2); /* Merges forward.*/
|
||||
chHeapFree(p1); /* Merges forward.*/
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
|
||||
}
|
||||
|
||||
/* [6.1.7] Small fragments handling. Checking the behavior when
|
||||
allocating blocks with size not multiple of alignment unit.*/
|
||||
/* [6.1.7] Covering the case where a provider is unable to return
|
||||
more memory.*/
|
||||
test_set_step(7);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p1);
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
/* Note, the first situation happens when the alignment size is smaller
|
||||
than the header size, the second in the other cases.*/
|
||||
test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) ||
|
||||
(chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
|
||||
chHeapFree(p2);
|
||||
chHeapFree(p1);
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
}
|
||||
|
||||
/* [6.1.8] Skipping a fragment, the first fragment in the list is too
|
||||
small so the allocator must pick the second one.*/
|
||||
test_set_step(8);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p1);
|
||||
test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/
|
||||
chHeapFree(p1);
|
||||
chHeapFree(p2);
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
}
|
||||
|
||||
/* [6.1.9] Allocating the whole available space.*/
|
||||
test_set_step(9);
|
||||
{
|
||||
(void)chHeapStatus(&test_heap, &n, NULL);
|
||||
p1 = chHeapAlloc(&test_heap, n);
|
||||
test_assert(p1 != NULL, "allocation failed");
|
||||
test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty");
|
||||
chHeapFree(p1);
|
||||
}
|
||||
|
||||
/* [6.1.10] Testing final conditions. The heap geometry must be the
|
||||
same than the one registered at beginning.*/
|
||||
test_set_step(10);
|
||||
{
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
test_assert(n == sz, "size changed");
|
||||
chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider);
|
||||
test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_006_001 = {
|
||||
"Allocation and fragmentation",
|
||||
"Loading and emptying a memory pool",
|
||||
test_006_001_setup,
|
||||
NULL,
|
||||
test_006_001_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_006_002 [6.2] Default Heap
|
||||
* @page test_006_002 [6.2] Loading and emptying a guarded memory pool without waiting
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The default heap is pre-allocated in the system. We test base
|
||||
* functionality.
|
||||
* The memory pool functionality is tested by loading and emptying it,
|
||||
* all conditions are tested.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [6.2.1] Single block allocation using chHeapAlloc() then the block
|
||||
* is freed using chHeapFree(), must not fail.
|
||||
* - [6.2.2] Testing allocation failure.
|
||||
* - [6.2.1] Adding the objects to the pool using
|
||||
* chGuardedPoolLoadArray().
|
||||
* - [6.2.2] Emptying the pool using chGuardedPoolAllocTimeout().
|
||||
* - [6.2.3] Now must be empty.
|
||||
* - [6.2.4] Adding the objects to the pool using chGuardedPoolFree().
|
||||
* - [6.2.5] Emptying the pool using chGuardedPoolAllocTimeout() again.
|
||||
* - [6.2.6] Now must be empty again.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_006_002_execute(void) {
|
||||
void *p1;
|
||||
size_t total_size, largest_size;
|
||||
static void test_006_002_setup(void) {
|
||||
chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
|
||||
}
|
||||
|
||||
/* [6.2.1] Single block allocation using chHeapAlloc() then the block
|
||||
is freed using chHeapFree(), must not fail.*/
|
||||
static void test_006_002_execute(void) {
|
||||
unsigned i;
|
||||
|
||||
/* [6.2.1] Adding the objects to the pool using
|
||||
chGuardedPoolLoadArray().*/
|
||||
test_set_step(1);
|
||||
{
|
||||
(void)chHeapStatus(NULL, &total_size, &largest_size);
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
test_assert(p1 != NULL, "allocation failed");
|
||||
chHeapFree(p1);
|
||||
chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE);
|
||||
}
|
||||
|
||||
/* [6.2.2] Testing allocation failure.*/
|
||||
/* [6.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/
|
||||
test_set_step(2);
|
||||
{
|
||||
p1 = chHeapAlloc(NULL, (size_t)-256);
|
||||
test_assert(p1 == NULL, "allocation not failed");
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
|
||||
}
|
||||
|
||||
/* [6.2.3] Now must be empty.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
|
||||
}
|
||||
|
||||
/* [6.2.4] Adding the objects to the pool using
|
||||
chGuardedPoolFree().*/
|
||||
test_set_step(4);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
chGuardedPoolFree(&gmp1, &objects[i]);
|
||||
}
|
||||
|
||||
/* [6.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
|
||||
again.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
|
||||
}
|
||||
|
||||
/* [6.2.6] Now must be empty again.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_006_002 = {
|
||||
"Default Heap",
|
||||
NULL,
|
||||
"Loading and emptying a guarded memory pool without waiting",
|
||||
test_006_002_setup,
|
||||
NULL,
|
||||
test_006_002_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_006_003 [6.3] Guarded Memory Pools timeout
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The timeout features for the Guarded Memory Pools is tested.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [6.3.1] Trying to allocate with 100mS timeout, must fail because
|
||||
* the pool is empty.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_006_003_setup(void) {
|
||||
chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
|
||||
}
|
||||
|
||||
static void test_006_003_execute(void) {
|
||||
|
||||
/* [6.3.1] Trying to allocate with 100mS timeout, must fail because
|
||||
the pool is empty.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_006_003 = {
|
||||
"Guarded Memory Pools timeout",
|
||||
test_006_003_setup,
|
||||
NULL,
|
||||
test_006_003_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Memory Heaps.
|
||||
* @brief Memory Pools.
|
||||
*/
|
||||
const testcase_t * const test_sequence_006[] = {
|
||||
&test_006_001,
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&test_006_002,
|
||||
#endif
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&test_006_003,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_HEAP */
|
||||
#endif /* CH_CFG_USE_MEMPOOLS */
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
#include "ch_test.h"
|
||||
#include "test_root.h"
|
||||
|
||||
/**
|
||||
* @file test_sequence_007.c
|
||||
* @brief Test Sequence 007 code.
|
||||
*
|
||||
* @page test_sequence_007 [7] Memory Heaps
|
||||
*
|
||||
* File: @ref test_sequence_007.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/NIL functionalities related to
|
||||
* memory heaps.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_HEAP
|
||||
* .
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_007_001
|
||||
* - @subpage test_007_002
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
#define ALLOC_SIZE 16
|
||||
#define HEAP_SIZE (ALLOC_SIZE * 8)
|
||||
|
||||
static memory_heap_t test_heap;
|
||||
static CH_HEAP_AREA(myheap, HEAP_SIZE);
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_007_001 [7.1] Allocation and fragmentation
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Series of allocations/deallocations are performed in carefully
|
||||
* designed sequences in order to stimulate all the possible code paths
|
||||
* inside the allocator. The test expects to find the heap back to the
|
||||
* initial status after each sequence.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [7.1.1] Testing initial conditions, the heap must not be
|
||||
* fragmented and one free block present.
|
||||
* - [7.1.2] Trying to allocate an block bigger than available space,
|
||||
* an error is expected.
|
||||
* - [7.1.3] Single block allocation using chHeapAlloc() then the block
|
||||
* is freed using chHeapFree(), must not fail.
|
||||
* - [7.1.4] Using chHeapStatus() to assess the heap state. There must
|
||||
* be at least one free block of sufficient size.
|
||||
* - [7.1.5] Allocating then freeing in the same order.
|
||||
* - [7.1.6] Allocating then freeing in reverse order.
|
||||
* - [7.1.7] Small fragments handling. Checking the behavior when
|
||||
* allocating blocks with size not multiple of alignment unit.
|
||||
* - [7.1.8] Skipping a fragment, the first fragment in the list is too
|
||||
* small so the allocator must pick the second one.
|
||||
* - [7.1.9] Allocating the whole available space.
|
||||
* - [7.1.10] Testing final conditions. The heap geometry must be the
|
||||
* same than the one registered at beginning.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_007_001_setup(void) {
|
||||
chHeapObjectInit(&test_heap, myheap, sizeof(myheap));
|
||||
}
|
||||
|
||||
static void test_007_001_execute(void) {
|
||||
void *p1, *p2, *p3;
|
||||
size_t n, sz;
|
||||
|
||||
/* [7.1.1] Testing initial conditions, the heap must not be
|
||||
fragmented and one free block present.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented");
|
||||
}
|
||||
|
||||
/* [7.1.2] Trying to allocate an block bigger than available space,
|
||||
an error is expected.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, HEAP_SIZE * 2);
|
||||
test_assert(p1 == NULL, "allocation not failed");
|
||||
}
|
||||
|
||||
/* [7.1.3] Single block allocation using chHeapAlloc() then the block
|
||||
is freed using chHeapFree(), must not fail.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
test_assert(p1 != NULL, "allocation failed");
|
||||
chHeapFree(p1);
|
||||
}
|
||||
|
||||
/* [7.1.4] Using chHeapStatus() to assess the heap state. There must
|
||||
be at least one free block of sufficient size.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
size_t total_size, largest_size;
|
||||
|
||||
n = chHeapStatus(&test_heap, &total_size, &largest_size);
|
||||
test_assert(n == 1, "missing free block");
|
||||
test_assert(total_size >= ALLOC_SIZE, "unexpected heap state");
|
||||
test_assert(total_size == largest_size, "unexpected heap state");
|
||||
}
|
||||
|
||||
/* [7.1.5] Allocating then freeing in the same order.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p1); /* Does not merge.*/
|
||||
chHeapFree(p2); /* Merges backward.*/
|
||||
chHeapFree(p3); /* Merges both sides.*/
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
}
|
||||
|
||||
/* [7.1.6] Allocating then freeing in reverse order.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p3); /* Merges forward.*/
|
||||
chHeapFree(p2); /* Merges forward.*/
|
||||
chHeapFree(p1); /* Merges forward.*/
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
}
|
||||
|
||||
/* [7.1.7] Small fragments handling. Checking the behavior when
|
||||
allocating blocks with size not multiple of alignment unit.*/
|
||||
test_set_step(7);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p1);
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
/* Note, the first situation happens when the alignment size is smaller
|
||||
than the header size, the second in the other cases.*/
|
||||
test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) ||
|
||||
(chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
|
||||
chHeapFree(p2);
|
||||
chHeapFree(p1);
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
}
|
||||
|
||||
/* [7.1.8] Skipping a fragment, the first fragment in the list is too
|
||||
small so the allocator must pick the second one.*/
|
||||
test_set_step(8);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p1);
|
||||
test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/
|
||||
chHeapFree(p1);
|
||||
chHeapFree(p2);
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
}
|
||||
|
||||
/* [7.1.9] Allocating the whole available space.*/
|
||||
test_set_step(9);
|
||||
{
|
||||
(void)chHeapStatus(&test_heap, &n, NULL);
|
||||
p1 = chHeapAlloc(&test_heap, n);
|
||||
test_assert(p1 != NULL, "allocation failed");
|
||||
test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty");
|
||||
chHeapFree(p1);
|
||||
}
|
||||
|
||||
/* [7.1.10] Testing final conditions. The heap geometry must be the
|
||||
same than the one registered at beginning.*/
|
||||
test_set_step(10);
|
||||
{
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
test_assert(n == sz, "size changed");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_007_001 = {
|
||||
"Allocation and fragmentation",
|
||||
test_007_001_setup,
|
||||
NULL,
|
||||
test_007_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_007_002 [7.2] Default Heap
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The default heap is pre-allocated in the system. We test base
|
||||
* functionality.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [7.2.1] Single block allocation using chHeapAlloc() then the block
|
||||
* is freed using chHeapFree(), must not fail.
|
||||
* - [7.2.2] Testing allocation failure.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_007_002_execute(void) {
|
||||
void *p1;
|
||||
size_t total_size, largest_size;
|
||||
|
||||
/* [7.2.1] Single block allocation using chHeapAlloc() then the block
|
||||
is freed using chHeapFree(), must not fail.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
(void)chHeapStatus(NULL, &total_size, &largest_size);
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
test_assert(p1 != NULL, "allocation failed");
|
||||
chHeapFree(p1);
|
||||
}
|
||||
|
||||
/* [7.2.2] Testing allocation failure.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
p1 = chHeapAlloc(NULL, (size_t)-256);
|
||||
test_assert(p1 == NULL, "allocation not failed");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_007_002 = {
|
||||
"Default Heap",
|
||||
NULL,
|
||||
NULL,
|
||||
test_007_002_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Memory Heaps.
|
||||
*/
|
||||
const testcase_t * const test_sequence_007[] = {
|
||||
&test_007_001,
|
||||
&test_007_002,
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_HEAP */
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
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 test_sequence_007.h
|
||||
* @brief Test Sequence 007 header.
|
||||
*/
|
||||
|
||||
#ifndef TEST_SEQUENCE_007_H
|
||||
#define TEST_SEQUENCE_007_H
|
||||
|
||||
extern const testcase_t * const test_sequence_007[];
|
||||
|
||||
#endif /* TEST_SEQUENCE_007_H */
|
|
@ -6,7 +6,8 @@ TESTSRC = ${CHIBIOS}/test/lib/ch_test.c \
|
|||
${CHIBIOS}/test/nil/source/test/test_sequence_003.c \
|
||||
${CHIBIOS}/test/nil/source/test/test_sequence_004.c \
|
||||
${CHIBIOS}/test/nil/source/test/test_sequence_005.c \
|
||||
${CHIBIOS}/test/nil/source/test/test_sequence_006.c
|
||||
${CHIBIOS}/test/nil/source/test/test_sequence_006.c\
|
||||
${CHIBIOS}/test/nil/source/test/test_sequence_007.c
|
||||
|
||||
# Required include directories
|
||||
TESTINC = ${CHIBIOS}/test/lib \
|
||||
|
|
|
@ -126,6 +126,210 @@ systime_t test_wait_tick(void) {
|
|||
</global_code>
|
||||
</global_data_and_code>
|
||||
<sequences>
|
||||
<sequence>
|
||||
<type index="0">
|
||||
<value>Internal Tests</value>
|
||||
</type>
|
||||
<brief>
|
||||
<value>Information.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>This sequence reports configuration and version information about the RT kernel.</value>
|
||||
</description>
|
||||
<condition>
|
||||
<value />
|
||||
</condition>
|
||||
<shared_code>
|
||||
<value><![CDATA[#include "ch.h"]]></value>
|
||||
</shared_code>
|
||||
<cases>
|
||||
<case>
|
||||
<brief>
|
||||
<value>Kernel Info.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>The version numbers are reported.</value>
|
||||
</description>
|
||||
<condition>
|
||||
<value />
|
||||
</condition>
|
||||
<various_code>
|
||||
<setup_code>
|
||||
<value />
|
||||
</setup_code>
|
||||
<teardown_code>
|
||||
<value />
|
||||
</teardown_code>
|
||||
<local_variables>
|
||||
<value />
|
||||
</local_variables>
|
||||
</various_code>
|
||||
<steps>
|
||||
<step>
|
||||
<description>
|
||||
<value>Prints the version string.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[test_println("*** Product: ChibiOS/RT");
|
||||
test_print("*** Stable Flag: ");
|
||||
test_printn(CH_KERNEL_STABLE);
|
||||
test_println("");
|
||||
test_print("*** Version String: ");
|
||||
test_println(CH_KERNEL_VERSION);
|
||||
test_print("*** Major Number: ");
|
||||
test_printn(CH_KERNEL_MAJOR);
|
||||
test_println("");
|
||||
test_print("*** Minor Number: ");
|
||||
test_printn(CH_KERNEL_MINOR);
|
||||
test_println("");
|
||||
test_print("*** Patch Number: ");
|
||||
test_printn(CH_KERNEL_PATCH);
|
||||
test_println("");]]></value>
|
||||
</code>
|
||||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
<case>
|
||||
<brief>
|
||||
<value>Kernel Settings.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>The static kernel settings are reported.</value>
|
||||
</description>
|
||||
<condition>
|
||||
<value />
|
||||
</condition>
|
||||
<various_code>
|
||||
<setup_code>
|
||||
<value />
|
||||
</setup_code>
|
||||
<teardown_code>
|
||||
<value />
|
||||
</teardown_code>
|
||||
<local_variables>
|
||||
<value />
|
||||
</local_variables>
|
||||
</various_code>
|
||||
<steps>
|
||||
<step>
|
||||
<description>
|
||||
<value>Prints the configuration options settings.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[test_print("*** CH_CFG_ST_RESOLUTION: ");
|
||||
test_printn(CH_CFG_ST_RESOLUTION);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_ST_FREQUENCY: ");
|
||||
test_printn(CH_CFG_ST_FREQUENCY);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_ST_TIMEDELTA: ");
|
||||
test_printn(CH_CFG_ST_TIMEDELTA);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_TIME_QUANTUM: ");
|
||||
test_printn(CH_CFG_TIME_QUANTUM);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_MEMCORE_SIZE: ");
|
||||
test_printn(CH_CFG_MEMCORE_SIZE);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_NO_IDLE_THREAD: ");
|
||||
test_printn(CH_CFG_NO_IDLE_THREAD);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_OPTIMIZE_SPEED: ");
|
||||
test_printn(CH_CFG_OPTIMIZE_SPEED);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_TM: ");
|
||||
test_printn(CH_CFG_USE_TM);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_REGISTRY: ");
|
||||
test_printn(CH_CFG_USE_REGISTRY);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_WAITEXIT: ");
|
||||
test_printn(CH_CFG_USE_WAITEXIT);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_SEMAPHORES: ");
|
||||
test_printn(CH_CFG_USE_SEMAPHORES);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_SEMAPHORES_PRI: ");
|
||||
test_printn(CH_CFG_USE_SEMAPHORES_PRIORITY);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MUTEXES: ");
|
||||
test_printn(CH_CFG_USE_MUTEXES);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MUTEXES_RECURS: ");
|
||||
test_printn(CH_CFG_USE_MUTEXES_RECURSIVE);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_CONDVARS: ");
|
||||
test_printn(CH_CFG_USE_CONDVARS);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_CONDVARS_TIMEO: ");
|
||||
test_printn(CH_CFG_USE_CONDVARS_TIMEOUT);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_EVENTS: ");
|
||||
test_printn(CH_CFG_USE_EVENTS);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_EVENTS_TIMEOUT: ");
|
||||
test_printn(CH_CFG_USE_EVENTS_TIMEOUT);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MESSAGES: ");
|
||||
test_printn(CH_CFG_USE_MESSAGES);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MESSAGES_PRI: ");
|
||||
test_printn(CH_CFG_USE_MESSAGES_PRIORITY);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MAILBOXES: ");
|
||||
test_printn(CH_CFG_USE_MAILBOXES);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MEMCORE: ");
|
||||
test_printn(CH_CFG_USE_MEMCORE);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_HEAP: ");
|
||||
test_printn(CH_CFG_USE_HEAP);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MEMPOOLS: ");
|
||||
test_printn(CH_CFG_USE_MEMPOOLS);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_DYNAMIC: ");
|
||||
test_printn(CH_CFG_USE_DYNAMIC);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_STATISTICS: ");
|
||||
test_printn(CH_DBG_STATISTICS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_SYSTEM_STATE_CHECK: ");
|
||||
test_printn(CH_DBG_SYSTEM_STATE_CHECK);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_ENABLE_CHECKS: ");
|
||||
test_printn(CH_DBG_ENABLE_CHECKS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_ENABLE_ASSERTS: ");
|
||||
test_printn(CH_DBG_ENABLE_ASSERTS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_TRACE_MASK: ");
|
||||
test_printn(CH_DBG_TRACE_MASK);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_TRACE_BUFFER_SIZE: ");
|
||||
test_printn(CH_DBG_TRACE_BUFFER_SIZE);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_ENABLE_STACK_CHECK: ");
|
||||
test_printn(CH_DBG_ENABLE_STACK_CHECK);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_FILL_THREADS: ");
|
||||
test_printn(CH_DBG_FILL_THREADS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_THREADS_PROFILING: ");
|
||||
test_printn(CH_DBG_THREADS_PROFILING);
|
||||
test_println("");]]></value>
|
||||
</code>
|
||||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
</cases>
|
||||
</sequence>
|
||||
<sequence>
|
||||
<type index="0">
|
||||
<value>Internal Tests</value>
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
* - @subpage test_sequence_010
|
||||
* - @subpage test_sequence_011
|
||||
* - @subpage test_sequence_012
|
||||
* - @subpage test_sequence_013
|
||||
* .
|
||||
*/
|
||||
|
||||
|
@ -58,31 +59,32 @@ const testcase_t * const *test_suite[] = {
|
|||
test_sequence_001,
|
||||
test_sequence_002,
|
||||
test_sequence_003,
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
test_sequence_004,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
test_sequence_005,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
test_sequence_006,
|
||||
#endif
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
test_sequence_007,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
test_sequence_008,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
|
||||
test_sequence_009,
|
||||
#endif
|
||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
||||
test_sequence_010,
|
||||
#endif
|
||||
#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
test_sequence_011,
|
||||
#endif
|
||||
#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
|
||||
test_sequence_012,
|
||||
#endif
|
||||
test_sequence_013,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "test_sequence_010.h"
|
||||
#include "test_sequence_011.h"
|
||||
#include "test_sequence_012.h"
|
||||
#include "test_sequence_013.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
|
|
|
@ -22,22 +22,17 @@
|
|||
* @file test_sequence_001.c
|
||||
* @brief Test Sequence 001 code.
|
||||
*
|
||||
* @page test_sequence_001 [1] System layer and port interface
|
||||
* @page test_sequence_001 [1] Information
|
||||
*
|
||||
* File: @ref test_sequence_001.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The functionality of the system layer and port interface is tested.
|
||||
* Basic RT functionality is taken for granted or this test suite could
|
||||
* not even be executed. Errors in implementation are detected by
|
||||
* executing this sequence with the state checker enabled
|
||||
* (CH_DBG_STATE_CHECKER=TRUE).
|
||||
* This sequence reports configuration and version information about
|
||||
* the RT kernel.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_001_001
|
||||
* - @subpage test_001_002
|
||||
* - @subpage test_001_003
|
||||
* - @subpage test_001_004
|
||||
* .
|
||||
*/
|
||||
|
||||
|
@ -45,238 +40,190 @@
|
|||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
/* Timer callback for testing system functions in ISR context.*/
|
||||
static void vtcb(void *p) {
|
||||
syssts_t sts;
|
||||
|
||||
(void)p;
|
||||
|
||||
/* Testing normal case.*/
|
||||
chSysLockFromISR();
|
||||
chSysUnlockFromISR();
|
||||
|
||||
/* Reentrant case.*/
|
||||
chSysLockFromISR();
|
||||
sts = chSysGetStatusAndLockX();
|
||||
chSysRestoreStatusX(sts);
|
||||
chSysUnlockFromISR();
|
||||
}
|
||||
#include "ch.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_001_001 [1.1] System integrity functionality
|
||||
* @page test_001_001 [1.1] Kernel Info
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The system self-test functionality is invoked in order to make an
|
||||
* initial system state assessment and for coverage.
|
||||
* The version numbers are reported.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [1.1.1] Testing Ready List integrity.
|
||||
* - [1.1.2] Testing Virtual Timers List integrity.
|
||||
* - [1.1.3] Testing Registry List integrity.
|
||||
* - [1.1.4] Testing Port-defined integrity.
|
||||
* - [1.1.1] Prints the version string.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_001_001_execute(void) {
|
||||
bool result;
|
||||
|
||||
/* [1.1.1] Testing Ready List integrity.*/
|
||||
/* [1.1.1] Prints the version string.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chSysLock();
|
||||
result = chSysIntegrityCheckI(CH_INTEGRITY_RLIST);
|
||||
chSysUnlock();
|
||||
test_assert(result == false, "ready list check failed");
|
||||
}
|
||||
|
||||
/* [1.1.2] Testing Virtual Timers List integrity.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chSysLock();
|
||||
result = chSysIntegrityCheckI(CH_INTEGRITY_VTLIST);
|
||||
chSysUnlock();
|
||||
test_assert(result == false, "virtual timers list check failed");
|
||||
}
|
||||
|
||||
/* [1.1.3] Testing Registry List integrity.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chSysLock();
|
||||
result = chSysIntegrityCheckI(CH_INTEGRITY_REGISTRY);
|
||||
chSysUnlock();
|
||||
test_assert(result == false, "registry list check failed");
|
||||
}
|
||||
|
||||
/* [1.1.4] Testing Port-defined integrity.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
chSysLock();
|
||||
result = chSysIntegrityCheckI(CH_INTEGRITY_PORT);
|
||||
chSysUnlock();
|
||||
test_assert(result == false, "port layer check failed");
|
||||
test_println("*** Product: ChibiOS/RT");
|
||||
test_print("*** Stable Flag: ");
|
||||
test_printn(CH_KERNEL_STABLE);
|
||||
test_println("");
|
||||
test_print("*** Version String: ");
|
||||
test_println(CH_KERNEL_VERSION);
|
||||
test_print("*** Major Number: ");
|
||||
test_printn(CH_KERNEL_MAJOR);
|
||||
test_println("");
|
||||
test_print("*** Minor Number: ");
|
||||
test_printn(CH_KERNEL_MINOR);
|
||||
test_println("");
|
||||
test_print("*** Patch Number: ");
|
||||
test_printn(CH_KERNEL_PATCH);
|
||||
test_println("");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_001_001 = {
|
||||
"System integrity functionality",
|
||||
"Kernel Info",
|
||||
NULL,
|
||||
NULL,
|
||||
test_001_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_001_002 [1.2] Critical zones functionality
|
||||
* @page test_001_002 [1.2] Kernel Settings
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The critical zones API is invoked for coverage.
|
||||
* The static kernel settings are reported.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [1.2.1] Testing chSysGetStatusAndLockX() and
|
||||
* chSysRestoreStatusX(), non reentrant case.
|
||||
* - [1.2.2] Testing chSysGetStatusAndLockX() and
|
||||
* chSysRestoreStatusX(), reentrant case.
|
||||
* - [1.2.3] Testing chSysUnconditionalLock().
|
||||
* - [1.2.4] Testing chSysUnconditionalUnlock().
|
||||
* - [1.2.5] Testing from ISR context using a virtual timer.
|
||||
* - [1.2.1] Prints the configuration options settings.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_001_002_execute(void) {
|
||||
syssts_t sts;
|
||||
virtual_timer_t vt;
|
||||
|
||||
/* [1.2.1] Testing chSysGetStatusAndLockX() and
|
||||
chSysRestoreStatusX(), non reentrant case.*/
|
||||
/* [1.2.1] Prints the configuration options settings.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
sts = chSysGetStatusAndLockX();
|
||||
chSysRestoreStatusX(sts);
|
||||
}
|
||||
|
||||
/* [1.2.2] Testing chSysGetStatusAndLockX() and
|
||||
chSysRestoreStatusX(), reentrant case.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chSysLock();
|
||||
sts = chSysGetStatusAndLockX();
|
||||
chSysRestoreStatusX(sts);
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/* [1.2.3] Testing chSysUnconditionalLock().*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chSysUnconditionalLock();
|
||||
chSysUnconditionalLock();
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/* [1.2.4] Testing chSysUnconditionalUnlock().*/
|
||||
test_set_step(4);
|
||||
{
|
||||
chSysLock();
|
||||
chSysUnconditionalUnlock();
|
||||
chSysUnconditionalUnlock();
|
||||
}
|
||||
|
||||
/* [1.2.5] Testing from ISR context using a virtual timer.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
chVTObjectInit(&vt);
|
||||
chVTSet(&vt, 1, vtcb, NULL);
|
||||
chThdSleep(10);
|
||||
|
||||
test_assert(chVTIsArmed(&vt) == false, "timer still armed");
|
||||
test_print("*** CH_CFG_ST_RESOLUTION: ");
|
||||
test_printn(CH_CFG_ST_RESOLUTION);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_ST_FREQUENCY: ");
|
||||
test_printn(CH_CFG_ST_FREQUENCY);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_ST_TIMEDELTA: ");
|
||||
test_printn(CH_CFG_ST_TIMEDELTA);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_TIME_QUANTUM: ");
|
||||
test_printn(CH_CFG_TIME_QUANTUM);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_MEMCORE_SIZE: ");
|
||||
test_printn(CH_CFG_MEMCORE_SIZE);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_NO_IDLE_THREAD: ");
|
||||
test_printn(CH_CFG_NO_IDLE_THREAD);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_OPTIMIZE_SPEED: ");
|
||||
test_printn(CH_CFG_OPTIMIZE_SPEED);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_TM: ");
|
||||
test_printn(CH_CFG_USE_TM);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_REGISTRY: ");
|
||||
test_printn(CH_CFG_USE_REGISTRY);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_WAITEXIT: ");
|
||||
test_printn(CH_CFG_USE_WAITEXIT);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_SEMAPHORES: ");
|
||||
test_printn(CH_CFG_USE_SEMAPHORES);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_SEMAPHORES_PRI: ");
|
||||
test_printn(CH_CFG_USE_SEMAPHORES_PRIORITY);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MUTEXES: ");
|
||||
test_printn(CH_CFG_USE_MUTEXES);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MUTEXES_RECURS: ");
|
||||
test_printn(CH_CFG_USE_MUTEXES_RECURSIVE);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_CONDVARS: ");
|
||||
test_printn(CH_CFG_USE_CONDVARS);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_CONDVARS_TIMEO: ");
|
||||
test_printn(CH_CFG_USE_CONDVARS_TIMEOUT);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_EVENTS: ");
|
||||
test_printn(CH_CFG_USE_EVENTS);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_EVENTS_TIMEOUT: ");
|
||||
test_printn(CH_CFG_USE_EVENTS_TIMEOUT);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MESSAGES: ");
|
||||
test_printn(CH_CFG_USE_MESSAGES);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MESSAGES_PRI: ");
|
||||
test_printn(CH_CFG_USE_MESSAGES_PRIORITY);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MAILBOXES: ");
|
||||
test_printn(CH_CFG_USE_MAILBOXES);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MEMCORE: ");
|
||||
test_printn(CH_CFG_USE_MEMCORE);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_HEAP: ");
|
||||
test_printn(CH_CFG_USE_HEAP);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_MEMPOOLS: ");
|
||||
test_printn(CH_CFG_USE_MEMPOOLS);
|
||||
test_println("");
|
||||
test_print("*** CH_CFG_USE_DYNAMIC: ");
|
||||
test_printn(CH_CFG_USE_DYNAMIC);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_STATISTICS: ");
|
||||
test_printn(CH_DBG_STATISTICS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_SYSTEM_STATE_CHECK: ");
|
||||
test_printn(CH_DBG_SYSTEM_STATE_CHECK);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_ENABLE_CHECKS: ");
|
||||
test_printn(CH_DBG_ENABLE_CHECKS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_ENABLE_ASSERTS: ");
|
||||
test_printn(CH_DBG_ENABLE_ASSERTS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_TRACE_MASK: ");
|
||||
test_printn(CH_DBG_TRACE_MASK);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_TRACE_BUFFER_SIZE: ");
|
||||
test_printn(CH_DBG_TRACE_BUFFER_SIZE);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_ENABLE_STACK_CHECK: ");
|
||||
test_printn(CH_DBG_ENABLE_STACK_CHECK);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_FILL_THREADS: ");
|
||||
test_printn(CH_DBG_FILL_THREADS);
|
||||
test_println("");
|
||||
test_print("*** CH_DBG_THREADS_PROFILING: ");
|
||||
test_printn(CH_DBG_THREADS_PROFILING);
|
||||
test_println("");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_001_002 = {
|
||||
"Critical zones functionality",
|
||||
"Kernel Settings",
|
||||
NULL,
|
||||
NULL,
|
||||
test_001_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_001_003 [1.3] Interrupts handling functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The interrupts handling API is invoked for coverage.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [1.3.1] Testing chSysSuspend(), chSysDisable() and chSysEnable().
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_001_003_execute(void) {
|
||||
|
||||
/* [1.3.1] Testing chSysSuspend(), chSysDisable() and
|
||||
chSysEnable().*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chSysSuspend();
|
||||
chSysDisable();
|
||||
chSysSuspend();
|
||||
chSysEnable();
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_001_003 = {
|
||||
"Interrupts handling functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
test_001_003_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_001_004 [1.4] System Tick Counter functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The functionality of the API @p chVTGetSystemTimeX() is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [1.4.1] A System Tick Counter increment is expected, the test
|
||||
* simply hangs if it does not happen.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_001_004_execute(void) {
|
||||
|
||||
/* [1.4.1] A System Tick Counter increment is expected, the test
|
||||
simply hangs if it does not happen.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
systime_t time = chVTGetSystemTimeX();
|
||||
while (time == chVTGetSystemTimeX()) {
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_001_004 = {
|
||||
"System Tick Counter functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
test_001_004_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief System layer and port interface.
|
||||
* @brief Information.
|
||||
*/
|
||||
const testcase_t * const test_sequence_001[] = {
|
||||
&test_001_001,
|
||||
&test_001_002,
|
||||
&test_001_003,
|
||||
&test_001_004,
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -22,13 +22,16 @@
|
|||
* @file test_sequence_002.c
|
||||
* @brief Test Sequence 002 code.
|
||||
*
|
||||
* @page test_sequence_002 [2] Threads Functionality
|
||||
* @page test_sequence_002 [2] System layer and port interface
|
||||
*
|
||||
* File: @ref test_sequence_002.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/RT functionalities related to
|
||||
* threading.
|
||||
* The functionality of the system layer and port interface is tested.
|
||||
* Basic RT functionality is taken for granted or this test suite could
|
||||
* not even be executed. Errors in implementation are detected by
|
||||
* executing this sequence with the state checker enabled
|
||||
* (CH_DBG_STATE_CHECKER=TRUE).
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_002_001
|
||||
|
@ -42,9 +45,21 @@
|
|||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
static THD_FUNCTION(thread, p) {
|
||||
/* Timer callback for testing system functions in ISR context.*/
|
||||
static void vtcb(void *p) {
|
||||
syssts_t sts;
|
||||
|
||||
test_emit_token(*(char *)p);
|
||||
(void)p;
|
||||
|
||||
/* Testing normal case.*/
|
||||
chSysLockFromISR();
|
||||
chSysUnlockFromISR();
|
||||
|
||||
/* Reentrant case.*/
|
||||
chSysLockFromISR();
|
||||
sts = chSysGetStatusAndLockX();
|
||||
chSysRestoreStatusX(sts);
|
||||
chSysUnlockFromISR();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -52,293 +67,216 @@ static THD_FUNCTION(thread, p) {
|
|||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_002_001 [2.1] Thread Sleep functionality
|
||||
* @page test_002_001 [2.1] System integrity functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The functionality of @p chThdSleep() and derivatives is tested.
|
||||
* The system self-test functionality is invoked in order to make an
|
||||
* initial system state assessment and for coverage.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [2.1.1] The current system time is read then a sleep is performed
|
||||
* for 100 system ticks and on exit the system time is verified
|
||||
* again.
|
||||
* - [2.1.2] The current system time is read then a sleep is performed
|
||||
* for 100000 microseconds and on exit the system time is verified
|
||||
* again.
|
||||
* - [2.1.3] The current system time is read then a sleep is performed
|
||||
* for 100 milliseconds and on exit the system time is verified
|
||||
* again.
|
||||
* - [2.1.4] The current system time is read then a sleep is performed
|
||||
* for 1 second and on exit the system time is verified again.
|
||||
* - [2.1.5] Function chThdSleepUntil() is tested with a timeline of
|
||||
* "now" + 100 ticks.
|
||||
* - [2.1.1] Testing Ready List integrity.
|
||||
* - [2.1.2] Testing Virtual Timers List integrity.
|
||||
* - [2.1.3] Testing Registry List integrity.
|
||||
* - [2.1.4] Testing Port-defined integrity.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_002_001_execute(void) {
|
||||
systime_t time;
|
||||
bool result;
|
||||
|
||||
/* [2.1.1] The current system time is read then a sleep is performed
|
||||
for 100 system ticks and on exit the system time is verified
|
||||
again.*/
|
||||
/* [2.1.1] Testing Ready List integrity.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleep(100);
|
||||
test_assert_time_window(time + 100,
|
||||
time + 100 + CH_CFG_ST_TIMEDELTA + 1,
|
||||
"out of time window");
|
||||
chSysLock();
|
||||
result = chSysIntegrityCheckI(CH_INTEGRITY_RLIST);
|
||||
chSysUnlock();
|
||||
test_assert(result == false, "ready list check failed");
|
||||
}
|
||||
|
||||
/* [2.1.2] The current system time is read then a sleep is performed
|
||||
for 100000 microseconds and on exit the system time is verified
|
||||
again.*/
|
||||
/* [2.1.2] Testing Virtual Timers List integrity.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepMicroseconds(100000);
|
||||
test_assert_time_window(time + US2ST(100000),
|
||||
time + US2ST(100000) + CH_CFG_ST_TIMEDELTA + 1,
|
||||
"out of time window");
|
||||
chSysLock();
|
||||
result = chSysIntegrityCheckI(CH_INTEGRITY_VTLIST);
|
||||
chSysUnlock();
|
||||
test_assert(result == false, "virtual timers list check failed");
|
||||
}
|
||||
|
||||
/* [2.1.3] The current system time is read then a sleep is performed
|
||||
for 100 milliseconds and on exit the system time is verified
|
||||
again.*/
|
||||
/* [2.1.3] Testing Registry List integrity.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepMilliseconds(100);
|
||||
test_assert_time_window(time + MS2ST(100),
|
||||
time + MS2ST(100) + CH_CFG_ST_TIMEDELTA + 1,
|
||||
"out of time window");
|
||||
chSysLock();
|
||||
result = chSysIntegrityCheckI(CH_INTEGRITY_REGISTRY);
|
||||
chSysUnlock();
|
||||
test_assert(result == false, "registry list check failed");
|
||||
}
|
||||
|
||||
/* [2.1.4] The current system time is read then a sleep is performed
|
||||
for 1 second and on exit the system time is verified again.*/
|
||||
/* [2.1.4] Testing Port-defined integrity.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepSeconds(1);
|
||||
test_assert_time_window(time + S2ST(1),
|
||||
time + S2ST(1) + CH_CFG_ST_TIMEDELTA + 1,
|
||||
"out of time window");
|
||||
}
|
||||
|
||||
/* [2.1.5] Function chThdSleepUntil() is tested with a timeline of
|
||||
"now" + 100 ticks.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepUntil(time + 100);
|
||||
test_assert_time_window(time + 100,
|
||||
time + 100 + CH_CFG_ST_TIMEDELTA + 1,
|
||||
"out of time window");
|
||||
chSysLock();
|
||||
result = chSysIntegrityCheckI(CH_INTEGRITY_PORT);
|
||||
chSysUnlock();
|
||||
test_assert(result == false, "port layer check failed");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_002_001 = {
|
||||
"Thread Sleep functionality",
|
||||
"System integrity functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
test_002_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_002_002 [2.2] Ready List functionality, threads priority order
|
||||
* @page test_002_002 [2.2] Critical zones functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads, are enqueued in the ready list and atomically
|
||||
* executed. The test expects the threads to perform their operations
|
||||
* in correct priority order regardless of the initial order.
|
||||
* The critical zones API is invoked for coverage.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [2.2.1] Creating 5 threads with increasing priority, execution
|
||||
* sequence is tested.
|
||||
* - [2.2.2] Creating 5 threads with decreasing priority, execution
|
||||
* sequence is tested.
|
||||
* - [2.2.3] Creating 5 threads with pseudo-random priority, execution
|
||||
* sequence is tested.
|
||||
* - [2.2.1] Testing chSysGetStatusAndLockX() and
|
||||
* chSysRestoreStatusX(), non reentrant case.
|
||||
* - [2.2.2] Testing chSysGetStatusAndLockX() and
|
||||
* chSysRestoreStatusX(), reentrant case.
|
||||
* - [2.2.3] Testing chSysUnconditionalLock().
|
||||
* - [2.2.4] Testing chSysUnconditionalUnlock().
|
||||
* - [2.2.5] Testing from ISR context using a virtual timer.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_002_002_execute(void) {
|
||||
syssts_t sts;
|
||||
virtual_timer_t vt;
|
||||
|
||||
/* [2.2.1] Creating 5 threads with increasing priority, execution
|
||||
sequence is tested.*/
|
||||
/* [2.2.1] Testing chSysGetStatusAndLockX() and
|
||||
chSysRestoreStatusX(), non reentrant case.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
|
||||
test_wait_threads();
|
||||
test_assert_sequence("ABCDE", "invalid sequence");
|
||||
sts = chSysGetStatusAndLockX();
|
||||
chSysRestoreStatusX(sts);
|
||||
}
|
||||
|
||||
/* [2.2.2] Creating 5 threads with decreasing priority, execution
|
||||
sequence is tested.*/
|
||||
/* [2.2.2] Testing chSysGetStatusAndLockX() and
|
||||
chSysRestoreStatusX(), reentrant case.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
|
||||
test_wait_threads();
|
||||
test_assert_sequence("ABCDE", "invalid sequence");
|
||||
chSysLock();
|
||||
sts = chSysGetStatusAndLockX();
|
||||
chSysRestoreStatusX(sts);
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/* [2.2.3] Creating 5 threads with pseudo-random priority, execution
|
||||
sequence is tested.*/
|
||||
/* [2.2.3] Testing chSysUnconditionalLock().*/
|
||||
test_set_step(3);
|
||||
{
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
|
||||
test_wait_threads();
|
||||
test_assert_sequence("ABCDE", "invalid sequence");
|
||||
chSysUnconditionalLock();
|
||||
chSysUnconditionalLock();
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/* [2.2.4] Testing chSysUnconditionalUnlock().*/
|
||||
test_set_step(4);
|
||||
{
|
||||
chSysLock();
|
||||
chSysUnconditionalUnlock();
|
||||
chSysUnconditionalUnlock();
|
||||
}
|
||||
|
||||
/* [2.2.5] Testing from ISR context using a virtual timer.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
chVTObjectInit(&vt);
|
||||
chVTSet(&vt, 1, vtcb, NULL);
|
||||
chThdSleep(10);
|
||||
|
||||
test_assert(chVTIsArmed(&vt) == false, "timer still armed");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_002_002 = {
|
||||
"Ready List functionality, threads priority order",
|
||||
"Critical zones functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
test_002_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_002_003 [2.3] Priority change test
|
||||
* @page test_002_003 [2.3] Interrupts handling functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A series of priority changes are performed on the current thread in
|
||||
* order to verify that the priority change happens as expected.
|
||||
* The interrupts handling API is invoked for coverage.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [2.3.1] Thread priority is increased by one then a check is
|
||||
* performed.
|
||||
* - [2.3.2] Thread priority is returned to the previous value then a
|
||||
* check is performed.
|
||||
* - [2.3.1] Testing chSysSuspend(), chSysDisable() and chSysEnable().
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_002_003_execute(void) {
|
||||
tprio_t prio, p1;
|
||||
|
||||
/* [2.3.1] Thread priority is increased by one then a check is
|
||||
performed.*/
|
||||
/* [2.3.1] Testing chSysSuspend(), chSysDisable() and
|
||||
chSysEnable().*/
|
||||
test_set_step(1);
|
||||
{
|
||||
prio = chThdGetPriorityX();
|
||||
p1 = chThdSetPriority(prio + 1);
|
||||
test_assert(p1 == prio, "unexpected returned priority level");
|
||||
test_assert(chThdGetPriorityX() == prio + 1, "unexpected priority level");
|
||||
}
|
||||
|
||||
/* [2.3.2] Thread priority is returned to the previous value then a
|
||||
check is performed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
p1 = chThdSetPriority(p1);
|
||||
test_assert(p1 == prio + 1, "unexpected returned priority level");
|
||||
test_assert(chThdGetPriorityX() == prio, "unexpected priority level");
|
||||
chSysSuspend();
|
||||
chSysDisable();
|
||||
chSysSuspend();
|
||||
chSysEnable();
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_002_003 = {
|
||||
"Priority change test",
|
||||
"Interrupts handling functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
test_002_003_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_002_004 [2.4] Priority change test with Priority Inheritance
|
||||
* @page test_002_004 [2.4] System Tick Counter functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A series of priority changes are performed on the current thread in
|
||||
* order to verify that the priority change happens as expected.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_MUTEXES
|
||||
* .
|
||||
* The functionality of the API @p chVTGetSystemTimeX() is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [2.4.1] Simulating a priority boost situation (prio > realprio).
|
||||
* - [2.4.2] Raising thread priority above original priority but below
|
||||
* the boosted level.
|
||||
* - [2.4.3] Raising thread priority above the boosted level.
|
||||
* - [2.4.4] Restoring original conditions.
|
||||
* - [2.4.1] A System Tick Counter increment is expected, the test
|
||||
* simply hangs if it does not happen.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_002_004_execute(void) {
|
||||
tprio_t prio, p1;
|
||||
|
||||
/* [2.4.1] Simulating a priority boost situation (prio > realprio).*/
|
||||
/* [2.4.1] A System Tick Counter increment is expected, the test
|
||||
simply hangs if it does not happen.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
prio = chThdGetPriorityX();
|
||||
chThdGetSelfX()->prio += 2;
|
||||
test_assert(chThdGetPriorityX() == prio + 2, "unexpected priority level");
|
||||
}
|
||||
|
||||
/* [2.4.2] Raising thread priority above original priority but below
|
||||
the boosted level.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
p1 = chThdSetPriority(prio + 1);
|
||||
test_assert(p1 == prio, "unexpected returned priority level");
|
||||
test_assert(chThdGetSelfX()->prio == prio + 2, "unexpected priority level");
|
||||
test_assert(chThdGetSelfX()->realprio == prio + 1, "unexpected returned real priority level");
|
||||
}
|
||||
|
||||
/* [2.4.3] Raising thread priority above the boosted level.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
p1 = chThdSetPriority(prio + 3);
|
||||
test_assert(p1 == prio + 1, "unexpected returned priority level");
|
||||
test_assert(chThdGetSelfX()->prio == prio + 3, "unexpected priority level");
|
||||
test_assert(chThdGetSelfX()->realprio == prio + 3, "unexpected real priority level");
|
||||
}
|
||||
|
||||
/* [2.4.4] Restoring original conditions.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
chSysLock();
|
||||
chThdGetSelfX()->prio = prio;
|
||||
chThdGetSelfX()->realprio = prio;
|
||||
chSysUnlock();
|
||||
systime_t time = chVTGetSystemTimeX();
|
||||
while (time == chVTGetSystemTimeX()) {
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_002_004 = {
|
||||
"Priority change test with Priority Inheritance",
|
||||
"System Tick Counter functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
test_002_004_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_MUTEXES */
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Threads Functionality.
|
||||
* @brief System layer and port interface.
|
||||
*/
|
||||
const testcase_t * const test_sequence_002[] = {
|
||||
&test_002_001,
|
||||
&test_002_002,
|
||||
&test_002_003,
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
&test_002_004,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -22,16 +22,19 @@
|
|||
* @file test_sequence_003.c
|
||||
* @brief Test Sequence 003 code.
|
||||
*
|
||||
* @page test_sequence_003 [3] Suspend/Resume
|
||||
* @page test_sequence_003 [3] Threads Functionality
|
||||
*
|
||||
* File: @ref test_sequence_003.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/RT functionalities related to
|
||||
* threads suspend/resume.
|
||||
* threading.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_003_001
|
||||
* - @subpage test_003_002
|
||||
* - @subpage test_003_003
|
||||
* - @subpage test_003_004
|
||||
* .
|
||||
*/
|
||||
|
||||
|
@ -39,14 +42,8 @@
|
|||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
static thread_reference_t tr1;
|
||||
static THD_FUNCTION(thread, p) {
|
||||
|
||||
static THD_FUNCTION(thread1, p) {
|
||||
|
||||
chSysLock();
|
||||
chThdResumeI(&tr1, MSG_OK);
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
test_emit_token(*(char *)p);
|
||||
}
|
||||
|
||||
|
@ -55,76 +52,293 @@ static THD_FUNCTION(thread1, p) {
|
|||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_003_001 [3.1] Suspend and Resume functionality
|
||||
* @page test_003_001 [3.1] Thread Sleep functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
|
||||
* tested.
|
||||
* The functionality of @p chThdSleep() and derivatives is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [3.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
* is remotely resumed with message @p MSG_OK. On return the message
|
||||
* and the state of the reference are tested.
|
||||
* - [3.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
* is not resumed so a timeout must occur. On return the message and
|
||||
* the state of the reference are tested.
|
||||
* - [3.1.1] The current system time is read then a sleep is performed
|
||||
* for 100 system ticks and on exit the system time is verified
|
||||
* again.
|
||||
* - [3.1.2] The current system time is read then a sleep is performed
|
||||
* for 100000 microseconds and on exit the system time is verified
|
||||
* again.
|
||||
* - [3.1.3] The current system time is read then a sleep is performed
|
||||
* for 100 milliseconds and on exit the system time is verified
|
||||
* again.
|
||||
* - [3.1.4] The current system time is read then a sleep is performed
|
||||
* for 1 second and on exit the system time is verified again.
|
||||
* - [3.1.5] Function chThdSleepUntil() is tested with a timeline of
|
||||
* "now" + 100 ticks.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_003_001_setup(void) {
|
||||
tr1 = NULL;
|
||||
}
|
||||
|
||||
static void test_003_001_execute(void) {
|
||||
systime_t time;
|
||||
msg_t msg;
|
||||
|
||||
/* [3.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
is remotely resumed with message @p MSG_OK. On return the message
|
||||
and the state of the reference are tested.*/
|
||||
/* [3.1.1] The current system time is read then a sleep is performed
|
||||
for 100 system ticks and on exit the system time is verified
|
||||
again.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread1, "A");
|
||||
chSysLock();
|
||||
msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE);
|
||||
chSysUnlock();
|
||||
test_assert(NULL == tr1, "not NULL");
|
||||
test_assert(MSG_OK == msg,"wrong returned message");
|
||||
test_wait_threads();
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleep(100);
|
||||
test_assert_time_window(time + 100,
|
||||
time + 100 + CH_CFG_ST_TIMEDELTA + 1,
|
||||
"out of time window");
|
||||
}
|
||||
|
||||
/* [3.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
is not resumed so a timeout must occur. On return the message and
|
||||
the state of the reference are tested.*/
|
||||
/* [3.1.2] The current system time is read then a sleep is performed
|
||||
for 100000 microseconds and on exit the system time is verified
|
||||
again.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chSysLock();
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chThdSuspendTimeoutS(&tr1, MS2ST(1000));
|
||||
chSysUnlock();
|
||||
test_assert_time_window(time + MS2ST(1000),
|
||||
time + MS2ST(1000) + CH_CFG_ST_TIMEDELTA + 1,
|
||||
chThdSleepMicroseconds(100000);
|
||||
test_assert_time_window(time + US2ST(100000),
|
||||
time + US2ST(100000) + CH_CFG_ST_TIMEDELTA + 1,
|
||||
"out of time window");
|
||||
}
|
||||
|
||||
/* [3.1.3] The current system time is read then a sleep is performed
|
||||
for 100 milliseconds and on exit the system time is verified
|
||||
again.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepMilliseconds(100);
|
||||
test_assert_time_window(time + MS2ST(100),
|
||||
time + MS2ST(100) + CH_CFG_ST_TIMEDELTA + 1,
|
||||
"out of time window");
|
||||
}
|
||||
|
||||
/* [3.1.4] The current system time is read then a sleep is performed
|
||||
for 1 second and on exit the system time is verified again.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepSeconds(1);
|
||||
test_assert_time_window(time + S2ST(1),
|
||||
time + S2ST(1) + CH_CFG_ST_TIMEDELTA + 1,
|
||||
"out of time window");
|
||||
}
|
||||
|
||||
/* [3.1.5] Function chThdSleepUntil() is tested with a timeline of
|
||||
"now" + 100 ticks.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepUntil(time + 100);
|
||||
test_assert_time_window(time + 100,
|
||||
time + 100 + CH_CFG_ST_TIMEDELTA + 1,
|
||||
"out of time window");
|
||||
test_assert(NULL == tr1, "not NULL");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong returned message");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_003_001 = {
|
||||
"Suspend and Resume functionality",
|
||||
test_003_001_setup,
|
||||
"Thread Sleep functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
test_003_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_003_002 [3.2] Ready List functionality, threads priority order
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads, are enqueued in the ready list and atomically
|
||||
* executed. The test expects the threads to perform their operations
|
||||
* in correct priority order regardless of the initial order.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [3.2.1] Creating 5 threads with increasing priority, execution
|
||||
* sequence is tested.
|
||||
* - [3.2.2] Creating 5 threads with decreasing priority, execution
|
||||
* sequence is tested.
|
||||
* - [3.2.3] Creating 5 threads with pseudo-random priority, execution
|
||||
* sequence is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_003_002_execute(void) {
|
||||
|
||||
/* [3.2.1] Creating 5 threads with increasing priority, execution
|
||||
sequence is tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
|
||||
test_wait_threads();
|
||||
test_assert_sequence("ABCDE", "invalid sequence");
|
||||
}
|
||||
|
||||
/* [3.2.2] Creating 5 threads with decreasing priority, execution
|
||||
sequence is tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
|
||||
test_wait_threads();
|
||||
test_assert_sequence("ABCDE", "invalid sequence");
|
||||
}
|
||||
|
||||
/* [3.2.3] Creating 5 threads with pseudo-random priority, execution
|
||||
sequence is tested.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
|
||||
test_wait_threads();
|
||||
test_assert_sequence("ABCDE", "invalid sequence");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_003_002 = {
|
||||
"Ready List functionality, threads priority order",
|
||||
NULL,
|
||||
NULL,
|
||||
test_003_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_003_003 [3.3] Priority change test
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A series of priority changes are performed on the current thread in
|
||||
* order to verify that the priority change happens as expected.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [3.3.1] Thread priority is increased by one then a check is
|
||||
* performed.
|
||||
* - [3.3.2] Thread priority is returned to the previous value then a
|
||||
* check is performed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_003_003_execute(void) {
|
||||
tprio_t prio, p1;
|
||||
|
||||
/* [3.3.1] Thread priority is increased by one then a check is
|
||||
performed.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
prio = chThdGetPriorityX();
|
||||
p1 = chThdSetPriority(prio + 1);
|
||||
test_assert(p1 == prio, "unexpected returned priority level");
|
||||
test_assert(chThdGetPriorityX() == prio + 1, "unexpected priority level");
|
||||
}
|
||||
|
||||
/* [3.3.2] Thread priority is returned to the previous value then a
|
||||
check is performed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
p1 = chThdSetPriority(p1);
|
||||
test_assert(p1 == prio + 1, "unexpected returned priority level");
|
||||
test_assert(chThdGetPriorityX() == prio, "unexpected priority level");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_003_003 = {
|
||||
"Priority change test",
|
||||
NULL,
|
||||
NULL,
|
||||
test_003_003_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_003_004 [3.4] Priority change test with Priority Inheritance
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A series of priority changes are performed on the current thread in
|
||||
* order to verify that the priority change happens as expected.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_MUTEXES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [3.4.1] Simulating a priority boost situation (prio > realprio).
|
||||
* - [3.4.2] Raising thread priority above original priority but below
|
||||
* the boosted level.
|
||||
* - [3.4.3] Raising thread priority above the boosted level.
|
||||
* - [3.4.4] Restoring original conditions.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_003_004_execute(void) {
|
||||
tprio_t prio, p1;
|
||||
|
||||
/* [3.4.1] Simulating a priority boost situation (prio > realprio).*/
|
||||
test_set_step(1);
|
||||
{
|
||||
prio = chThdGetPriorityX();
|
||||
chThdGetSelfX()->prio += 2;
|
||||
test_assert(chThdGetPriorityX() == prio + 2, "unexpected priority level");
|
||||
}
|
||||
|
||||
/* [3.4.2] Raising thread priority above original priority but below
|
||||
the boosted level.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
p1 = chThdSetPriority(prio + 1);
|
||||
test_assert(p1 == prio, "unexpected returned priority level");
|
||||
test_assert(chThdGetSelfX()->prio == prio + 2, "unexpected priority level");
|
||||
test_assert(chThdGetSelfX()->realprio == prio + 1, "unexpected returned real priority level");
|
||||
}
|
||||
|
||||
/* [3.4.3] Raising thread priority above the boosted level.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
p1 = chThdSetPriority(prio + 3);
|
||||
test_assert(p1 == prio + 1, "unexpected returned priority level");
|
||||
test_assert(chThdGetSelfX()->prio == prio + 3, "unexpected priority level");
|
||||
test_assert(chThdGetSelfX()->realprio == prio + 3, "unexpected real priority level");
|
||||
}
|
||||
|
||||
/* [3.4.4] Restoring original conditions.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
chSysLock();
|
||||
chThdGetSelfX()->prio = prio;
|
||||
chThdGetSelfX()->realprio = prio;
|
||||
chSysUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_003_004 = {
|
||||
"Priority change test with Priority Inheritance",
|
||||
NULL,
|
||||
NULL,
|
||||
test_003_004_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_MUTEXES */
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Suspend/Resume.
|
||||
* @brief Threads Functionality.
|
||||
*/
|
||||
const testcase_t * const test_sequence_003[] = {
|
||||
&test_003_001,
|
||||
&test_003_002,
|
||||
&test_003_003,
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
&test_003_004,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -22,66 +22,32 @@
|
|||
* @file test_sequence_004.c
|
||||
* @brief Test Sequence 004 code.
|
||||
*
|
||||
* @page test_sequence_004 [4] Counter and Binary Semaphores
|
||||
* @page test_sequence_004 [4] Suspend/Resume
|
||||
*
|
||||
* File: @ref test_sequence_004.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/RT functionalities related to
|
||||
* counter semaphores.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
* threads suspend/resume.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_004_001
|
||||
* - @subpage test_004_002
|
||||
* - @subpage test_004_003
|
||||
* - @subpage test_004_004
|
||||
* - @subpage test_004_005
|
||||
* - @subpage test_004_006
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
static semaphore_t sem1;
|
||||
static thread_reference_t tr1;
|
||||
|
||||
static THD_FUNCTION(thread1, p) {
|
||||
|
||||
chSemWait(&sem1);
|
||||
test_emit_token(*(char *)p);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread2, p) {
|
||||
|
||||
(void)p;
|
||||
chThdSleepMilliseconds(50);
|
||||
chSysLock();
|
||||
chSemSignalI(&sem1); /* For coverage reasons */
|
||||
chThdResumeI(&tr1, MSG_OK);
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread3, p) {
|
||||
|
||||
(void)p;
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread4, p) {
|
||||
|
||||
chBSemSignal((binary_semaphore_t *)p);
|
||||
test_emit_token(*(char *)p);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -89,420 +55,76 @@ static THD_FUNCTION(thread4, p) {
|
|||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_004_001 [4.1] Semaphore primitives, no state change
|
||||
* @page test_004_001 [4.1] Suspend and Resume functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Wait, Signal and Reset primitives are tested. The testing thread
|
||||
* does not trigger a state change.
|
||||
* The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
|
||||
* tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.1.1] The function chSemWait() is invoked, after return the
|
||||
* counter and the returned message are tested.
|
||||
* - [4.1.2] The function chSemSignal() is invoked, after return the
|
||||
* counter is tested.
|
||||
* - [4.1.3] The function chSemReset() is invoked, after return the
|
||||
* counter is tested.
|
||||
* - [4.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
* is remotely resumed with message @p MSG_OK. On return the message
|
||||
* and the state of the reference are tested.
|
||||
* - [4.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
* is not resumed so a timeout must occur. On return the message and
|
||||
* the state of the reference are tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_004_001_setup(void) {
|
||||
chSemObjectInit(&sem1, 1);
|
||||
}
|
||||
|
||||
static void test_004_001_teardown(void) {
|
||||
chSemReset(&sem1, 0);
|
||||
tr1 = NULL;
|
||||
}
|
||||
|
||||
static void test_004_001_execute(void) {
|
||||
systime_t time;
|
||||
msg_t msg;
|
||||
|
||||
/* [4.1.1] The function chSemWait() is invoked, after return the
|
||||
counter and the returned message are tested.*/
|
||||
/* [4.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
is remotely resumed with message @p MSG_OK. On return the message
|
||||
and the state of the reference are tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
msg_t msg;
|
||||
|
||||
msg = chSemWait(&sem1);
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_OK == msg, "wrong returned message");
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread1, "A");
|
||||
chSysLock();
|
||||
msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE);
|
||||
chSysUnlock();
|
||||
test_assert(NULL == tr1, "not NULL");
|
||||
test_assert(MSG_OK == msg,"wrong returned message");
|
||||
test_wait_threads();
|
||||
}
|
||||
|
||||
/* [4.1.2] The function chSemSignal() is invoked, after return the
|
||||
counter is tested.*/
|
||||
/* [4.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
is not resumed so a timeout must occur. On return the message and
|
||||
the state of the reference are tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chSemSignal(&sem1);
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 1, "wrong counter value");
|
||||
}
|
||||
|
||||
/* [4.1.3] The function chSemReset() is invoked, after return the
|
||||
counter is tested.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chSemReset(&sem1, 2);
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value");
|
||||
chSysLock();
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chThdSuspendTimeoutS(&tr1, MS2ST(1000));
|
||||
chSysUnlock();
|
||||
test_assert_time_window(time + MS2ST(1000),
|
||||
time + MS2ST(1000) + CH_CFG_ST_TIMEDELTA + 1,
|
||||
"out of time window");
|
||||
test_assert(NULL == tr1, "not NULL");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong returned message");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_004_001 = {
|
||||
"Semaphore primitives, no state change",
|
||||
"Suspend and Resume functionality",
|
||||
test_004_001_setup,
|
||||
test_004_001_teardown,
|
||||
NULL,
|
||||
test_004_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_004_002 [4.2] Semaphore enqueuing test
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads with randomized priorities are enqueued to a semaphore
|
||||
* then awakened one at time. The test expects that the threads reach
|
||||
* their goal in FIFO order or priority order depending on the @p
|
||||
* CH_CFG_USE_SEMAPHORES_PRIORITY configuration setting.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.2.1] Five threads are created with mixed priority levels (not
|
||||
* increasing nor decreasing). Threads enqueue on a semaphore
|
||||
* initialized to zero.
|
||||
* - [4.2.2] The semaphore is signaled 5 times. The thread activation
|
||||
* sequence is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_004_002_setup(void) {
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static void test_004_002_execute(void) {
|
||||
|
||||
/* [4.2.1] Five threads are created with mixed priority levels (not
|
||||
increasing nor decreasing). Threads enqueue on a semaphore
|
||||
initialized to zero.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, thread1, "A");
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+1, thread1, "B");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, thread1, "C");
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+4, thread1, "D");
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+2, thread1, "E");
|
||||
}
|
||||
|
||||
/* [4.2.2] The semaphore is signaled 5 times. The thread activation
|
||||
sequence is tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chSemSignal(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
test_wait_threads();
|
||||
#if CH_CFG_USE_SEMAPHORES_PRIORITY
|
||||
test_assert_sequence("ADCEB", "invalid sequence");
|
||||
#else
|
||||
test_assert_sequence("ABCDE", "invalid sequence");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_004_002 = {
|
||||
"Semaphore enqueuing test",
|
||||
test_004_002_setup,
|
||||
NULL,
|
||||
test_004_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_004_003 [4.3] Semaphore timeout test
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The three possible semaphore waiting modes (do not wait, wait with
|
||||
* timeout, wait without timeout) are explored. The test expects that
|
||||
* the semaphore wait function returns the correct value in each of the
|
||||
* above scenario and that the semaphore structure status is correct
|
||||
* after each operation.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.3.1] Testing special case TIME_IMMEDIATE.
|
||||
* - [4.3.2] Testing non-timeout condition.
|
||||
* - [4.3.3] Testing timeout condition.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_004_003_setup(void) {
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static void test_004_003_execute(void) {
|
||||
unsigned i;
|
||||
systime_t target_time;
|
||||
msg_t msg;
|
||||
|
||||
/* [4.3.1] Testing special case TIME_IMMEDIATE.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
msg = chSemWaitTimeout(&sem1, TIME_IMMEDIATE);
|
||||
test_assert(msg == MSG_TIMEOUT, "wrong wake-up message");
|
||||
test_assert(queue_isempty(&sem1.queue), "queue not empty");
|
||||
test_assert(sem1.cnt == 0, "counter not zero");
|
||||
}
|
||||
|
||||
/* [4.3.2] Testing non-timeout condition.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
thread2, 0);
|
||||
msg = chSemWaitTimeout(&sem1, MS2ST(500));
|
||||
test_wait_threads();
|
||||
test_assert(msg == MSG_OK, "wrong wake-up message");
|
||||
test_assert(queue_isempty(&sem1.queue), "queue not empty");
|
||||
test_assert(sem1.cnt == 0, "counter not zero");
|
||||
}
|
||||
|
||||
/* [4.3.3] Testing timeout condition.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
target_time = test_wait_tick() + MS2ST(5 * 50);
|
||||
for (i = 0; i < 5; i++) {
|
||||
test_emit_token('A' + i);
|
||||
msg = chSemWaitTimeout(&sem1, MS2ST(50));
|
||||
test_assert(msg == MSG_TIMEOUT, "wrong wake-up message");
|
||||
test_assert(queue_isempty(&sem1.queue), "queue not empty");
|
||||
test_assert(sem1.cnt == 0, "counter not zero");
|
||||
}
|
||||
test_assert_sequence("ABCDE", "invalid sequence");
|
||||
test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
|
||||
"out of time window");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_004_003 = {
|
||||
"Semaphore timeout test",
|
||||
test_004_003_setup,
|
||||
NULL,
|
||||
test_004_003_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_004_004 [4.4] Testing chSemAddCounterI() functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The functon is tested by waking up a thread then the semaphore
|
||||
* counter value is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.4.1] A thread is created, it goes to wait on the semaphore.
|
||||
* - [4.4.2] The semaphore counter is increased by two, it is then
|
||||
* tested to be one, the thread must have completed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_004_004_setup(void) {
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static void test_004_004_execute(void) {
|
||||
|
||||
/* [4.4.1] A thread is created, it goes to wait on the semaphore.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread1, "A");
|
||||
}
|
||||
|
||||
/* [4.4.2] The semaphore counter is increased by two, it is then
|
||||
tested to be one, the thread must have completed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chSysLock();
|
||||
chSemAddCounterI(&sem1, 2);
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
test_wait_threads();
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 1, "invalid counter");
|
||||
test_assert_sequence("A", "invalid sequence");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_004_004 = {
|
||||
"Testing chSemAddCounterI() functionality",
|
||||
test_004_004_setup,
|
||||
NULL,
|
||||
test_004_004_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_004_005 [4.5] Testing chSemWaitSignal() functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This test case explicitly addresses the @p chSemWaitSignal()
|
||||
* function. A thread is created that performs a wait and a signal
|
||||
* operations. The tester thread is awakened from an atomic wait/signal
|
||||
* operation. The test expects that the semaphore wait function returns
|
||||
* the correct value in each of the above scenario and that the
|
||||
* semaphore structure status is correct after each operation.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.5.1] An higher priority thread is created that performs
|
||||
* non-atomical wait and signal operations on a semaphore.
|
||||
* - [4.5.2] The function chSemSignalWait() is invoked by specifying
|
||||
* the same semaphore for the wait and signal phases. The counter
|
||||
* value must be one on exit.
|
||||
* - [4.5.3] The function chSemSignalWait() is invoked again by
|
||||
* specifying the same semaphore for the wait and signal phases. The
|
||||
* counter value must be one on exit.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_004_005_setup(void) {
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static void test_004_005_teardown(void) {
|
||||
test_wait_threads();
|
||||
}
|
||||
|
||||
static void test_004_005_execute(void) {
|
||||
|
||||
/* [4.5.1] An higher priority thread is created that performs
|
||||
non-atomical wait and signal operations on a semaphore.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread3, 0);
|
||||
}
|
||||
|
||||
/* [4.5.2] The function chSemSignalWait() is invoked by specifying
|
||||
the same semaphore for the wait and signal phases. The counter
|
||||
value must be one on exit.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chSemSignalWait(&sem1, &sem1);
|
||||
test_assert(queue_isempty(&sem1.queue), "queue not empty");
|
||||
test_assert(sem1.cnt == 0, "counter not zero");
|
||||
}
|
||||
|
||||
/* [4.5.3] The function chSemSignalWait() is invoked again by
|
||||
specifying the same semaphore for the wait and signal phases. The
|
||||
counter value must be one on exit.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chSemSignalWait(&sem1, &sem1);
|
||||
test_assert(queue_isempty(&sem1.queue), "queue not empty");
|
||||
test_assert(sem1.cnt == 0, "counter not zero");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_004_005 = {
|
||||
"Testing chSemWaitSignal() functionality",
|
||||
test_004_005_setup,
|
||||
test_004_005_teardown,
|
||||
test_004_005_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_004_006 [4.6] Testing Binary Semaphores special case
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This test case tests the binary semaphores functionality. The test
|
||||
* both checks the binary semaphore status and the expected status of
|
||||
* the underlying counting semaphore.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.6.1] Creating a binary semaphore in "taken" state, the state is
|
||||
* checked.
|
||||
* - [4.6.2] Resetting the binary semaphore in "taken" state, the state
|
||||
* must not change.
|
||||
* - [4.6.3] Starting a signaler thread at a lower priority.
|
||||
* - [4.6.4] Waiting for the binary semaphore to be signaled, the
|
||||
* semaphore is expected to be taken.
|
||||
* - [4.6.5] Signaling the binary semaphore, checking the binary
|
||||
* semaphore state to be "not taken" and the underlying counter
|
||||
* semaphore counter to be one.
|
||||
* - [4.6.6] Signaling the binary semaphore again, the internal state
|
||||
* must not change from "not taken".
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_004_006_teardown(void) {
|
||||
test_wait_threads();
|
||||
}
|
||||
|
||||
static void test_004_006_execute(void) {
|
||||
binary_semaphore_t bsem;
|
||||
msg_t msg;
|
||||
|
||||
/* [4.6.1] Creating a binary semaphore in "taken" state, the state is
|
||||
checked.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chBSemObjectInit(&bsem, true);
|
||||
test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken");
|
||||
}
|
||||
|
||||
/* [4.6.2] Resetting the binary semaphore in "taken" state, the state
|
||||
must not change.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chBSemReset(&bsem, true);
|
||||
test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken");
|
||||
}
|
||||
|
||||
/* [4.6.3] Starting a signaler thread at a lower priority.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE,
|
||||
chThdGetPriorityX()-1, thread4, &bsem);
|
||||
}
|
||||
|
||||
/* [4.6.4] Waiting for the binary semaphore to be signaled, the
|
||||
semaphore is expected to be taken.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
msg = chBSemWait(&bsem);
|
||||
test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken");
|
||||
test_assert(msg == MSG_OK, "unexpected message");
|
||||
}
|
||||
|
||||
/* [4.6.5] Signaling the binary semaphore, checking the binary
|
||||
semaphore state to be "not taken" and the underlying counter
|
||||
semaphore counter to be one.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
chBSemSignal(&bsem);
|
||||
test_assert_lock(chBSemGetStateI(&bsem) ==false, "still taken");
|
||||
test_assert_lock(chSemGetCounterI(&bsem.sem) == 1, "unexpected counter");
|
||||
}
|
||||
|
||||
/* [4.6.6] Signaling the binary semaphore again, the internal state
|
||||
must not change from "not taken".*/
|
||||
test_set_step(6);
|
||||
{
|
||||
chBSemSignal(&bsem);
|
||||
test_assert_lock(chBSemGetStateI(&bsem) == false, "taken");
|
||||
test_assert_lock(chSemGetCounterI(&bsem.sem) == 1, "unexpected counter");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_004_006 = {
|
||||
"Testing Binary Semaphores special case",
|
||||
NULL,
|
||||
test_004_006_teardown,
|
||||
test_004_006_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Counter and Binary Semaphores.
|
||||
* @brief Suspend/Resume.
|
||||
*/
|
||||
const testcase_t * const test_sequence_004[] = {
|
||||
&test_004_001,
|
||||
&test_004_002,
|
||||
&test_004_003,
|
||||
&test_004_004,
|
||||
&test_004_005,
|
||||
&test_004_006,
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -22,56 +22,37 @@
|
|||
* @file test_sequence_007.c
|
||||
* @brief Test Sequence 007 code.
|
||||
*
|
||||
* @page test_sequence_007 [7] Event Sources and Event Flags
|
||||
* @page test_sequence_007 [7] Synchronous Messages
|
||||
*
|
||||
* File: @ref test_sequence_007.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the Events subsystem.
|
||||
* This module implements the test sequence for the Synchronous
|
||||
* Messages subsystem.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_EVENTS
|
||||
* - CH_CFG_USE_MESSAGES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_007_001
|
||||
* - @subpage test_007_002
|
||||
* - @subpage test_007_003
|
||||
* - @subpage test_007_004
|
||||
* - @subpage test_007_005
|
||||
* - @subpage test_007_006
|
||||
* - @subpage test_007_007
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
static EVENTSOURCE_DECL(es1);
|
||||
static EVENTSOURCE_DECL(es2);
|
||||
static THD_FUNCTION(msg_thread1, p) {
|
||||
|
||||
static void h1(eventid_t id) {(void)id;test_emit_token('A');}
|
||||
static void h2(eventid_t id) {(void)id;test_emit_token('B');}
|
||||
static void h3(eventid_t id) {(void)id;test_emit_token('C');}
|
||||
static ROMCONST evhandler_t evhndl[] = {h1, h2, h3};
|
||||
|
||||
static THD_FUNCTION(evt_thread3, p) {
|
||||
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtSignal((thread_t *)p, 1);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(evt_thread7, p) {
|
||||
|
||||
(void)p;
|
||||
chEvtBroadcast(&es1);
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtBroadcast(&es2);
|
||||
chMsgSend(p, 'A');
|
||||
chMsgSend(p, 'B');
|
||||
chMsgSend(p, 'C');
|
||||
chMsgSend(p, 'D');
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -79,491 +60,64 @@ static THD_FUNCTION(evt_thread7, p) {
|
|||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_007_001 [7.1] Events registration
|
||||
* @page test_007_001 [7.1] Messages Server loop
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Two event listeners are registered on an event source and then
|
||||
* unregistered in the same order.<br> The test expects that the even
|
||||
* source has listeners after the registrations and after the first
|
||||
* unregistration, then, after the second unegistration, the test
|
||||
* expects no more listeners.
|
||||
* A messenger thread is spawned that sends four messages back to the
|
||||
* tester thread.<br> The test expect to receive the messages in the
|
||||
* correct sequence and to not find a fifth message waiting.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [7.1.1] An Event Source is initialized.
|
||||
* - [7.1.2] Two Event Listeners are registered on the Event Source,
|
||||
* the Event Source is tested to have listeners.
|
||||
* - [7.1.3] An Event Listener is unregistered, the Event Source must
|
||||
* still have listeners.
|
||||
* - [7.1.4] An Event Listener is unregistered, the Event Source must
|
||||
* not have listeners.
|
||||
* - [7.1.1] Starting the messenger thread.
|
||||
* - [7.1.2] Waiting for four messages then testing the receive order.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_007_001_execute(void) {
|
||||
event_listener_t el1, el2;
|
||||
thread_t *tp;
|
||||
msg_t msg;
|
||||
|
||||
/* [7.1.1] An Event Source is initialized.*/
|
||||
/* [7.1.1] Starting the messenger thread.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtObjectInit(&es1);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() + 1,
|
||||
msg_thread1, chThdGetSelfX());
|
||||
}
|
||||
|
||||
/* [7.1.2] Two Event Listeners are registered on the Event Source,
|
||||
the Event Source is tested to have listeners.*/
|
||||
/* [7.1.2] Waiting for four messages then testing the receive
|
||||
order.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es1, &el2, 2);
|
||||
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
|
||||
}
|
||||
unsigned i;
|
||||
|
||||
/* [7.1.3] An Event Listener is unregistered, the Event Source must
|
||||
still have listeners.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chEvtUnregister(&es1, &el1);
|
||||
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
|
||||
}
|
||||
|
||||
/* [7.1.4] An Event Listener is unregistered, the Event Source must
|
||||
not have listeners.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
chEvtUnregister(&es1, &el2);
|
||||
test_assert_lock(!chEvtIsListeningI(&es1), "stuck listener");
|
||||
for (i = 0; i < 4; i++) {
|
||||
tp = chMsgWait();
|
||||
msg = chMsgGet(tp);
|
||||
chMsgRelease(tp, msg);
|
||||
test_emit_token(msg);
|
||||
}
|
||||
test_wait_threads();
|
||||
test_assert_sequence("ABCD", "invalid sequence");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_007_001 = {
|
||||
"Events registration",
|
||||
"Messages Server loop",
|
||||
NULL,
|
||||
NULL,
|
||||
test_007_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_007_002 [7.2] Event Flags dispatching
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The test dispatches three event flags and verifies that the
|
||||
* associated event handlers are invoked in LSb-first order.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [7.2.1] Three evenf flag bits are raised then chEvtDispatch() is
|
||||
* invoked, the sequence of handlers calls is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_007_002_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void test_007_002_execute(void) {
|
||||
|
||||
/* [7.2.1] Three evenf flag bits are raised then chEvtDispatch() is
|
||||
invoked, the sequence of handlers calls is tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtDispatch(evhndl, 7);
|
||||
test_assert_sequence("ABC", "invalid sequence");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_007_002 = {
|
||||
"Event Flags dispatching",
|
||||
test_007_002_setup,
|
||||
NULL,
|
||||
test_007_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_007_003 [7.3] Events Flags wait using chEvtWaitOne()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitOne() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [7.3.1] Setting three event flags.
|
||||
* - [7.3.2] Calling chEvtWaitOne() three times, each time a single
|
||||
* flag must be returned in order of priority.
|
||||
* - [7.3.3] Getting current time and starting a signaler thread, the
|
||||
* thread will set an event flag after 50mS.
|
||||
* - [7.3.4] Calling chEvtWaitOne() then verifying that the event has
|
||||
* been received after 50mS and that the event flags mask has been
|
||||
* emptied.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_007_003_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void test_007_003_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
|
||||
/* [7.3.1] Setting three event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(7);
|
||||
}
|
||||
|
||||
/* [7.3.2] Calling chEvtWaitOne() three times, each time a single
|
||||
flag must be returned in order of priority.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(m == 1, "single event error");
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(m == 2, "single event error");
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(m == 4, "single event error");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
}
|
||||
|
||||
/* [7.3.3] Getting current time and starting a signaler thread, the
|
||||
thread will set an event flag after 50mS.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
target_time = test_wait_tick() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread3, chThdGetSelfX());
|
||||
}
|
||||
|
||||
/* [7.3.4] Calling chEvtWaitOne() then verifying that the event has
|
||||
been received after 50mS and that the event flags mask has been
|
||||
emptied.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
|
||||
"out of time window");
|
||||
test_assert(m == 1, "event flag error");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
test_wait_threads();
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_007_003 = {
|
||||
"Events Flags wait using chEvtWaitOne()",
|
||||
test_007_003_setup,
|
||||
NULL,
|
||||
test_007_003_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_007_004 [7.4] Events Flags wait using chEvtWaitAny()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitAny() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [7.4.1] Setting two, non contiguous, event flags.
|
||||
* - [7.4.2] Calling chEvtWaitAny() one time, the two flags must be
|
||||
* returned.
|
||||
* - [7.4.3] Getting current time and starting a signaler thread, the
|
||||
* thread will set an event flag after 50mS.
|
||||
* - [7.4.4] Calling chEvtWaitAny() then verifying that the event has
|
||||
* been received after 50mS and that the event flags mask has been
|
||||
* emptied.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_007_004_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void test_007_004_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
|
||||
/* [7.4.1] Setting two, non contiguous, event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(5);
|
||||
}
|
||||
|
||||
/* [7.4.2] Calling chEvtWaitAny() one time, the two flags must be
|
||||
returned.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
m = chEvtWaitAny(ALL_EVENTS);
|
||||
test_assert(m == 5, "unexpected pending bit");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
}
|
||||
|
||||
/* [7.4.3] Getting current time and starting a signaler thread, the
|
||||
thread will set an event flag after 50mS.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
target_time = test_wait_tick() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread3, chThdGetSelfX());
|
||||
}
|
||||
|
||||
/* [7.4.4] Calling chEvtWaitAny() then verifying that the event has
|
||||
been received after 50mS and that the event flags mask has been
|
||||
emptied.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
m = chEvtWaitAny(ALL_EVENTS);
|
||||
test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
|
||||
"out of time window");
|
||||
test_assert(m == 1, "event flag error");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
test_wait_threads();
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_007_004 = {
|
||||
"Events Flags wait using chEvtWaitAny()",
|
||||
test_007_004_setup,
|
||||
NULL,
|
||||
test_007_004_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_007_005 [7.5] Events Flags wait using chEvtWaitAll()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitAll() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [7.5.1] Setting two, non contiguous, event flags.
|
||||
* - [7.5.2] Calling chEvtWaitAll() one time, the two flags must be
|
||||
* returned.
|
||||
* - [7.5.3] Setting one event flag.
|
||||
* - [7.5.4] Getting current time and starting a signaler thread, the
|
||||
* thread will set another event flag after 50mS.
|
||||
* - [7.5.5] Calling chEvtWaitAll() then verifying that both event
|
||||
* flags have been received after 50mS and that the event flags mask
|
||||
* has been emptied.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_007_005_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void test_007_005_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
|
||||
/* [7.5.1] Setting two, non contiguous, event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(5);
|
||||
}
|
||||
|
||||
/* [7.5.2] Calling chEvtWaitAll() one time, the two flags must be
|
||||
returned.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
m = chEvtWaitAll(5);
|
||||
test_assert(m == 5, "unexpected pending bit");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
}
|
||||
|
||||
/* [7.5.3] Setting one event flag.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chEvtAddEvents(4);
|
||||
}
|
||||
|
||||
/* [7.5.4] Getting current time and starting a signaler thread, the
|
||||
thread will set another event flag after 50mS.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
target_time = test_wait_tick() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread3, chThdGetSelfX());
|
||||
}
|
||||
|
||||
/* [7.5.5] Calling chEvtWaitAll() then verifying that both event
|
||||
flags have been received after 50mS and that the event flags mask
|
||||
has been emptied.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
m = chEvtWaitAll(5);
|
||||
test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
|
||||
"out of time window");
|
||||
test_assert(m == 5, "event flags error");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
test_wait_threads();
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_007_005 = {
|
||||
"Events Flags wait using chEvtWaitAll()",
|
||||
test_007_005_setup,
|
||||
NULL,
|
||||
test_007_005_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_007_006 [7.6] Events Flags wait timeouts
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Timeout functionality is tested for chEvtWaitOneTimeout(),
|
||||
* chEvtWaitAnyTimeout() and chEvtWaitAllTimeout().
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_EVENTS_TIMEOUT
|
||||
* .
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [7.6.1] The functions are invoked first with TIME_IMMEDIATE
|
||||
* timeout, the timeout condition is tested.
|
||||
* - [7.6.2] The functions are invoked first with a 50mS timeout, the
|
||||
* timeout condition is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_007_006_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void test_007_006_execute(void) {
|
||||
eventmask_t m;
|
||||
|
||||
/* [7.6.1] The functions are invoked first with TIME_IMMEDIATE
|
||||
timeout, the timeout condition is tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(m == 0, "spurious event");
|
||||
}
|
||||
|
||||
/* [7.6.2] The functions are invoked first with a 50mS timeout, the
|
||||
timeout condition is tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
m = chEvtWaitOneTimeout(ALL_EVENTS, MS2ST(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAllTimeout(ALL_EVENTS, MS2ST(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_007_006 = {
|
||||
"Events Flags wait timeouts",
|
||||
test_007_006_setup,
|
||||
NULL,
|
||||
test_007_006_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_EVENTS_TIMEOUT */
|
||||
|
||||
/**
|
||||
* @page test_007_007 [7.7] Broadcasting using chEvtBroadcast()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtBroadcast() is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [7.7.1] Registering on two event sources associating them with
|
||||
* flags 1 and 4.
|
||||
* - [7.7.2] Getting current time and starting a broadcaster thread,
|
||||
* the thread broadcast the first Event Source immediately and the
|
||||
* other after 50mS.
|
||||
* - [7.7.3] Calling chEvtWaitAll() then verifying that both event
|
||||
* flags have been received after 50mS and that the event flags mask
|
||||
* has been emptied.
|
||||
* - [7.7.4] Unregistering from the Event Sources.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_007_007_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
chEvtObjectInit(&es1);
|
||||
chEvtObjectInit(&es2);
|
||||
}
|
||||
|
||||
static void test_007_007_execute(void) {
|
||||
eventmask_t m;
|
||||
event_listener_t el1, el2;
|
||||
systime_t target_time;
|
||||
|
||||
/* [7.7.1] Registering on two event sources associating them with
|
||||
flags 1 and 4.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es2, &el2, 4);
|
||||
}
|
||||
|
||||
/* [7.7.2] Getting current time and starting a broadcaster thread,
|
||||
the thread broadcast the first Event Source immediately and the
|
||||
other after 50mS.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
target_time = test_wait_tick() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread7, "A");
|
||||
}
|
||||
|
||||
/* [7.7.3] Calling chEvtWaitAll() then verifying that both event
|
||||
flags have been received after 50mS and that the event flags mask
|
||||
has been emptied.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
m = chEvtWaitAll(5);
|
||||
test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
|
||||
"out of time window");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
test_wait_threads();
|
||||
}
|
||||
|
||||
/* [7.7.4] Unregistering from the Event Sources.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
chEvtUnregister(&es1, &el1);
|
||||
chEvtUnregister(&es2, &el2);
|
||||
test_assert(!chEvtIsListeningI(&es1), "stuck listener");
|
||||
test_assert(!chEvtIsListeningI(&es2), "stuck listener");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_007_007 = {
|
||||
"Broadcasting using chEvtBroadcast()",
|
||||
test_007_007_setup,
|
||||
NULL,
|
||||
test_007_007_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Event Sources and Event Flags.
|
||||
* @brief Synchronous Messages.
|
||||
*/
|
||||
const testcase_t * const test_sequence_007[] = {
|
||||
&test_007_001,
|
||||
&test_007_002,
|
||||
&test_007_003,
|
||||
&test_007_004,
|
||||
&test_007_005,
|
||||
#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
|
||||
&test_007_006,
|
||||
#endif
|
||||
&test_007_007,
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_EVENTS */
|
||||
#endif /* CH_CFG_USE_MESSAGES */
|
||||
|
|
|
@ -22,388 +22,548 @@
|
|||
* @file test_sequence_008.c
|
||||
* @brief Test Sequence 008 code.
|
||||
*
|
||||
* @page test_sequence_008 [8] Mailboxes
|
||||
* @page test_sequence_008 [8] Event Sources and Event Flags
|
||||
*
|
||||
* File: @ref test_sequence_008.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/RT functionalities related to
|
||||
* mailboxes.
|
||||
* This module implements the test sequence for the Events subsystem.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_MAILBOXES
|
||||
* - CH_CFG_USE_EVENTS
|
||||
* .
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_008_001
|
||||
* - @subpage test_008_002
|
||||
* - @subpage test_008_003
|
||||
* - @subpage test_008_004
|
||||
* - @subpage test_008_005
|
||||
* - @subpage test_008_006
|
||||
* - @subpage test_008_007
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
#define MB_SIZE 4
|
||||
static EVENTSOURCE_DECL(es1);
|
||||
static EVENTSOURCE_DECL(es2);
|
||||
|
||||
static msg_t mb_buffer[MB_SIZE];
|
||||
static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE);
|
||||
static void h1(eventid_t id) {(void)id;test_emit_token('A');}
|
||||
static void h2(eventid_t id) {(void)id;test_emit_token('B');}
|
||||
static void h3(eventid_t id) {(void)id;test_emit_token('C');}
|
||||
static ROMCONST evhandler_t evhndl[] = {h1, h2, h3};
|
||||
|
||||
static THD_FUNCTION(evt_thread3, p) {
|
||||
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtSignal((thread_t *)p, 1);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(evt_thread7, p) {
|
||||
|
||||
(void)p;
|
||||
chEvtBroadcast(&es1);
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtBroadcast(&es2);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_008_001 [8.1] Mailbox normal API, non-blocking tests
|
||||
* @page test_008_001 [8.1] Events registration
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The mailbox normal API is tested without triggering blocking
|
||||
* conditions.
|
||||
* Two event listeners are registered on an event source and then
|
||||
* unregistered in the same order.<br> The test expects that the even
|
||||
* source has listeners after the registrations and after the first
|
||||
* unregistration, then, after the second unegistration, the test
|
||||
* expects no more listeners.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [8.1.1] Testing the mailbox size.
|
||||
* - [8.1.2] Resetting the mailbox, conditions are checked, no errors
|
||||
* expected.
|
||||
* - [8.1.3] Testing the behavior of API when the mailbox is in reset
|
||||
* state then return in active state.
|
||||
* - [8.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
|
||||
* once, no errors expected.
|
||||
* - [8.1.5] Testing intermediate conditions. Data pointers must be
|
||||
* aligned, semaphore counters are checked.
|
||||
* - [8.1.6] Emptying the mailbox using chMBFetch(), no errors
|
||||
* expected.
|
||||
* - [8.1.7] Posting and then fetching one more message, no errors
|
||||
* expected.
|
||||
* - [8.1.8] Testing final conditions. Data pointers must be aligned to
|
||||
* buffer start, semaphore counters are checked.
|
||||
* - [8.1.1] An Event Source is initialized.
|
||||
* - [8.1.2] Two Event Listeners are registered on the Event Source,
|
||||
* the Event Source is tested to have listeners.
|
||||
* - [8.1.3] An Event Listener is unregistered, the Event Source must
|
||||
* still have listeners.
|
||||
* - [8.1.4] An Event Listener is unregistered, the Event Source must
|
||||
* not have listeners.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_008_001_setup(void) {
|
||||
chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
|
||||
}
|
||||
|
||||
static void test_008_001_teardown(void) {
|
||||
chMBReset(&mb1);
|
||||
}
|
||||
|
||||
static void test_008_001_execute(void) {
|
||||
msg_t msg1, msg2;
|
||||
unsigned i;
|
||||
event_listener_t el1, el2;
|
||||
|
||||
/* [8.1.1] Testing the mailbox size.*/
|
||||
/* [8.1.1] An Event Source is initialized.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
|
||||
chEvtObjectInit(&es1);
|
||||
}
|
||||
|
||||
/* [8.1.2] Resetting the mailbox, conditions are checked, no errors
|
||||
expected.*/
|
||||
/* [8.1.2] Two Event Listeners are registered on the Event Source,
|
||||
the Event Source is tested to have listeners.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chMBReset(&mb1);
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es1, &el2, 2);
|
||||
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
|
||||
}
|
||||
|
||||
/* [8.1.3] Testing the behavior of API when the mailbox is in reset
|
||||
state then return in active state.*/
|
||||
/* [8.1.3] An Event Listener is unregistered, the Event Source must
|
||||
still have listeners.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
msg1 = chMBPost(&mb1, (msg_t)0, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_RESET, "not in reset state");
|
||||
msg1 = chMBPostAhead(&mb1, (msg_t)0, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_RESET, "not in reset state");
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_RESET, "not in reset state");
|
||||
chMBResumeX(&mb1);
|
||||
chEvtUnregister(&es1, &el1);
|
||||
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
|
||||
}
|
||||
|
||||
/* [8.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
|
||||
once, no errors expected.*/
|
||||
/* [8.1.4] An Event Listener is unregistered, the Event Source must
|
||||
not have listeners.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
for (i = 0; i < MB_SIZE - 1; i++) {
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [8.1.5] Testing intermediate conditions. Data pointers must be
|
||||
aligned, semaphore counters are checked.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
|
||||
test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
|
||||
}
|
||||
|
||||
/* [8.1.6] Emptying the mailbox using chMBFetch(), no errors
|
||||
expected.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
test_emit_token(msg2);
|
||||
}
|
||||
test_assert_sequence("ABCD", "wrong get sequence");
|
||||
}
|
||||
|
||||
/* [8.1.7] Posting and then fetching one more message, no errors
|
||||
expected.*/
|
||||
test_set_step(7);
|
||||
{
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [8.1.8] Testing final conditions. Data pointers must be aligned to
|
||||
buffer start, semaphore counters are checked.*/
|
||||
test_set_step(8);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
chEvtUnregister(&es1, &el2);
|
||||
test_assert_lock(!chEvtIsListeningI(&es1), "stuck listener");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_008_001 = {
|
||||
"Mailbox normal API, non-blocking tests",
|
||||
test_008_001_setup,
|
||||
test_008_001_teardown,
|
||||
"Events registration",
|
||||
NULL,
|
||||
NULL,
|
||||
test_008_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_008_002 [8.2] Mailbox I-Class API, non-blocking tests
|
||||
* @page test_008_002 [8.2] Event Flags dispatching
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The mailbox I-Class API is tested without triggering blocking
|
||||
* conditions.
|
||||
* The test dispatches three event flags and verifies that the
|
||||
* associated event handlers are invoked in LSb-first order.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [8.2.1] Testing the mailbox size.
|
||||
* - [8.2.2] Resetting the mailbox, conditions are checked, no errors
|
||||
* expected. The mailbox is then returned in active state.
|
||||
* - [8.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
|
||||
* once, no errors expected.
|
||||
* - [8.2.4] Testing intermediate conditions. Data pointers must be
|
||||
* aligned, semaphore counters are checked.
|
||||
* - [8.2.5] Emptying the mailbox using chMBFetchI(), no errors
|
||||
* expected.
|
||||
* - [8.2.6] Posting and then fetching one more message, no errors
|
||||
* expected.
|
||||
* - [8.2.7] Testing final conditions. Data pointers must be aligned to
|
||||
* buffer start, semaphore counters are checked.
|
||||
* - [8.2.1] Three evenf flag bits are raised then chEvtDispatch() is
|
||||
* invoked, the sequence of handlers calls is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_008_002_setup(void) {
|
||||
chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
|
||||
}
|
||||
|
||||
static void test_008_002_teardown(void) {
|
||||
chMBReset(&mb1);
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void test_008_002_execute(void) {
|
||||
msg_t msg1, msg2;
|
||||
unsigned i;
|
||||
|
||||
/* [8.2.1] Testing the mailbox size.*/
|
||||
/* [8.2.1] Three evenf flag bits are raised then chEvtDispatch() is
|
||||
invoked, the sequence of handlers calls is tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
|
||||
}
|
||||
|
||||
/* [8.2.2] Resetting the mailbox, conditions are checked, no errors
|
||||
expected. The mailbox is then returned in active state.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chSysLock();
|
||||
chMBResetI(&mb1);
|
||||
chSysUnlock();
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
chMBResumeX(&mb1);
|
||||
}
|
||||
|
||||
/* [8.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
|
||||
once, no errors expected.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
for (i = 0; i < MB_SIZE - 1; i++) {
|
||||
chSysLock();
|
||||
msg1 = chMBPostI(&mb1, 'B' + i);
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
chSysLock();
|
||||
msg1 = chMBPostAheadI(&mb1, 'A');
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [8.2.4] Testing intermediate conditions. Data pointers must be
|
||||
aligned, semaphore counters are checked.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
|
||||
test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
|
||||
}
|
||||
|
||||
/* [8.2.5] Emptying the mailbox using chMBFetchI(), no errors
|
||||
expected.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
chSysLock();
|
||||
msg1 = chMBFetchI(&mb1, &msg2);
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
test_emit_token(msg2);
|
||||
}
|
||||
test_assert_sequence("ABCD", "wrong get sequence");
|
||||
}
|
||||
|
||||
/* [8.2.6] Posting and then fetching one more message, no errors
|
||||
expected.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [8.2.7] Testing final conditions. Data pointers must be aligned to
|
||||
buffer start, semaphore counters are checked.*/
|
||||
test_set_step(7);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
chEvtDispatch(evhndl, 7);
|
||||
test_assert_sequence("ABC", "invalid sequence");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_008_002 = {
|
||||
"Mailbox I-Class API, non-blocking tests",
|
||||
"Event Flags dispatching",
|
||||
test_008_002_setup,
|
||||
test_008_002_teardown,
|
||||
NULL,
|
||||
test_008_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_008_003 [8.3] Mailbox timeouts
|
||||
* @page test_008_003 [8.3] Events Flags wait using chEvtWaitOne()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The mailbox API is tested for timeouts.
|
||||
* Functionality of chEvtWaitOne() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [8.3.1] Filling the mailbox.
|
||||
* - [8.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
|
||||
* chMBPostAheadI() timeout.
|
||||
* - [8.3.3] Resetting the mailbox. The mailbox is then returned in
|
||||
* active state.
|
||||
* - [8.3.4] Testing chMBFetch() and chMBFetchI() timeout.
|
||||
* - [8.3.1] Setting three event flags.
|
||||
* - [8.3.2] Calling chEvtWaitOne() three times, each time a single
|
||||
* flag must be returned in order of priority.
|
||||
* - [8.3.3] Getting current time and starting a signaler thread, the
|
||||
* thread will set an event flag after 50mS.
|
||||
* - [8.3.4] Calling chEvtWaitOne() then verifying that the event has
|
||||
* been received after 50mS and that the event flags mask has been
|
||||
* emptied.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_008_003_setup(void) {
|
||||
chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
|
||||
}
|
||||
|
||||
static void test_008_003_teardown(void) {
|
||||
chMBReset(&mb1);
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void test_008_003_execute(void) {
|
||||
msg_t msg1, msg2;
|
||||
unsigned i;
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
|
||||
/* [8.3.1] Filling the mailbox.*/
|
||||
/* [8.3.1] Setting three event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
chEvtAddEvents(7);
|
||||
}
|
||||
|
||||
/* [8.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
|
||||
chMBPostAheadI() timeout.*/
|
||||
/* [8.3.2] Calling chEvtWaitOne() three times, each time a single
|
||||
flag must be returned in order of priority.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
msg1 = chMBPost(&mb1, 'X', 1);
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBPostI(&mb1, 'X');
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
msg1 = chMBPostAhead(&mb1, 'X', 1);
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBPostAheadI(&mb1, 'X');
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(m == 1, "single event error");
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(m == 2, "single event error");
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(m == 4, "single event error");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
}
|
||||
|
||||
/* [8.3.3] Resetting the mailbox. The mailbox is then returned in
|
||||
active state.*/
|
||||
/* [8.3.3] Getting current time and starting a signaler thread, the
|
||||
thread will set an event flag after 50mS.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chMBReset(&mb1);
|
||||
chMBResumeX(&mb1);
|
||||
target_time = test_wait_tick() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread3, chThdGetSelfX());
|
||||
}
|
||||
|
||||
/* [8.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/
|
||||
/* [8.3.4] Calling chEvtWaitOne() then verifying that the event has
|
||||
been received after 50mS and that the event flags mask has been
|
||||
emptied.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
msg1 = chMBFetch(&mb1, &msg2, 1);
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBFetchI(&mb1, &msg2);
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
|
||||
"out of time window");
|
||||
test_assert(m == 1, "event flag error");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
test_wait_threads();
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_008_003 = {
|
||||
"Mailbox timeouts",
|
||||
"Events Flags wait using chEvtWaitOne()",
|
||||
test_008_003_setup,
|
||||
test_008_003_teardown,
|
||||
NULL,
|
||||
test_008_003_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_008_004 [8.4] Events Flags wait using chEvtWaitAny()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitAny() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [8.4.1] Setting two, non contiguous, event flags.
|
||||
* - [8.4.2] Calling chEvtWaitAny() one time, the two flags must be
|
||||
* returned.
|
||||
* - [8.4.3] Getting current time and starting a signaler thread, the
|
||||
* thread will set an event flag after 50mS.
|
||||
* - [8.4.4] Calling chEvtWaitAny() then verifying that the event has
|
||||
* been received after 50mS and that the event flags mask has been
|
||||
* emptied.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_008_004_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void test_008_004_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
|
||||
/* [8.4.1] Setting two, non contiguous, event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(5);
|
||||
}
|
||||
|
||||
/* [8.4.2] Calling chEvtWaitAny() one time, the two flags must be
|
||||
returned.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
m = chEvtWaitAny(ALL_EVENTS);
|
||||
test_assert(m == 5, "unexpected pending bit");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
}
|
||||
|
||||
/* [8.4.3] Getting current time and starting a signaler thread, the
|
||||
thread will set an event flag after 50mS.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
target_time = test_wait_tick() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread3, chThdGetSelfX());
|
||||
}
|
||||
|
||||
/* [8.4.4] Calling chEvtWaitAny() then verifying that the event has
|
||||
been received after 50mS and that the event flags mask has been
|
||||
emptied.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
m = chEvtWaitAny(ALL_EVENTS);
|
||||
test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
|
||||
"out of time window");
|
||||
test_assert(m == 1, "event flag error");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
test_wait_threads();
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_008_004 = {
|
||||
"Events Flags wait using chEvtWaitAny()",
|
||||
test_008_004_setup,
|
||||
NULL,
|
||||
test_008_004_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_008_005 [8.5] Events Flags wait using chEvtWaitAll()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitAll() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [8.5.1] Setting two, non contiguous, event flags.
|
||||
* - [8.5.2] Calling chEvtWaitAll() one time, the two flags must be
|
||||
* returned.
|
||||
* - [8.5.3] Setting one event flag.
|
||||
* - [8.5.4] Getting current time and starting a signaler thread, the
|
||||
* thread will set another event flag after 50mS.
|
||||
* - [8.5.5] Calling chEvtWaitAll() then verifying that both event
|
||||
* flags have been received after 50mS and that the event flags mask
|
||||
* has been emptied.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_008_005_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void test_008_005_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
|
||||
/* [8.5.1] Setting two, non contiguous, event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(5);
|
||||
}
|
||||
|
||||
/* [8.5.2] Calling chEvtWaitAll() one time, the two flags must be
|
||||
returned.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
m = chEvtWaitAll(5);
|
||||
test_assert(m == 5, "unexpected pending bit");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
}
|
||||
|
||||
/* [8.5.3] Setting one event flag.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chEvtAddEvents(4);
|
||||
}
|
||||
|
||||
/* [8.5.4] Getting current time and starting a signaler thread, the
|
||||
thread will set another event flag after 50mS.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
target_time = test_wait_tick() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread3, chThdGetSelfX());
|
||||
}
|
||||
|
||||
/* [8.5.5] Calling chEvtWaitAll() then verifying that both event
|
||||
flags have been received after 50mS and that the event flags mask
|
||||
has been emptied.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
m = chEvtWaitAll(5);
|
||||
test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
|
||||
"out of time window");
|
||||
test_assert(m == 5, "event flags error");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
test_wait_threads();
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_008_005 = {
|
||||
"Events Flags wait using chEvtWaitAll()",
|
||||
test_008_005_setup,
|
||||
NULL,
|
||||
test_008_005_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_008_006 [8.6] Events Flags wait timeouts
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Timeout functionality is tested for chEvtWaitOneTimeout(),
|
||||
* chEvtWaitAnyTimeout() and chEvtWaitAllTimeout().
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_EVENTS_TIMEOUT
|
||||
* .
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [8.6.1] The functions are invoked first with TIME_IMMEDIATE
|
||||
* timeout, the timeout condition is tested.
|
||||
* - [8.6.2] The functions are invoked first with a 50mS timeout, the
|
||||
* timeout condition is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_008_006_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void test_008_006_execute(void) {
|
||||
eventmask_t m;
|
||||
|
||||
/* [8.6.1] The functions are invoked first with TIME_IMMEDIATE
|
||||
timeout, the timeout condition is tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(m == 0, "spurious event");
|
||||
}
|
||||
|
||||
/* [8.6.2] The functions are invoked first with a 50mS timeout, the
|
||||
timeout condition is tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
m = chEvtWaitOneTimeout(ALL_EVENTS, MS2ST(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAllTimeout(ALL_EVENTS, MS2ST(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_008_006 = {
|
||||
"Events Flags wait timeouts",
|
||||
test_008_006_setup,
|
||||
NULL,
|
||||
test_008_006_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_EVENTS_TIMEOUT */
|
||||
|
||||
/**
|
||||
* @page test_008_007 [8.7] Broadcasting using chEvtBroadcast()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtBroadcast() is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [8.7.1] Registering on two event sources associating them with
|
||||
* flags 1 and 4.
|
||||
* - [8.7.2] Getting current time and starting a broadcaster thread,
|
||||
* the thread broadcast the first Event Source immediately and the
|
||||
* other after 50mS.
|
||||
* - [8.7.3] Calling chEvtWaitAll() then verifying that both event
|
||||
* flags have been received after 50mS and that the event flags mask
|
||||
* has been emptied.
|
||||
* - [8.7.4] Unregistering from the Event Sources.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_008_007_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
chEvtObjectInit(&es1);
|
||||
chEvtObjectInit(&es2);
|
||||
}
|
||||
|
||||
static void test_008_007_execute(void) {
|
||||
eventmask_t m;
|
||||
event_listener_t el1, el2;
|
||||
systime_t target_time;
|
||||
|
||||
/* [8.7.1] Registering on two event sources associating them with
|
||||
flags 1 and 4.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es2, &el2, 4);
|
||||
}
|
||||
|
||||
/* [8.7.2] Getting current time and starting a broadcaster thread,
|
||||
the thread broadcast the first Event Source immediately and the
|
||||
other after 50mS.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
target_time = test_wait_tick() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread7, "A");
|
||||
}
|
||||
|
||||
/* [8.7.3] Calling chEvtWaitAll() then verifying that both event
|
||||
flags have been received after 50mS and that the event flags mask
|
||||
has been emptied.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
m = chEvtWaitAll(5);
|
||||
test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
|
||||
"out of time window");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
test_wait_threads();
|
||||
}
|
||||
|
||||
/* [8.7.4] Unregistering from the Event Sources.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
chEvtUnregister(&es1, &el1);
|
||||
chEvtUnregister(&es2, &el2);
|
||||
test_assert(!chEvtIsListeningI(&es1), "stuck listener");
|
||||
test_assert(!chEvtIsListeningI(&es2), "stuck listener");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_008_007 = {
|
||||
"Broadcasting using chEvtBroadcast()",
|
||||
test_008_007_setup,
|
||||
NULL,
|
||||
test_008_007_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Mailboxes.
|
||||
* @brief Event Sources and Event Flags.
|
||||
*/
|
||||
const testcase_t * const test_sequence_008[] = {
|
||||
&test_008_001,
|
||||
&test_008_002,
|
||||
&test_008_003,
|
||||
&test_008_004,
|
||||
&test_008_005,
|
||||
#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
|
||||
&test_008_006,
|
||||
#endif
|
||||
&test_008_007,
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_MAILBOXES */
|
||||
#endif /* CH_CFG_USE_EVENTS */
|
||||
|
|
|
@ -22,18 +22,18 @@
|
|||
* @file test_sequence_009.c
|
||||
* @brief Test Sequence 009 code.
|
||||
*
|
||||
* @page test_sequence_009 [9] Memory Pools
|
||||
* @page test_sequence_009 [9] Mailboxes
|
||||
*
|
||||
* File: @ref test_sequence_009.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/RT functionalities related to memory
|
||||
* pools.
|
||||
* This sequence tests the ChibiOS/RT functionalities related to
|
||||
* mailboxes.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_MEMPOOLS
|
||||
* - CH_CFG_USE_MAILBOXES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
|
@ -43,254 +43,367 @@
|
|||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
#define MEMORY_POOL_SIZE 4
|
||||
#define MB_SIZE 4
|
||||
|
||||
static uint32_t objects[MEMORY_POOL_SIZE];
|
||||
static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL);
|
||||
|
||||
#if CH_CFG_USE_SEMAPHORES
|
||||
static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t));
|
||||
#endif
|
||||
|
||||
static void *null_provider(size_t size, unsigned align) {
|
||||
|
||||
(void)size;
|
||||
(void)align;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
static msg_t mb_buffer[MB_SIZE];
|
||||
static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE);
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_009_001 [9.1] Loading and emptying a memory pool
|
||||
* @page test_009_001 [9.1] Mailbox normal API, non-blocking tests
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The memory pool functionality is tested by loading and emptying it,
|
||||
* all conditions are tested.
|
||||
* The mailbox normal API is tested without triggering blocking
|
||||
* conditions.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [9.1.1] Adding the objects to the pool using chPoolLoadArray().
|
||||
* - [9.1.2] Emptying the pool using chPoolAlloc().
|
||||
* - [9.1.3] Now must be empty.
|
||||
* - [9.1.4] Adding the objects to the pool using chPoolFree().
|
||||
* - [9.1.5] Emptying the pool using chPoolAlloc() again.
|
||||
* - [9.1.6] Now must be empty again.
|
||||
* - [9.1.7] Covering the case where a provider is unable to return
|
||||
* more memory.
|
||||
* - [9.1.1] Testing the mailbox size.
|
||||
* - [9.1.2] Resetting the mailbox, conditions are checked, no errors
|
||||
* expected.
|
||||
* - [9.1.3] Testing the behavior of API when the mailbox is in reset
|
||||
* state then return in active state.
|
||||
* - [9.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
|
||||
* once, no errors expected.
|
||||
* - [9.1.5] Testing intermediate conditions. Data pointers must be
|
||||
* aligned, semaphore counters are checked.
|
||||
* - [9.1.6] Emptying the mailbox using chMBFetch(), no errors
|
||||
* expected.
|
||||
* - [9.1.7] Posting and then fetching one more message, no errors
|
||||
* expected.
|
||||
* - [9.1.8] Testing final conditions. Data pointers must be aligned to
|
||||
* buffer start, semaphore counters are checked.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_009_001_setup(void) {
|
||||
chPoolObjectInit(&mp1, sizeof (uint32_t), NULL);
|
||||
chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
|
||||
}
|
||||
|
||||
static void test_009_001_teardown(void) {
|
||||
chMBReset(&mb1);
|
||||
}
|
||||
|
||||
static void test_009_001_execute(void) {
|
||||
msg_t msg1, msg2;
|
||||
unsigned i;
|
||||
|
||||
/* [9.1.1] Adding the objects to the pool using chPoolLoadArray().*/
|
||||
/* [9.1.1] Testing the mailbox size.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE);
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
|
||||
}
|
||||
|
||||
/* [9.1.2] Emptying the pool using chPoolAlloc().*/
|
||||
/* [9.1.2] Resetting the mailbox, conditions are checked, no errors
|
||||
expected.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
|
||||
chMBReset(&mb1);
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
}
|
||||
|
||||
/* [9.1.3] Now must be empty.*/
|
||||
/* [9.1.3] Testing the behavior of API when the mailbox is in reset
|
||||
state then return in active state.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
|
||||
msg1 = chMBPost(&mb1, (msg_t)0, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_RESET, "not in reset state");
|
||||
msg1 = chMBPostAhead(&mb1, (msg_t)0, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_RESET, "not in reset state");
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_RESET, "not in reset state");
|
||||
chMBResumeX(&mb1);
|
||||
}
|
||||
|
||||
/* [9.1.4] Adding the objects to the pool using chPoolFree().*/
|
||||
/* [9.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
|
||||
once, no errors expected.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
chPoolFree(&mp1, &objects[i]);
|
||||
for (i = 0; i < MB_SIZE - 1; i++) {
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [9.1.5] Emptying the pool using chPoolAlloc() again.*/
|
||||
/* [9.1.5] Testing intermediate conditions. Data pointers must be
|
||||
aligned, semaphore counters are checked.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
|
||||
test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
|
||||
}
|
||||
|
||||
/* [9.1.6] Now must be empty again.*/
|
||||
/* [9.1.6] Emptying the mailbox using chMBFetch(), no errors
|
||||
expected.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
test_emit_token(msg2);
|
||||
}
|
||||
test_assert_sequence("ABCD", "wrong get sequence");
|
||||
}
|
||||
|
||||
/* [9.1.7] Covering the case where a provider is unable to return
|
||||
more memory.*/
|
||||
/* [9.1.7] Posting and then fetching one more message, no errors
|
||||
expected.*/
|
||||
test_set_step(7);
|
||||
{
|
||||
chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider);
|
||||
test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory");
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [9.1.8] Testing final conditions. Data pointers must be aligned to
|
||||
buffer start, semaphore counters are checked.*/
|
||||
test_set_step(8);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_009_001 = {
|
||||
"Loading and emptying a memory pool",
|
||||
"Mailbox normal API, non-blocking tests",
|
||||
test_009_001_setup,
|
||||
NULL,
|
||||
test_009_001_teardown,
|
||||
test_009_001_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_009_002 [9.2] Loading and emptying a guarded memory pool without waiting
|
||||
* @page test_009_002 [9.2] Mailbox I-Class API, non-blocking tests
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The memory pool functionality is tested by loading and emptying it,
|
||||
* all conditions are tested.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
* The mailbox I-Class API is tested without triggering blocking
|
||||
* conditions.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [9.2.1] Adding the objects to the pool using
|
||||
* chGuardedPoolLoadArray().
|
||||
* - [9.2.2] Emptying the pool using chGuardedPoolAllocTimeout().
|
||||
* - [9.2.3] Now must be empty.
|
||||
* - [9.2.4] Adding the objects to the pool using chGuardedPoolFree().
|
||||
* - [9.2.5] Emptying the pool using chGuardedPoolAllocTimeout() again.
|
||||
* - [9.2.6] Now must be empty again.
|
||||
* - [9.2.1] Testing the mailbox size.
|
||||
* - [9.2.2] Resetting the mailbox, conditions are checked, no errors
|
||||
* expected. The mailbox is then returned in active state.
|
||||
* - [9.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
|
||||
* once, no errors expected.
|
||||
* - [9.2.4] Testing intermediate conditions. Data pointers must be
|
||||
* aligned, semaphore counters are checked.
|
||||
* - [9.2.5] Emptying the mailbox using chMBFetchI(), no errors
|
||||
* expected.
|
||||
* - [9.2.6] Posting and then fetching one more message, no errors
|
||||
* expected.
|
||||
* - [9.2.7] Testing final conditions. Data pointers must be aligned to
|
||||
* buffer start, semaphore counters are checked.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_009_002_setup(void) {
|
||||
chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
|
||||
chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
|
||||
}
|
||||
|
||||
static void test_009_002_teardown(void) {
|
||||
chMBReset(&mb1);
|
||||
}
|
||||
|
||||
static void test_009_002_execute(void) {
|
||||
msg_t msg1, msg2;
|
||||
unsigned i;
|
||||
|
||||
/* [9.2.1] Adding the objects to the pool using
|
||||
chGuardedPoolLoadArray().*/
|
||||
/* [9.2.1] Testing the mailbox size.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE);
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
|
||||
}
|
||||
|
||||
/* [9.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/
|
||||
/* [9.2.2] Resetting the mailbox, conditions are checked, no errors
|
||||
expected. The mailbox is then returned in active state.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
|
||||
chSysLock();
|
||||
chMBResetI(&mb1);
|
||||
chSysUnlock();
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
chMBResumeX(&mb1);
|
||||
}
|
||||
|
||||
/* [9.2.3] Now must be empty.*/
|
||||
/* [9.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
|
||||
once, no errors expected.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
|
||||
for (i = 0; i < MB_SIZE - 1; i++) {
|
||||
chSysLock();
|
||||
msg1 = chMBPostI(&mb1, 'B' + i);
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
chSysLock();
|
||||
msg1 = chMBPostAheadI(&mb1, 'A');
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [9.2.4] Adding the objects to the pool using
|
||||
chGuardedPoolFree().*/
|
||||
/* [9.2.4] Testing intermediate conditions. Data pointers must be
|
||||
aligned, semaphore counters are checked.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
chGuardedPoolFree(&gmp1, &objects[i]);
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
|
||||
test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
|
||||
}
|
||||
|
||||
/* [9.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
|
||||
again.*/
|
||||
/* [9.2.5] Emptying the mailbox using chMBFetchI(), no errors
|
||||
expected.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
chSysLock();
|
||||
msg1 = chMBFetchI(&mb1, &msg2);
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
test_emit_token(msg2);
|
||||
}
|
||||
test_assert_sequence("ABCD", "wrong get sequence");
|
||||
}
|
||||
|
||||
/* [9.2.6] Now must be empty again.*/
|
||||
/* [9.2.6] Posting and then fetching one more message, no errors
|
||||
expected.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [9.2.7] Testing final conditions. Data pointers must be aligned to
|
||||
buffer start, semaphore counters are checked.*/
|
||||
test_set_step(7);
|
||||
{
|
||||
test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_009_002 = {
|
||||
"Loading and emptying a guarded memory pool without waiting",
|
||||
"Mailbox I-Class API, non-blocking tests",
|
||||
test_009_002_setup,
|
||||
NULL,
|
||||
test_009_002_teardown,
|
||||
test_009_002_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_009_003 [9.3] Guarded Memory Pools timeout
|
||||
* @page test_009_003 [9.3] Mailbox timeouts
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The timeout features for the Guarded Memory Pools is tested.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
* The mailbox API is tested for timeouts.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [9.3.1] Trying to allocate with 100mS timeout, must fail because
|
||||
* the pool is empty.
|
||||
* - [9.3.1] Filling the mailbox.
|
||||
* - [9.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
|
||||
* chMBPostAheadI() timeout.
|
||||
* - [9.3.3] Resetting the mailbox. The mailbox is then returned in
|
||||
* active state.
|
||||
* - [9.3.4] Testing chMBFetch() and chMBFetchI() timeout.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_009_003_setup(void) {
|
||||
chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
|
||||
chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
|
||||
}
|
||||
|
||||
static void test_009_003_teardown(void) {
|
||||
chMBReset(&mb1);
|
||||
}
|
||||
|
||||
static void test_009_003_execute(void) {
|
||||
msg_t msg1, msg2;
|
||||
unsigned i;
|
||||
|
||||
/* [9.3.1] Trying to allocate with 100mS timeout, must fail because
|
||||
the pool is empty.*/
|
||||
/* [9.3.1] Filling the mailbox.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty");
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
}
|
||||
|
||||
/* [9.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
|
||||
chMBPostAheadI() timeout.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
msg1 = chMBPost(&mb1, 'X', 1);
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBPostI(&mb1, 'X');
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
msg1 = chMBPostAhead(&mb1, 'X', 1);
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBPostAheadI(&mb1, 'X');
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
}
|
||||
|
||||
/* [9.3.3] Resetting the mailbox. The mailbox is then returned in
|
||||
active state.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chMBReset(&mb1);
|
||||
chMBResumeX(&mb1);
|
||||
}
|
||||
|
||||
/* [9.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
msg1 = chMBFetch(&mb1, &msg2, 1);
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBFetchI(&mb1, &msg2);
|
||||
chSysUnlock();
|
||||
test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_009_003 = {
|
||||
"Guarded Memory Pools timeout",
|
||||
"Mailbox timeouts",
|
||||
test_009_003_setup,
|
||||
NULL,
|
||||
test_009_003_teardown,
|
||||
test_009_003_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Memory Pools.
|
||||
* @brief Mailboxes.
|
||||
*/
|
||||
const testcase_t * const test_sequence_009[] = {
|
||||
&test_009_001,
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&test_009_002,
|
||||
#endif
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&test_009_003,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_MEMPOOLS */
|
||||
#endif /* CH_CFG_USE_MAILBOXES */
|
||||
|
|
|
@ -22,251 +22,276 @@
|
|||
* @file test_sequence_010.c
|
||||
* @brief Test Sequence 010 code.
|
||||
*
|
||||
* @page test_sequence_010 [10] Memory Heaps
|
||||
* @page test_sequence_010 [10] Memory Pools
|
||||
*
|
||||
* File: @ref test_sequence_010.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/RT functionalities related to memory
|
||||
* heaps.
|
||||
* pools.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_HEAP
|
||||
* - CH_CFG_USE_MEMPOOLS
|
||||
* .
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_010_001
|
||||
* - @subpage test_010_002
|
||||
* - @subpage test_010_003
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
#define ALLOC_SIZE 16
|
||||
#define HEAP_SIZE (ALLOC_SIZE * 8)
|
||||
#define MEMORY_POOL_SIZE 4
|
||||
|
||||
memory_heap_t test_heap;
|
||||
static uint32_t objects[MEMORY_POOL_SIZE];
|
||||
static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL);
|
||||
|
||||
#if CH_CFG_USE_SEMAPHORES
|
||||
static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t));
|
||||
#endif
|
||||
|
||||
static void *null_provider(size_t size, unsigned align) {
|
||||
|
||||
(void)size;
|
||||
(void)align;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page test_010_001 [10.1] Allocation and fragmentation
|
||||
* @page test_010_001 [10.1] Loading and emptying a memory pool
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Series of allocations/deallocations are performed in carefully
|
||||
* designed sequences in order to stimulate all the possible code paths
|
||||
* inside the allocator. The test expects to find the heap back to the
|
||||
* initial status after each sequence.
|
||||
* The memory pool functionality is tested by loading and emptying it,
|
||||
* all conditions are tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [10.1.1] Testing initial conditions, the heap must not be
|
||||
* fragmented and one free block present.
|
||||
* - [10.1.2] Trying to allocate an block bigger than available space,
|
||||
* an error is expected.
|
||||
* - [10.1.3] Single block allocation using chHeapAlloc() then the
|
||||
* block is freed using chHeapFree(), must not fail.
|
||||
* - [10.1.4] Using chHeapStatus() to assess the heap state. There must
|
||||
* be at least one free block of sufficient size.
|
||||
* - [10.1.5] Allocating then freeing in the same order.
|
||||
* - [10.1.6] Allocating then freeing in reverse order.
|
||||
* - [10.1.7] Small fragments handling. Checking the behavior when
|
||||
* allocating blocks with size not multiple of alignment unit.
|
||||
* - [10.1.8] Skipping a fragment, the first fragment in the list is
|
||||
* too small so the allocator must pick the second one.
|
||||
* - [10.1.9] Allocating the whole available space.
|
||||
* - [10.1.10] Testing final conditions. The heap geometry must be the
|
||||
* same than the one registered at beginning.
|
||||
* - [10.1.1] Adding the objects to the pool using chPoolLoadArray().
|
||||
* - [10.1.2] Emptying the pool using chPoolAlloc().
|
||||
* - [10.1.3] Now must be empty.
|
||||
* - [10.1.4] Adding the objects to the pool using chPoolFree().
|
||||
* - [10.1.5] Emptying the pool using chPoolAlloc() again.
|
||||
* - [10.1.6] Now must be empty again.
|
||||
* - [10.1.7] Covering the case where a provider is unable to return
|
||||
* more memory.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_010_001_setup(void) {
|
||||
chHeapObjectInit(&test_heap, test_buffer, sizeof(test_buffer));
|
||||
chPoolObjectInit(&mp1, sizeof (uint32_t), NULL);
|
||||
}
|
||||
|
||||
static void test_010_001_execute(void) {
|
||||
void *p1, *p2, *p3;
|
||||
size_t n, sz;
|
||||
unsigned i;
|
||||
|
||||
/* [10.1.1] Testing initial conditions, the heap must not be
|
||||
fragmented and one free block present.*/
|
||||
/* [10.1.1] Adding the objects to the pool using chPoolLoadArray().*/
|
||||
test_set_step(1);
|
||||
{
|
||||
test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented");
|
||||
chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE);
|
||||
}
|
||||
|
||||
/* [10.1.2] Trying to allocate an block bigger than available space,
|
||||
an error is expected.*/
|
||||
/* [10.1.2] Emptying the pool using chPoolAlloc().*/
|
||||
test_set_step(2);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, sizeof test_buffer * 2);
|
||||
test_assert(p1 == NULL, "allocation not failed");
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
|
||||
}
|
||||
|
||||
/* [10.1.3] Single block allocation using chHeapAlloc() then the
|
||||
block is freed using chHeapFree(), must not fail.*/
|
||||
/* [10.1.3] Now must be empty.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
test_assert(p1 != NULL, "allocation failed");
|
||||
chHeapFree(p1);
|
||||
test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
|
||||
}
|
||||
|
||||
/* [10.1.4] Using chHeapStatus() to assess the heap state. There must
|
||||
be at least one free block of sufficient size.*/
|
||||
/* [10.1.4] Adding the objects to the pool using chPoolFree().*/
|
||||
test_set_step(4);
|
||||
{
|
||||
size_t total_size, largest_size;
|
||||
|
||||
n = chHeapStatus(&test_heap, &total_size, &largest_size);
|
||||
test_assert(n == 1, "missing free block");
|
||||
test_assert(total_size >= ALLOC_SIZE, "unexpected heap state");
|
||||
test_assert(total_size == largest_size, "unexpected heap state");
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
chPoolFree(&mp1, &objects[i]);
|
||||
}
|
||||
|
||||
/* [10.1.5] Allocating then freeing in the same order.*/
|
||||
/* [10.1.5] Emptying the pool using chPoolAlloc() again.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p1); /* Does not merge.*/
|
||||
chHeapFree(p2); /* Merges backward.*/
|
||||
chHeapFree(p3); /* Merges both sides.*/
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
|
||||
}
|
||||
|
||||
/* [10.1.6] Allocating then freeing in reverse order.*/
|
||||
/* [10.1.6] Now must be empty again.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p3); /* Merges forward.*/
|
||||
chHeapFree(p2); /* Merges forward.*/
|
||||
chHeapFree(p1); /* Merges forward.*/
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
|
||||
}
|
||||
|
||||
/* [10.1.7] Small fragments handling. Checking the behavior when
|
||||
allocating blocks with size not multiple of alignment unit.*/
|
||||
/* [10.1.7] Covering the case where a provider is unable to return
|
||||
more memory.*/
|
||||
test_set_step(7);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p1);
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
/* Note, the first situation happens when the alignment size is smaller
|
||||
than the header size, the second in the other cases.*/
|
||||
test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) ||
|
||||
(chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
|
||||
chHeapFree(p2);
|
||||
chHeapFree(p1);
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
}
|
||||
|
||||
/* [10.1.8] Skipping a fragment, the first fragment in the list is
|
||||
too small so the allocator must pick the second one.*/
|
||||
test_set_step(8);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p1);
|
||||
test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/
|
||||
chHeapFree(p1);
|
||||
chHeapFree(p2);
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
}
|
||||
|
||||
/* [10.1.9] Allocating the whole available space.*/
|
||||
test_set_step(9);
|
||||
{
|
||||
(void)chHeapStatus(&test_heap, &n, NULL);
|
||||
p1 = chHeapAlloc(&test_heap, n);
|
||||
test_assert(p1 != NULL, "allocation failed");
|
||||
test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty");
|
||||
chHeapFree(p1);
|
||||
}
|
||||
|
||||
/* [10.1.10] Testing final conditions. The heap geometry must be the
|
||||
same than the one registered at beginning.*/
|
||||
test_set_step(10);
|
||||
{
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
test_assert(n == sz, "size changed");
|
||||
chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider);
|
||||
test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_010_001 = {
|
||||
"Allocation and fragmentation",
|
||||
"Loading and emptying a memory pool",
|
||||
test_010_001_setup,
|
||||
NULL,
|
||||
test_010_001_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_010_002 [10.2] Default Heap
|
||||
* @page test_010_002 [10.2] Loading and emptying a guarded memory pool without waiting
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The default heap is pre-allocated in the system. We test base
|
||||
* functionality.
|
||||
* The memory pool functionality is tested by loading and emptying it,
|
||||
* all conditions are tested.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [10.2.1] Single block allocation using chHeapAlloc() then the
|
||||
* block is freed using chHeapFree(), must not fail.
|
||||
* - [10.2.2] Testing allocation failure.
|
||||
* - [10.2.1] Adding the objects to the pool using
|
||||
* chGuardedPoolLoadArray().
|
||||
* - [10.2.2] Emptying the pool using chGuardedPoolAllocTimeout().
|
||||
* - [10.2.3] Now must be empty.
|
||||
* - [10.2.4] Adding the objects to the pool using chGuardedPoolFree().
|
||||
* - [10.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
|
||||
* again.
|
||||
* - [10.2.6] Now must be empty again.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_010_002_execute(void) {
|
||||
void *p1;
|
||||
size_t total_size, largest_size;
|
||||
static void test_010_002_setup(void) {
|
||||
chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
|
||||
}
|
||||
|
||||
/* [10.2.1] Single block allocation using chHeapAlloc() then the
|
||||
block is freed using chHeapFree(), must not fail.*/
|
||||
static void test_010_002_execute(void) {
|
||||
unsigned i;
|
||||
|
||||
/* [10.2.1] Adding the objects to the pool using
|
||||
chGuardedPoolLoadArray().*/
|
||||
test_set_step(1);
|
||||
{
|
||||
(void)chHeapStatus(NULL, &total_size, &largest_size);
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
test_assert(p1 != NULL, "allocation failed");
|
||||
chHeapFree(p1);
|
||||
chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE);
|
||||
}
|
||||
|
||||
/* [10.2.2] Testing allocation failure.*/
|
||||
/* [10.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/
|
||||
test_set_step(2);
|
||||
{
|
||||
p1 = chHeapAlloc(NULL, (size_t)-256);
|
||||
test_assert(p1 == NULL, "allocation not failed");
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
|
||||
}
|
||||
|
||||
/* [10.2.3] Now must be empty.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
|
||||
}
|
||||
|
||||
/* [10.2.4] Adding the objects to the pool using
|
||||
chGuardedPoolFree().*/
|
||||
test_set_step(4);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
chGuardedPoolFree(&gmp1, &objects[i]);
|
||||
}
|
||||
|
||||
/* [10.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
|
||||
again.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
for (i = 0; i < MEMORY_POOL_SIZE; i++)
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
|
||||
}
|
||||
|
||||
/* [10.2.6] Now must be empty again.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_010_002 = {
|
||||
"Default Heap",
|
||||
NULL,
|
||||
"Loading and emptying a guarded memory pool without waiting",
|
||||
test_010_002_setup,
|
||||
NULL,
|
||||
test_010_002_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_010_003 [10.3] Guarded Memory Pools timeout
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The timeout features for the Guarded Memory Pools is tested.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [10.3.1] Trying to allocate with 100mS timeout, must fail because
|
||||
* the pool is empty.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_010_003_setup(void) {
|
||||
chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
|
||||
}
|
||||
|
||||
static void test_010_003_execute(void) {
|
||||
|
||||
/* [10.3.1] Trying to allocate with 100mS timeout, must fail because
|
||||
the pool is empty.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_010_003 = {
|
||||
"Guarded Memory Pools timeout",
|
||||
test_010_003_setup,
|
||||
NULL,
|
||||
test_010_003_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Memory Heaps.
|
||||
* @brief Memory Pools.
|
||||
*/
|
||||
const testcase_t * const test_sequence_010[] = {
|
||||
&test_010_001,
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&test_010_002,
|
||||
#endif
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&test_010_003,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_HEAP */
|
||||
#endif /* CH_CFG_USE_MEMPOOLS */
|
||||
|
|
|
@ -22,18 +22,18 @@
|
|||
* @file test_sequence_011.c
|
||||
* @brief Test Sequence 011 code.
|
||||
*
|
||||
* @page test_sequence_011 [11] Dynamic threads
|
||||
* @page test_sequence_011 [11] Memory Heaps
|
||||
*
|
||||
* File: @ref test_sequence_011.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the dynamic thread
|
||||
* creation APIs.
|
||||
* This sequence tests the ChibiOS/RT functionalities related to memory
|
||||
* heaps.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_DYNAMIC
|
||||
* - CH_CFG_USE_HEAP
|
||||
* .
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
|
@ -42,243 +42,231 @@
|
|||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
#if CH_CFG_USE_HEAP
|
||||
static memory_heap_t heap1;
|
||||
#endif
|
||||
#if CH_CFG_USE_MEMPOOLS
|
||||
static memory_pool_t mp1;
|
||||
#endif
|
||||
#define ALLOC_SIZE 16
|
||||
#define HEAP_SIZE (ALLOC_SIZE * 8)
|
||||
|
||||
static THD_FUNCTION(dyn_thread1, p) {
|
||||
|
||||
test_emit_token(*(char *)p);
|
||||
}
|
||||
memory_heap_t test_heap;
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_011_001 [11.1] Threads creation from Memory Heap
|
||||
* @page test_011_001 [11.1] Allocation and fragmentation
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Two threads are started by allocating the memory from the Memory
|
||||
* Heap then a third thread is started with a huge stack
|
||||
* requirement.<br> The test expects the first two threads to
|
||||
* successfully start and the third one to fail.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_HEAP
|
||||
* .
|
||||
* Series of allocations/deallocations are performed in carefully
|
||||
* designed sequences in order to stimulate all the possible code paths
|
||||
* inside the allocator. The test expects to find the heap back to the
|
||||
* initial status after each sequence.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [11.1.1] Getting base priority for threads.
|
||||
* - [11.1.2] Getting heap info before the test.
|
||||
* - [11.1.3] Creating thread 1, it is expected to succeed.
|
||||
* - [11.1.4] Creating thread 2, it is expected to succeed.
|
||||
* - [11.1.5] Creating thread 3, it is expected to fail.
|
||||
* - [11.1.6] Letting threads execute then checking the start order and
|
||||
* freeing memory.
|
||||
* - [11.1.7] Getting heap info again for verification.
|
||||
* - [11.1.1] Testing initial conditions, the heap must not be
|
||||
* fragmented and one free block present.
|
||||
* - [11.1.2] Trying to allocate an block bigger than available space,
|
||||
* an error is expected.
|
||||
* - [11.1.3] Single block allocation using chHeapAlloc() then the
|
||||
* block is freed using chHeapFree(), must not fail.
|
||||
* - [11.1.4] Using chHeapStatus() to assess the heap state. There must
|
||||
* be at least one free block of sufficient size.
|
||||
* - [11.1.5] Allocating then freeing in the same order.
|
||||
* - [11.1.6] Allocating then freeing in reverse order.
|
||||
* - [11.1.7] Small fragments handling. Checking the behavior when
|
||||
* allocating blocks with size not multiple of alignment unit.
|
||||
* - [11.1.8] Skipping a fragment, the first fragment in the list is
|
||||
* too small so the allocator must pick the second one.
|
||||
* - [11.1.9] Allocating the whole available space.
|
||||
* - [11.1.10] Testing final conditions. The heap geometry must be the
|
||||
* same than the one registered at beginning.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_011_001_setup(void) {
|
||||
chHeapObjectInit(&heap1, test_buffer, sizeof test_buffer);
|
||||
chHeapObjectInit(&test_heap, test_buffer, sizeof(test_buffer));
|
||||
}
|
||||
|
||||
static void test_011_001_execute(void) {
|
||||
size_t n1, total1, largest1;
|
||||
size_t n2, total2, largest2;
|
||||
tprio_t prio;
|
||||
void *p1, *p2, *p3;
|
||||
size_t n, sz;
|
||||
|
||||
/* [11.1.1] Getting base priority for threads.*/
|
||||
/* [11.1.1] Testing initial conditions, the heap must not be
|
||||
fragmented and one free block present.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
prio = chThdGetPriorityX();
|
||||
test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented");
|
||||
}
|
||||
|
||||
/* [11.1.2] Getting heap info before the test.*/
|
||||
/* [11.1.2] Trying to allocate an block bigger than available space,
|
||||
an error is expected.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
n1 = chHeapStatus(&heap1, &total1, &largest1);
|
||||
test_assert(n1 == 1, "heap fragmented");
|
||||
p1 = chHeapAlloc(&test_heap, sizeof test_buffer * 2);
|
||||
test_assert(p1 == NULL, "allocation not failed");
|
||||
}
|
||||
|
||||
/* [11.1.3] Creating thread 1, it is expected to succeed.*/
|
||||
/* [11.1.3] Single block allocation using chHeapAlloc() then the
|
||||
block is freed using chHeapFree(), must not fail.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
threads[0] = chThdCreateFromHeap(&heap1,
|
||||
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
|
||||
"dyn1",
|
||||
prio-1, dyn_thread1, "A");
|
||||
test_assert(threads[0] != NULL, "thread creation failed");
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
test_assert(p1 != NULL, "allocation failed");
|
||||
chHeapFree(p1);
|
||||
}
|
||||
|
||||
/* [11.1.4] Creating thread 2, it is expected to succeed.*/
|
||||
/* [11.1.4] Using chHeapStatus() to assess the heap state. There must
|
||||
be at least one free block of sufficient size.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
threads[1] = chThdCreateFromHeap(&heap1,
|
||||
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
|
||||
"dyn2",
|
||||
prio-2, dyn_thread1, "B");
|
||||
test_assert(threads[1] != NULL, "thread creation failed");
|
||||
size_t total_size, largest_size;
|
||||
|
||||
n = chHeapStatus(&test_heap, &total_size, &largest_size);
|
||||
test_assert(n == 1, "missing free block");
|
||||
test_assert(total_size >= ALLOC_SIZE, "unexpected heap state");
|
||||
test_assert(total_size == largest_size, "unexpected heap state");
|
||||
}
|
||||
|
||||
/* [11.1.5] Creating thread 3, it is expected to fail.*/
|
||||
/* [11.1.5] Allocating then freeing in the same order.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
threads[2] = chThdCreateFromHeap(&heap1,
|
||||
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE * 1024),
|
||||
"dyn3",
|
||||
prio-3, dyn_thread1, "C");
|
||||
test_assert(threads[2] == NULL, "thread creation not failed");
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p1); /* Does not merge.*/
|
||||
chHeapFree(p2); /* Merges backward.*/
|
||||
chHeapFree(p3); /* Merges both sides.*/
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
}
|
||||
|
||||
/* [11.1.6] Letting threads execute then checking the start order and
|
||||
freeing memory.*/
|
||||
/* [11.1.6] Allocating then freeing in reverse order.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
test_wait_threads();
|
||||
test_assert_sequence("AB", "invalid sequence");
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p3); /* Merges forward.*/
|
||||
chHeapFree(p2); /* Merges forward.*/
|
||||
chHeapFree(p1); /* Merges forward.*/
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
}
|
||||
|
||||
/* [11.1.7] Getting heap info again for verification.*/
|
||||
/* [11.1.7] Small fragments handling. Checking the behavior when
|
||||
allocating blocks with size not multiple of alignment unit.*/
|
||||
test_set_step(7);
|
||||
{
|
||||
n2 = chHeapStatus(&heap1, &total2, &largest2);
|
||||
test_assert(n1 == n2, "fragmentation changed");
|
||||
test_assert(total1 == total2, "total free space changed");
|
||||
test_assert(largest1 == largest2, "largest fragment size changed");
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p1);
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
/* Note, the first situation happens when the alignment size is smaller
|
||||
than the header size, the second in the other cases.*/
|
||||
test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) ||
|
||||
(chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
|
||||
chHeapFree(p2);
|
||||
chHeapFree(p1);
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
}
|
||||
|
||||
/* [11.1.8] Skipping a fragment, the first fragment in the list is
|
||||
too small so the allocator must pick the second one.*/
|
||||
test_set_step(8);
|
||||
{
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
chHeapFree(p1);
|
||||
test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/
|
||||
chHeapFree(p1);
|
||||
chHeapFree(p2);
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
}
|
||||
|
||||
/* [11.1.9] Allocating the whole available space.*/
|
||||
test_set_step(9);
|
||||
{
|
||||
(void)chHeapStatus(&test_heap, &n, NULL);
|
||||
p1 = chHeapAlloc(&test_heap, n);
|
||||
test_assert(p1 != NULL, "allocation failed");
|
||||
test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty");
|
||||
chHeapFree(p1);
|
||||
}
|
||||
|
||||
/* [11.1.10] Testing final conditions. The heap geometry must be the
|
||||
same than the one registered at beginning.*/
|
||||
test_set_step(10);
|
||||
{
|
||||
test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
test_assert(n == sz, "size changed");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_011_001 = {
|
||||
"Threads creation from Memory Heap",
|
||||
"Allocation and fragmentation",
|
||||
test_011_001_setup,
|
||||
NULL,
|
||||
test_011_001_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_HEAP */
|
||||
|
||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_011_002 [11.2] Threads creation from Memory Pool
|
||||
* @page test_011_002 [11.2] Default Heap
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five thread creation are attempted from a pool containing only four
|
||||
* elements.<br> The test expects the first four threads to
|
||||
* successfully start and the last one to fail.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_MEMPOOLS
|
||||
* .
|
||||
* The default heap is pre-allocated in the system. We test base
|
||||
* functionality.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [11.2.1] Adding four working areas to the pool.
|
||||
* - [11.2.2] Getting base priority for threads.
|
||||
* - [11.2.3] Creating the five threads.
|
||||
* - [11.2.4] Testing that only the fifth thread creation failed.
|
||||
* - [11.2.5] Letting them run, free the memory then checking the
|
||||
* execution sequence.
|
||||
* - [11.2.6] Testing that the pool contains four elements again.
|
||||
* - [11.2.1] Single block allocation using chHeapAlloc() then the
|
||||
* block is freed using chHeapFree(), must not fail.
|
||||
* - [11.2.2] Testing allocation failure.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_011_002_setup(void) {
|
||||
chPoolObjectInit(&mp1, THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), NULL);
|
||||
}
|
||||
|
||||
static void test_011_002_execute(void) {
|
||||
unsigned i;
|
||||
tprio_t prio;
|
||||
void *p1;
|
||||
size_t total_size, largest_size;
|
||||
|
||||
/* [11.2.1] Adding four working areas to the pool.*/
|
||||
/* [11.2.1] Single block allocation using chHeapAlloc() then the
|
||||
block is freed using chHeapFree(), must not fail.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
chPoolFree(&mp1, wa[i]);
|
||||
(void)chHeapStatus(NULL, &total_size, &largest_size);
|
||||
p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
|
||||
test_assert(p1 != NULL, "allocation failed");
|
||||
chHeapFree(p1);
|
||||
}
|
||||
|
||||
/* [11.2.2] Getting base priority for threads.*/
|
||||
/* [11.2.2] Testing allocation failure.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
prio = chThdGetPriorityX();
|
||||
}
|
||||
|
||||
/* [11.2.3] Creating the five threads.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
threads[0] = chThdCreateFromMemoryPool(&mp1, "dyn1", prio-1, dyn_thread1, "A");
|
||||
threads[1] = chThdCreateFromMemoryPool(&mp1, "dyn2", prio-2, dyn_thread1, "B");
|
||||
threads[2] = chThdCreateFromMemoryPool(&mp1, "dyn3", prio-3, dyn_thread1, "C");
|
||||
threads[3] = chThdCreateFromMemoryPool(&mp1, "dyn4", prio-4, dyn_thread1, "D");
|
||||
threads[4] = chThdCreateFromMemoryPool(&mp1, "dyn5", prio-5, dyn_thread1, "E");
|
||||
}
|
||||
|
||||
/* [11.2.4] Testing that only the fifth thread creation failed.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
test_assert((threads[0] != NULL) &&
|
||||
(threads[1] != NULL) &&
|
||||
(threads[2] != NULL) &&
|
||||
(threads[3] != NULL),
|
||||
"thread creation failed");
|
||||
test_assert(threads[4] == NULL,
|
||||
"thread creation not failed");
|
||||
}
|
||||
|
||||
/* [11.2.5] Letting them run, free the memory then checking the
|
||||
execution sequence.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
test_wait_threads();
|
||||
test_assert_sequence("ABCD", "invalid sequence");
|
||||
}
|
||||
|
||||
/* [11.2.6] Testing that the pool contains four elements again.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
test_assert(chPoolAlloc(&mp1) != NULL, "pool list empty");
|
||||
test_assert(chPoolAlloc(&mp1) == NULL, "pool list not empty");
|
||||
p1 = chHeapAlloc(NULL, (size_t)-256);
|
||||
test_assert(p1 == NULL, "allocation not failed");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_011_002 = {
|
||||
"Threads creation from Memory Pool",
|
||||
test_011_002_setup,
|
||||
"Default Heap",
|
||||
NULL,
|
||||
NULL,
|
||||
test_011_002_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_MEMPOOLS */
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Dynamic threads.
|
||||
* @brief Memory Heaps.
|
||||
*/
|
||||
const testcase_t * const test_sequence_011[] = {
|
||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
&test_011_001,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
||||
&test_011_002,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_DYNAMIC */
|
||||
#endif /* CH_CFG_USE_HEAP */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
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 test_sequence_013.h
|
||||
* @brief Test Sequence 013 header.
|
||||
*/
|
||||
|
||||
#ifndef TEST_SEQUENCE_013_H
|
||||
#define TEST_SEQUENCE_013_H
|
||||
|
||||
extern const testcase_t * const test_sequence_013[];
|
||||
|
||||
#endif /* TEST_SEQUENCE_013_H */
|
|
@ -12,7 +12,8 @@ TESTSRC = ${CHIBIOS}/test/lib/ch_test.c \
|
|||
${CHIBIOS}/test/rt/source/test/test_sequence_009.c \
|
||||
${CHIBIOS}/test/rt/source/test/test_sequence_010.c \
|
||||
${CHIBIOS}/test/rt/source/test/test_sequence_011.c \
|
||||
${CHIBIOS}/test/rt/source/test/test_sequence_012.c
|
||||
${CHIBIOS}/test/rt/source/test/test_sequence_012.c \
|
||||
${CHIBIOS}/test/rt/source/test/test_sequence_013.c
|
||||
|
||||
# Required include directories
|
||||
TESTINC = ${CHIBIOS}/test/lib \
|
||||
|
|
Loading…
Reference in New Issue