From 3b3afb7d55d3822b4ae734d166022e327ee0c563 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Sun, 17 Sep 2017 15:38:40 +0000 Subject: [PATCH] Improved RT and NIL test suite. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10614 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- ...C-NUCLEO64 (OpenOCD, Flash and Run).launch | 104 +- readme.txt | 2 + test/nil/configuration.xml | 150 +++ test/nil/source/test/test_root.c | 14 +- test/nil/source/test/test_root.h | 1 + test/nil/source/test/test_sequence_001.c | 162 ++- test/nil/source/test/test_sequence_002.c | 242 ++-- test/nil/source/test/test_sequence_003.c | 246 ++-- test/nil/source/test/test_sequence_004.c | 387 ++---- test/nil/source/test/test_sequence_005.c | 342 ++++-- test/nil/source/test/test_sequence_006.c | 299 ++--- test/nil/source/test/test_sequence_007.c | 273 +++++ test/nil/source/test/test_sequence_007.h | 27 + test/nil/test.mk | 3 +- test/rt/configuration.xml | 204 ++++ test/rt/source/test/test_root.c | 20 +- test/rt/source/test/test_root.h | 1 + test/rt/source/test/test_sequence_001.c | 317 ++--- test/rt/source/test/test_sequence_002.c | 296 ++--- test/rt/source/test/test_sequence_003.c | 306 ++++- test/rt/source/test/test_sequence_004.c | 462 +------ test/rt/source/test/test_sequence_005.c | 1007 ++++------------ test/rt/source/test/test_sequence_006.c | 1018 +++++++++++++++- test/rt/source/test/test_sequence_007.c | 516 +------- test/rt/source/test/test_sequence_008.c | 670 +++++++---- test/rt/source/test/test_sequence_009.c | 345 ++++-- test/rt/source/test/test_sequence_010.c | 299 ++--- test/rt/source/test/test_sequence_011.c | 286 +++-- test/rt/source/test/test_sequence_012.c | 1063 +++-------------- test/rt/source/test/test_sequence_013.c | 1031 ++++++++++++++++ test/rt/source/test/test_sequence_013.h | 27 + test/rt/test.mk | 3 +- 32 files changed, 5473 insertions(+), 4650 deletions(-) create mode 100644 test/nil/source/test/test_sequence_007.c create mode 100644 test/nil/source/test/test_sequence_007.h create mode 100644 test/rt/source/test/test_sequence_013.c create mode 100644 test/rt/source/test/test_sequence_013.h diff --git a/demos/STM32/RT-STM32F091RC-NUCLEO64/debug/RT-STM32F091RC-NUCLEO64 (OpenOCD, Flash and Run).launch b/demos/STM32/RT-STM32F091RC-NUCLEO64/debug/RT-STM32F091RC-NUCLEO64 (OpenOCD, Flash and Run).launch index 42a271817..2d1b49670 100644 --- a/demos/STM32/RT-STM32F091RC-NUCLEO64/debug/RT-STM32F091RC-NUCLEO64 (OpenOCD, Flash and Run).launch +++ b/demos/STM32/RT-STM32F091RC-NUCLEO64/debug/RT-STM32F091RC-NUCLEO64 (OpenOCD, Flash and Run).launch @@ -1,52 +1,52 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/readme.txt b/readme.txt index eeb145313..59fae6a4d 100644 --- a/readme.txt +++ b/readme.txt @@ -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. diff --git a/test/nil/configuration.xml b/test/nil/configuration.xml index 710e9a3be..d58582dd8 100644 --- a/test/nil/configuration.xml +++ b/test/nil/configuration.xml @@ -77,6 +77,156 @@ THD_FUNCTION(test_support, arg) { + + + Internal Tests + + + Information. + + + This sequence reports configuration and version information about the NIL kernel. + + + + + + + + + + + Kernel Info. + + + The version numbers are reported. + + + + + + + + + + + + + + + + + + + Prints the version string. + + + + + + + + + + + + + Kernel Settings. + + + The static kernel settings are reported. + + + + + + + + + + + + + + + + + + + Prints the configuration options settings. + + + + + + + + + + + + Internal Tests diff --git a/test/nil/source/test/test_root.c b/test/nil/source/test/test_root.c index 177a46853..a41bb56bc 100644 --- a/test/nil/source/test/test_root.c +++ b/test/nil/source/test/test_root.c @@ -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 }; diff --git a/test/nil/source/test/test_root.h b/test/nil/source/test/test_root.h index 694abf9c5..a5b5d6958 100644 --- a/test/nil/source/test/test_root.h +++ b/test/nil/source/test/test_root.h @@ -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__) diff --git a/test/nil/source/test/test_sequence_001.c b/test/nil/source/test/test_sequence_001.c index df99ee49b..683a26f3f 100644 --- a/test/nil/source/test/test_sequence_001.c +++ b/test/nil/source/test/test_sequence_001.c @@ -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 * *

Description

- * This sequence tests the ChibiOS/NIL functionalities related to - * threading. + * This sequence reports configuration and version information about + * the NIL kernel. * *

Test Cases

* - @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 * *

Description

- * The functionality of the API @p chVTGetSystemTimeX() is tested. + * The version numbers are reported. * *

Test Steps

- * - [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 * *

Description

- * The functionality of @p chThdSleep() and derivatives is tested. + * The static kernel settings are reported. * *

Test Steps

- * - [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, diff --git a/test/nil/source/test/test_sequence_002.c b/test/nil/source/test/test_sequence_002.c index 1e0f41d43..9e72d707d 100644 --- a/test/nil/source/test/test_sequence_002.c +++ b/test/nil/source/test/test_sequence_002.c @@ -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 * *

Description

* This sequence tests the ChibiOS/NIL functionalities related to - * counter semaphores. - * - *

Conditions

- * This sequence is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_SEMAPHORES - * . + * threading. * *

Test Cases

* - @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 * *

Description

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

Test Steps

- * - [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 * *

Description

- * Wait, Signal and Reset primitives are tested. The testing thread - * triggers a state change. + * The functionality of @p chThdSleep() and derivatives is tested. * *

Test Steps

- * - [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 - * - *

Description

- * Timeout on semaphores is tested. - * - *

Test Steps

- * - [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 */ diff --git a/test/nil/source/test/test_sequence_003.c b/test/nil/source/test/test_sequence_003.c index bf5c7941f..22e233620 100644 --- a/test/nil/source/test/test_sequence_003.c +++ b/test/nil/source/test/test_sequence_003.c @@ -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 * *

Description

* This sequence tests the ChibiOS/NIL functionalities related to - * threads suspend/resume and event flags. + * counter semaphores. + * + *

Conditions

+ * This sequence is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . * *

Test Cases

* - @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 * *

Description

- * The functionality of chThdSuspendTimeoutS() and chThdResumeI() is - * tested. + * Wait, Signal and Reset primitives are tested. The testing thread + * does not trigger a state change. * *

Test Steps

- * - [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 * *

Description

- * Event flags functionality is tested. - * - *

Conditions

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

Test Steps

- * - [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 + * + *

Description

+ * Timeout on semaphores is tested. + * + *

Test Steps

+ * - [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 */ diff --git a/test/nil/source/test/test_sequence_004.c b/test/nil/source/test/test_sequence_004.c index c3f3463d3..52e3e88d0 100644 --- a/test/nil/source/test/test_sequence_004.c +++ b/test/nil/source/test/test_sequence_004.c @@ -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 * *

Description

* This sequence tests the ChibiOS/NIL functionalities related to - * mailboxes. - * - *

Conditions

- * This sequence is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_MAILBOXES - * . + * threads suspend/resume and event flags. * *

Test Cases

* - @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 * *

Description

- * The mailbox normal API is tested without triggering blocking - * conditions. + * The functionality of chThdSuspendTimeoutS() and chThdResumeI() is + * tested. * *

Test Steps

- * - [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 * *

Description

- * The mailbox I-Class API is tested without triggering blocking - * conditions. + * Event flags functionality is tested. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_EVENTS + * . * *

Test Steps

- * - [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 - * - *

Description

- * The mailbox API is tested for timeouts. - * - *

Test Steps

- * - [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 */ diff --git a/test/nil/source/test/test_sequence_005.c b/test/nil/source/test/test_sequence_005.c index 3c0ef8668..70954f1d1 100644 --- a/test/nil/source/test/test_sequence_005.c +++ b/test/nil/source/test/test_sequence_005.c @@ -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 * *

Description

* This sequence tests the ChibiOS/NIL functionalities related to - * memory pools. + * mailboxes. * *

Conditions

* This sequence is only executed if the following preprocessor condition * evaluates to true: - * - CH_CFG_USE_MEMPOOLS + * - CH_CFG_USE_MAILBOXES * . * *

Test Cases

@@ -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 * *

Description

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

Test Steps

- * - [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 * *

Description

- * The memory pool functionality is tested by loading and emptying it, - * all conditions are tested. - * - *

Conditions

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

Test Steps

- * - [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 * *

Description

- * The timeout features for the Guarded Memory Pools is tested. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_SEMAPHORES - * . + * The mailbox API is tested for timeouts. * *

Test Steps

- * - [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 */ diff --git a/test/nil/source/test/test_sequence_006.c b/test/nil/source/test/test_sequence_006.c index ba3e8cbf9..dad464e6c 100644 --- a/test/nil/source/test/test_sequence_006.c +++ b/test/nil/source/test/test_sequence_006.c @@ -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 * *

Description

* This sequence tests the ChibiOS/NIL functionalities related to - * memory heaps. + * memory pools. * *

Conditions

* This sequence is only executed if the following preprocessor condition * evaluates to true: - * - CH_CFG_USE_HEAP + * - CH_CFG_USE_MEMPOOLS * . * *

Test Cases

* - @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 * *

Description

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

Test Steps

- * - [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 * *

Description

- * 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. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . * *

Test Steps

- * - [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 + * + *

Description

+ * The timeout features for the Guarded Memory Pools is tested. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . + * + *

Test Steps

+ * - [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 */ diff --git a/test/nil/source/test/test_sequence_007.c b/test/nil/source/test/test_sequence_007.c new file mode 100644 index 000000000..4cd0c804e --- /dev/null +++ b/test/nil/source/test/test_sequence_007.c @@ -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 + * + *

Description

+ * This sequence tests the ChibiOS/NIL functionalities related to + * memory heaps. + * + *

Conditions

+ * This sequence is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_HEAP + * . + * + *

Test Cases

+ * - @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 + * + *

Description

+ * 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. + * + *

Test Steps

+ * - [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 + * + *

Description

+ * The default heap is pre-allocated in the system. We test base + * functionality. + * + *

Test Steps

+ * - [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 */ diff --git a/test/nil/source/test/test_sequence_007.h b/test/nil/source/test/test_sequence_007.h new file mode 100644 index 000000000..18b68a556 --- /dev/null +++ b/test/nil/source/test/test_sequence_007.h @@ -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 */ diff --git a/test/nil/test.mk b/test/nil/test.mk index 92c30be25..ac60ee95a 100644 --- a/test/nil/test.mk +++ b/test/nil/test.mk @@ -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 \ diff --git a/test/rt/configuration.xml b/test/rt/configuration.xml index 49305faac..dcbdc233d 100644 --- a/test/rt/configuration.xml +++ b/test/rt/configuration.xml @@ -126,6 +126,210 @@ systime_t test_wait_tick(void) { + + + Internal Tests + + + Information. + + + This sequence reports configuration and version information about the RT kernel. + + + + + + + + + + + Kernel Info. + + + The version numbers are reported. + + + + + + + + + + + + + + + + + + + Prints the version string. + + + + + + + + + + + + + Kernel Settings. + + + The static kernel settings are reported. + + + + + + + + + + + + + + + + + + + Prints the configuration options settings. + + + + + + + + + + + + Internal Tests diff --git a/test/rt/source/test/test_root.c b/test/rt/source/test/test_root.c index 5754813ac..876c738fe 100644 --- a/test/rt/source/test/test_root.c +++ b/test/rt/source/test/test_root.c @@ -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 }; diff --git a/test/rt/source/test/test_root.h b/test/rt/source/test/test_root.h index 4fdc5ec57..2a0853df8 100644 --- a/test/rt/source/test/test_root.h +++ b/test/rt/source/test/test_root.h @@ -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__) diff --git a/test/rt/source/test/test_sequence_001.c b/test/rt/source/test/test_sequence_001.c index 9003fa153..6cde4ca1e 100644 --- a/test/rt/source/test/test_sequence_001.c +++ b/test/rt/source/test/test_sequence_001.c @@ -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 * *

Description

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

Test Cases

* - @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 * *

Description

- * The system self-test functionality is invoked in order to make an - * initial system state assessment and for coverage. + * The version numbers are reported. * *

Test Steps

- * - [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 * *

Description

- * The critical zones API is invoked for coverage. + * The static kernel settings are reported. * *

Test Steps

- * - [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 - * - *

Description

- * The interrupts handling API is invoked for coverage. - * - *

Test Steps

- * - [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 - * - *

Description

- * The functionality of the API @p chVTGetSystemTimeX() is tested. - * - *

Test Steps

- * - [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 }; diff --git a/test/rt/source/test/test_sequence_002.c b/test/rt/source/test/test_sequence_002.c index a712021c6..52a3ff7d7 100644 --- a/test/rt/source/test/test_sequence_002.c +++ b/test/rt/source/test/test_sequence_002.c @@ -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 * *

Description

- * 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). * *

Test Cases

* - @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 * *

Description

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

Test Steps

- * - [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 * *

Description

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

Test Steps

- * - [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 * *

Description

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

Test Steps

- * - [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 * *

Description

- * A series of priority changes are performed on the current thread in - * order to verify that the priority change happens as expected. - * - *

Conditions

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

Test Steps

- * - [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 }; diff --git a/test/rt/source/test/test_sequence_003.c b/test/rt/source/test/test_sequence_003.c index 3f29a30c7..4232708c7 100644 --- a/test/rt/source/test/test_sequence_003.c +++ b/test/rt/source/test/test_sequence_003.c @@ -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 * *

Description

* This sequence tests the ChibiOS/RT functionalities related to - * threads suspend/resume. + * threading. * *

Test Cases

* - @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 * *

Description

- * The functionality of chThdSuspendTimeoutS() and chThdResumeI() is - * tested. + * The functionality of @p chThdSleep() and derivatives is tested. * *

Test Steps

- * - [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 + * + *

Description

+ * 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. + * + *

Test Steps

+ * - [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 + * + *

Description

+ * A series of priority changes are performed on the current thread in + * order to verify that the priority change happens as expected. + * + *

Test Steps

+ * - [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 + * + *

Description

+ * A series of priority changes are performed on the current thread in + * order to verify that the priority change happens as expected. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_MUTEXES + * . + * + *

Test Steps

+ * - [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 }; diff --git a/test/rt/source/test/test_sequence_004.c b/test/rt/source/test/test_sequence_004.c index eb62cfb76..d20b36506 100644 --- a/test/rt/source/test/test_sequence_004.c +++ b/test/rt/source/test/test_sequence_004.c @@ -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 * *

Description

* This sequence tests the ChibiOS/RT functionalities related to - * counter semaphores. - * - *

Conditions

- * This sequence is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_SEMAPHORES - * . + * threads suspend/resume. * *

Test Cases

* - @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 * *

Description

- * Wait, Signal and Reset primitives are tested. The testing thread - * does not trigger a state change. + * The functionality of chThdSuspendTimeoutS() and chThdResumeI() is + * tested. * *

Test Steps

- * - [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 - * - *

Description

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

Test Steps

- * - [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 - * - *

Description

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

Test Steps

- * - [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 - * - *

Description

- * The functon is tested by waking up a thread then the semaphore - * counter value is tested. - * - *

Test Steps

- * - [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 - * - *

Description

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

Test Steps

- * - [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 - * - *

Description

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

Test Steps

- * - [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 */ diff --git a/test/rt/source/test/test_sequence_005.c b/test/rt/source/test/test_sequence_005.c index 8b584d4de..4fe9bcc74 100644 --- a/test/rt/source/test/test_sequence_005.c +++ b/test/rt/source/test/test_sequence_005.c @@ -22,18 +22,18 @@ * @file test_sequence_005.c * @brief Test Sequence 005 code. * - * @page test_sequence_005 [5] Mutexes, Condition Variables and Priority Inheritance + * @page test_sequence_005 [5] Counter and Binary Semaphores * * File: @ref test_sequence_005.c * *

Description

* This sequence tests the ChibiOS/RT functionalities related to - * mutexes, condition variables and priority inheritance algorithm. + * counter semaphores. * *

Conditions

* This sequence is only executed if the following preprocessor condition * evaluates to true: - * - CH_CFG_USE_MUTEXES + * - CH_CFG_USE_SEMAPHORES * . * *

Test Cases

@@ -43,1027 +43,466 @@ * - @subpage test_005_004 * - @subpage test_005_005 * - @subpage test_005_006 - * - @subpage test_005_007 - * - @subpage test_005_008 - * - @subpage test_005_009 * . */ -#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__) +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) /**************************************************************************** * Shared code. ****************************************************************************/ -static MUTEX_DECL(m1); -static MUTEX_DECL(m2); -#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__) -static CONDVAR_DECL(c1); -#endif +#include "ch.h" -#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__) -/** - * @brief CPU pulse. - * @note The current implementation is not totally reliable. - * - * @param[in] duration CPU pulse duration in milliseconds - */ -void test_cpu_pulse(unsigned duration) { - systime_t start, end, now; - - start = chThdGetTicksX(chThdGetSelfX()); - end = start + MS2ST(duration); - do { - now = chThdGetTicksX(chThdGetSelfX()); -#if defined(SIMULATOR) - _sim_check_for_interrupts(); -#endif - } - while (chVTIsTimeWithinX(now, start, end)); -} -#endif /* CH_DBG_THREADS_PROFILING */ +static semaphore_t sem1; static THD_FUNCTION(thread1, p) { - chMtxLock(&m1); + chSemWait(&sem1); test_emit_token(*(char *)p); - chMtxUnlock(&m1); } -#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__) -/* Low priority thread */ -static THD_FUNCTION(thread2L, p) { - - (void)p; - chMtxLock(&m1); - test_cpu_pulse(40); - chMtxUnlock(&m1); - test_cpu_pulse(10); - test_emit_token('C'); -} - -/* Medium priority thread */ -static THD_FUNCTION(thread2M, p) { - - (void)p; - chThdSleepMilliseconds(20); - test_cpu_pulse(40); - test_emit_token('B'); -} - -/* High priority thread */ -static THD_FUNCTION(thread2H, p) { - - (void)p; - chThdSleepMilliseconds(40); - chMtxLock(&m1); - test_cpu_pulse(10); - chMtxUnlock(&m1); - test_emit_token('A'); -} - -/* Lowest priority thread */ -static THD_FUNCTION(thread3LL, p) { - - (void)p; - chMtxLock(&m1); - test_cpu_pulse(30); - chMtxUnlock(&m1); - test_emit_token('E'); -} - -/* Low priority thread */ -static THD_FUNCTION(thread3L, p) { - - (void)p; - chThdSleepMilliseconds(10); - chMtxLock(&m2); - test_cpu_pulse(20); - chMtxLock(&m1); - test_cpu_pulse(10); - chMtxUnlock(&m1); - test_cpu_pulse(10); - chMtxUnlock(&m2); - test_emit_token('D'); -} - -/* Medium priority thread */ -static THD_FUNCTION(thread3M, p) { - - (void)p; - chThdSleepMilliseconds(20); - chMtxLock(&m2); - test_cpu_pulse(10); - chMtxUnlock(&m2); - test_emit_token('C'); -} - -/* High priority thread */ -static THD_FUNCTION(thread3H, p) { - - (void)p; - chThdSleepMilliseconds(40); - test_cpu_pulse(20); - test_emit_token('B'); -} - -/* Highest priority thread */ -static THD_FUNCTION(thread3HH, p) { +static THD_FUNCTION(thread2, p) { (void)p; chThdSleepMilliseconds(50); - chMtxLock(&m2); - test_cpu_pulse(10); - chMtxUnlock(&m2); - test_emit_token('A'); -} -#endif /* CH_DBG_THREADS_PROFILING */ - -static THD_FUNCTION(thread4A, p) { - - (void)p; - chThdSleepMilliseconds(50); - chMtxLock(&m1); - chMtxUnlock(&m1); -} - -static THD_FUNCTION(thread4B, p) { - - (void)p; - chThdSleepMilliseconds(150); chSysLock(); - chMtxLockS(&m2); /* For coverage of the chMtxLockS() function variant.*/ - chMtxUnlockS(&m2); /* For coverage of the chMtxUnlockS() function variant.*/ + chSemSignalI(&sem1); /* For coverage reasons */ chSchRescheduleS(); chSysUnlock(); } -#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__) -static THD_FUNCTION(thread6, p) { +static THD_FUNCTION(thread3, p) { - chMtxLock(&m1); - chCondWait(&c1); - test_emit_token(*(char *)p); - chMtxUnlock(&m1); + (void)p; + chSemWait(&sem1); + chSemSignal(&sem1); } -static THD_FUNCTION(thread8, p) { +static THD_FUNCTION(thread4, p) { - chMtxLock(&m2); - chMtxLock(&m1); -#if CH_CFG_USE_CONDVARS_TIMEOUT || defined(__DOXYGEN__) - chCondWaitTimeout(&c1, TIME_INFINITE); -#else - chCondWait(&c1); -#endif - test_emit_token(*(char *)p); - chMtxUnlock(&m1); - chMtxUnlock(&m2); + chBSemSignal((binary_semaphore_t *)p); } -static THD_FUNCTION(thread9, p) { - - chMtxLock(&m2); - test_emit_token(*(char *)p); - chMtxUnlock(&m2); -} -#endif /* CH_CFG_USE_CONDVARS */ - /**************************************************************************** * Test cases. ****************************************************************************/ /** - * @page test_005_001 [5.1] Priority enqueuing test + * @page test_005_001 [5.1] Semaphore primitives, no state change * *

Description

- * Five threads, with increasing priority, are enqueued on a locked - * mutex then the mutex is unlocked. The test expects the threads to - * perform their operations in increasing priority order regardless of - * the initial order. + * Wait, Signal and Reset primitives are tested. The testing thread + * does not trigger a state change. * *

Test Steps

- * - [5.1.1] Getting the initial priority. - * - [5.1.2] Locking the mutex. - * - [5.1.3] Five threads are created that try to lock and unlock the - * mutex then terminate. The threads are created in ascending - * priority order. - * - [5.1.4] Unlocking the mutex, the threads will wakeup in priority - * order because the mutext queue is an ordered one. + * - [5.1.1] The function chSemWait() is invoked, after return the + * counter and the returned message are tested. + * - [5.1.2] The function chSemSignal() is invoked, after return the + * counter is tested. + * - [5.1.3] The function chSemReset() is invoked, after return the + * counter is tested. * . */ static void test_005_001_setup(void) { - chMtxObjectInit(&m1); + chSemObjectInit(&sem1, 1); +} + +static void test_005_001_teardown(void) { + chSemReset(&sem1, 0); } static void test_005_001_execute(void) { - tprio_t prio; - /* [5.1.1] Getting the initial priority.*/ + /* [5.1.1] The function chSemWait() is invoked, after return the + counter and the returned message are tested.*/ test_set_step(1); { - prio = chThdGetPriorityX(); + msg_t msg; + + msg = chSemWait(&sem1); + test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value"); + test_assert(MSG_OK == msg, "wrong returned message"); } - /* [5.1.2] Locking the mutex.*/ + /* [5.1.2] The function chSemSignal() is invoked, after return the + counter is tested.*/ test_set_step(2); { - chMtxLock(&m1); + chSemSignal(&sem1); + test_assert_lock(chSemGetCounterI(&sem1) == 1, "wrong counter value"); } - /* [5.1.3] Five threads are created that try to lock and unlock the - mutex then terminate. The threads are created in ascending - priority order.*/ + /* [5.1.3] The function chSemReset() is invoked, after return the + counter is tested.*/ test_set_step(3); { - threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread1, "E"); - threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread1, "D"); - threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread1, "C"); - threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread1, "B"); - threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread1, "A"); - } - - /* [5.1.4] Unlocking the mutex, the threads will wakeup in priority - order because the mutext queue is an ordered one.*/ - test_set_step(4); - { - chMtxUnlock(&m1); - test_wait_threads(); - test_assert(prio == chThdGetPriorityX(), "wrong priority level"); - test_assert_sequence("ABCDE", "invalid sequence"); + chSemReset(&sem1, 2); + test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value"); } } static const testcase_t test_005_001 = { - "Priority enqueuing test", + "Semaphore primitives, no state change", test_005_001_setup, - NULL, + test_005_001_teardown, test_005_001_execute }; -#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__) /** - * @page test_005_002 [5.2] Priority inheritance, simple case + * @page test_005_002 [5.2] Semaphore enqueuing test * *

Description

- * Three threads are involved in the classic priority inversion - * scenario, a medium priority thread tries to starve an high priority - * thread by blocking a low priority thread into a mutex lock zone. The - * test expects the threads to reach their goal in increasing priority - * order by rearranging their priorities in order to avoid the priority - * inversion trap. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_DBG_THREADS_PROFILING - * . + * 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. * *

Test Steps

- * - [5.2.1] Getting the system time for test duration measurement. - * - [5.2.2] The three contenders threads are created and let run - * atomically, the goals sequence is tested, the threads must - * complete in priority order. - * - [5.2.3] Testing that all threads completed within the specified - * time windows (100mS...100mS+ALLOWED_DELAY). + * - [5.2.1] Five threads are created with mixed priority levels (not + * increasing nor decreasing). Threads enqueue on a semaphore + * initialized to zero. + * - [5.2.2] The semaphore is signaled 5 times. The thread activation + * sequence is tested. * . */ static void test_005_002_setup(void) { - chMtxObjectInit(&m1); + chSemObjectInit(&sem1, 0); } static void test_005_002_execute(void) { - systime_t time; - /* [5.2.1] Getting the system time for test duration measurement.*/ + /* [5.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); { - time = test_wait_tick(); + 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"); } - /* [5.2.2] The three contenders threads are created and let run - atomically, the goals sequence is tested, the threads must - complete in priority order.*/ + /* [5.2.2] The semaphore is signaled 5 times. The thread activation + sequence is tested.*/ test_set_step(2); { - threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread2H, 0); - threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-2, thread2M, 0); - threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread2L, 0); + chSemSignal(&sem1); + chSemSignal(&sem1); + chSemSignal(&sem1); + chSemSignal(&sem1); + chSemSignal(&sem1); test_wait_threads(); - test_assert_sequence("ABC", "invalid sequence"); - } - - /* [5.2.3] Testing that all threads completed within the specified - time windows (100mS...100mS+ALLOWED_DELAY).*/ - test_set_step(3); - { - test_assert_time_window(time + MS2ST(100), time + MS2ST(100) + ALLOWED_DELAY, - "out of time window"); +#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_005_002 = { - "Priority inheritance, simple case", + "Semaphore enqueuing test", test_005_002_setup, NULL, test_005_002_execute }; -#endif /* CH_DBG_THREADS_PROFILING */ -#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__) /** - * @page test_005_003 [5.3] Priority inheritance, complex case + * @page test_005_003 [5.3] Semaphore timeout test * *

Description

- * Five threads are involved in the complex priority inversion - * scenario, the priority inheritance algorithm is tested for depths - * greater than one. The test expects the threads to perform their - * operations in increasing priority order by rearranging their - * priorities in order to avoid the priority inversion trap. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_DBG_THREADS_PROFILING - * . + * 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. * *

Test Steps

- * - [5.3.1] Getting the system time for test duration measurement. - * - [5.3.2] The five contenders threads are created and let run - * atomically, the goals sequence is tested, the threads must - * complete in priority order. - * - [5.3.3] Testing that all threads completed within the specified - * time windows (110mS...110mS+ALLOWED_DELAY). + * - [5.3.1] Testing special case TIME_IMMEDIATE. + * - [5.3.2] Testing non-timeout condition. + * - [5.3.3] Testing timeout condition. * . */ static void test_005_003_setup(void) { - chMtxObjectInit(&m1); /* Mutex B.*/ - chMtxObjectInit(&m2); /* Mutex A.*/ + chSemObjectInit(&sem1, 0); } static void test_005_003_execute(void) { - systime_t time; + unsigned i; + systime_t target_time; + msg_t msg; - /* [5.3.1] Getting the system time for test duration measurement.*/ + /* [5.3.1] Testing special case TIME_IMMEDIATE.*/ test_set_step(1); { - time = test_wait_tick(); + 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"); } - /* [5.3.2] The five contenders threads are created and let run - atomically, the goals sequence is tested, the threads must - complete in priority order.*/ + /* [5.3.2] Testing non-timeout condition.*/ test_set_step(2); { - threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread3LL, 0); - threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread3L, 0); - threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread3M, 0); - threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread3H, 0); - threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread3HH, 0); + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1, + thread2, 0); + msg = chSemWaitTimeout(&sem1, MS2ST(500)); test_wait_threads(); - test_assert_sequence("ABCDE", "invalid sequence"); + 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"); } - /* [5.3.3] Testing that all threads completed within the specified - time windows (110mS...110mS+ALLOWED_DELAY).*/ + /* [5.3.3] Testing timeout condition.*/ test_set_step(3); { - test_assert_time_window(time + MS2ST(110), time + MS2ST(110) + ALLOWED_DELAY, + 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_005_003 = { - "Priority inheritance, complex case", + "Semaphore timeout test", test_005_003_setup, NULL, test_005_003_execute }; -#endif /* CH_DBG_THREADS_PROFILING */ /** - * @page test_005_004 [5.4] Priority return verification + * @page test_005_004 [5.4] Testing chSemAddCounterI() functionality * *

Description

- * Two threads are spawned that try to lock the mutexes already locked - * by the tester thread with precise timing. The test expects that the - * priority changes caused by the priority inheritance algorithm happen - * at the right moment and with the right values.
Thread A performs - * wait(50), lock(m1), unlock(m1), exit. Thread B performs wait(150), - * lock(m2), unlock(m2), exit. + * The functon is tested by waking up a thread then the semaphore + * counter value is tested. * *

Test Steps

- * - [5.4.1] Getting current thread priority P(0) and assigning to the - * threads A and B priorities +1 and +2. - * - [5.4.2] Spawning threads A and B at priorities P(A) and P(B). - * - [5.4.3] Locking the mutex M1 before thread A has a chance to lock - * it. The priority must not change because A has not yet reached - * chMtxLock(M1). the mutex is not locked. - * - [5.4.4] Waiting 100mS, this makes thread A reach chMtxLock(M1) and - * get the mutex. This must boost the priority of the current thread - * at the same level of thread A. - * - [5.4.5] Locking the mutex M2 before thread B has a chance to lock - * it. The priority must not change because B has not yet reached - * chMtxLock(M2). the mutex is not locked. - * - [5.4.6] Waiting 100mS, this makes thread B reach chMtxLock(M2) and - * get the mutex. This must boost the priority of the current thread - * at the same level of thread B. - * - [5.4.7] Unlocking M2, the priority should fall back to P(A). - * - [5.4.8] Unlocking M1, the priority should fall back to P(0). + * - [5.4.1] A thread is created, it goes to wait on the semaphore. + * - [5.4.2] The semaphore counter is increased by two, it is then + * tested to be one, the thread must have completed. * . */ static void test_005_004_setup(void) { - chMtxObjectInit(&m1); - chMtxObjectInit(&m2); -} - -static void test_005_004_teardown(void) { - test_wait_threads(); + chSemObjectInit(&sem1, 0); } static void test_005_004_execute(void) { - tprio_t p, pa, pb; - /* [5.4.1] Getting current thread priority P(0) and assigning to the - threads A and B priorities +1 and +2.*/ + /* [5.4.1] A thread is created, it goes to wait on the semaphore.*/ test_set_step(1); { - p = chThdGetPriorityX(); - pa = p + 1; - pb = p + 2; + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread1, "A"); } - /* [5.4.2] Spawning threads A and B at priorities P(A) and P(B).*/ + /* [5.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); { - threads[0] = chThdCreateStatic(wa[0], WA_SIZE, pa, thread4A, "A"); - threads[1] = chThdCreateStatic(wa[1], WA_SIZE, pb, thread4B, "B"); - } - - /* [5.4.3] Locking the mutex M1 before thread A has a chance to lock - it. The priority must not change because A has not yet reached - chMtxLock(M1). the mutex is not locked.*/ - test_set_step(3); - { - chMtxLock(&m1); - test_assert(chThdGetPriorityX() == p, "wrong priority level"); - } - - /* [5.4.4] Waiting 100mS, this makes thread A reach chMtxLock(M1) and - get the mutex. This must boost the priority of the current thread - at the same level of thread A.*/ - test_set_step(4); - { - chThdSleepMilliseconds(100); - test_assert(chThdGetPriorityX() == pa, "wrong priority level"); - } - - /* [5.4.5] Locking the mutex M2 before thread B has a chance to lock - it. The priority must not change because B has not yet reached - chMtxLock(M2). the mutex is not locked.*/ - test_set_step(5); - { - chMtxLock(&m2); - test_assert(chThdGetPriorityX() == pa, "wrong priority level"); - } - - /* [5.4.6] Waiting 100mS, this makes thread B reach chMtxLock(M2) and - get the mutex. This must boost the priority of the current thread - at the same level of thread B.*/ - test_set_step(6); - { - chThdSleepMilliseconds(100); - test_assert(chThdGetPriorityX() == pb, "wrong priority level"); - } - - /* [5.4.7] Unlocking M2, the priority should fall back to P(A).*/ - test_set_step(7); - { - chMtxUnlock(&m2); - test_assert(chThdGetPriorityX() == pa, "wrong priority level"); - } - - /* [5.4.8] Unlocking M1, the priority should fall back to P(0).*/ - test_set_step(8); - { - chMtxUnlock(&m1); - test_assert(chThdGetPriorityX() == p, "wrong priority level"); + 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_005_004 = { - "Priority return verification", + "Testing chSemAddCounterI() functionality", test_005_004_setup, - test_005_004_teardown, + NULL, test_005_004_execute }; -#if (!CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__) /** - * @page test_005_005 [5.5] Repeated locks, non recursive scenario + * @page test_005_005 [5.5] Testing chSemWaitSignal() functionality * *

Description

- * The behavior of multiple mutex locks from the same thread is tested - * when recursion is disabled. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - !CH_CFG_USE_MUTEXES_RECURSIVE - * . + * 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. * *

Test Steps

- * - [5.5.1] Getting current thread priority for later checks. - * - [5.5.2] Locking the mutex first time, it must be possible because - * it is not owned. - * - [5.5.3] Locking the mutex second time, it must fail because it is - * already owned. - * - [5.5.4] Unlocking the mutex then it must not be owned anymore and - * the queue must be empty. - * - [5.5.5] Testing that priority has not changed after operations. - * - [5.5.6] Testing chMtxUnlockAll() behavior. - * - [5.5.7] Testing that priority has not changed after operations. + * - [5.5.1] An higher priority thread is created that performs + * non-atomical wait and signal operations on a semaphore. + * - [5.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. + * - [5.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_005_005_setup(void) { - chMtxObjectInit(&m1); + chSemObjectInit(&sem1, 0); +} + +static void test_005_005_teardown(void) { + test_wait_threads(); } static void test_005_005_execute(void) { - bool b; - tprio_t prio; - /* [5.5.1] Getting current thread priority for later checks.*/ + /* [5.5.1] An higher priority thread is created that performs + non-atomical wait and signal operations on a semaphore.*/ test_set_step(1); { - prio = chThdGetPriorityX(); + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread3, 0); } - /* [5.5.2] Locking the mutex first time, it must be possible because - it is not owned.*/ + /* [5.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); { - b = chMtxTryLock(&m1); - test_assert(b, "already locked"); + chSemSignalWait(&sem1, &sem1); + test_assert(queue_isempty(&sem1.queue), "queue not empty"); + test_assert(sem1.cnt == 0, "counter not zero"); } - /* [5.5.3] Locking the mutex second time, it must fail because it is - already owned.*/ + /* [5.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); { - b = chMtxTryLock(&m1); - test_assert(!b, "not locked"); - } - - /* [5.5.4] Unlocking the mutex then it must not be owned anymore and - the queue must be empty.*/ - test_set_step(4); - { - chMtxUnlock(&m1); - test_assert(m1.owner == NULL, "still owned"); - test_assert(queue_isempty(&m1.queue), "queue not empty"); - } - - /* [5.5.5] Testing that priority has not changed after operations.*/ - test_set_step(5); - { - test_assert(chThdGetPriorityX() == prio, "wrong priority level"); - } - - /* [5.5.6] Testing chMtxUnlockAll() behavior.*/ - test_set_step(6); - { - b = chMtxTryLock(&m1); - test_assert(b, "already locked"); - b = chMtxTryLock(&m1); - test_assert(!b, "not locked"); - - chMtxUnlockAll(); - test_assert(m1.owner == NULL, "still owned"); - test_assert(queue_isempty(&m1.queue), "queue not empty"); - } - - /* [5.5.7] Testing that priority has not changed after operations.*/ - test_set_step(7); - { - test_assert(chThdGetPriorityX() == prio, "wrong priority level"); + 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_005_005 = { - "Repeated locks, non recursive scenario", + "Testing chSemWaitSignal() functionality", test_005_005_setup, - NULL, + test_005_005_teardown, test_005_005_execute }; -#endif /* !CH_CFG_USE_MUTEXES_RECURSIVE */ -#if (CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__) /** - * @page test_005_006 [5.6] Repeated locks using, recursive scenario + * @page test_005_006 [5.6] Testing Binary Semaphores special case * *

Description

- * The behavior of multiple mutex locks from the same thread is tested - * when recursion is enabled. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_MUTEXES_RECURSIVE - * . + * 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. * *

Test Steps

- * - [5.6.1] Getting current thread priority for later checks. - * - [5.6.2] Locking the mutex first time, it must be possible because - * it is not owned. - * - [5.6.3] Locking the mutex second time, it must be possible because - * it is recursive. - * - [5.6.4] Unlocking the mutex then it must be still owned because - * recursivity. - * - [5.6.5] Unlocking the mutex then it must not be owned anymore and - * the queue must be empty. - * - [5.6.6] Testing that priority has not changed after operations. - * - [5.6.7] Testing consecutive chMtxTryLock()/chMtxTryLockS() calls - * and a final chMtxUnlockAllS(). - * - [5.6.8] Testing consecutive chMtxLock()/chMtxLockS() calls and a - * final chMtxUnlockAll(). - * - [5.6.9] Testing that priority has not changed after operations. + * - [5.6.1] Creating a binary semaphore in "taken" state, the state is + * checked. + * - [5.6.2] Resetting the binary semaphore in "taken" state, the state + * must not change. + * - [5.6.3] Starting a signaler thread at a lower priority. + * - [5.6.4] Waiting for the binary semaphore to be signaled, the + * semaphore is expected to be taken. + * - [5.6.5] Signaling the binary semaphore, checking the binary + * semaphore state to be "not taken" and the underlying counter + * semaphore counter to be one. + * - [5.6.6] Signaling the binary semaphore again, the internal state + * must not change from "not taken". * . */ -static void test_005_006_setup(void) { - chMtxObjectInit(&m1); +static void test_005_006_teardown(void) { + test_wait_threads(); } static void test_005_006_execute(void) { - bool b; - tprio_t prio; + binary_semaphore_t bsem; + msg_t msg; - /* [5.6.1] Getting current thread priority for later checks.*/ + /* [5.6.1] Creating a binary semaphore in "taken" state, the state is + checked.*/ test_set_step(1); { - prio = chThdGetPriorityX(); + chBSemObjectInit(&bsem, true); + test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken"); } - /* [5.6.2] Locking the mutex first time, it must be possible because - it is not owned.*/ + /* [5.6.2] Resetting the binary semaphore in "taken" state, the state + must not change.*/ test_set_step(2); { - b = chMtxTryLock(&m1); - test_assert(b, "already locked"); + chBSemReset(&bsem, true); + test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken"); } - /* [5.6.3] Locking the mutex second time, it must be possible because - it is recursive.*/ + /* [5.6.3] Starting a signaler thread at a lower priority.*/ test_set_step(3); { - b = chMtxTryLock(&m1); - test_assert(b, "already locked"); + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, + chThdGetPriorityX()-1, thread4, &bsem); } - /* [5.6.4] Unlocking the mutex then it must be still owned because - recursivity.*/ + /* [5.6.4] Waiting for the binary semaphore to be signaled, the + semaphore is expected to be taken.*/ test_set_step(4); { - chMtxUnlock(&m1); - test_assert(m1.owner != NULL, "not owned"); + msg = chBSemWait(&bsem); + test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken"); + test_assert(msg == MSG_OK, "unexpected message"); } - /* [5.6.5] Unlocking the mutex then it must not be owned anymore and - the queue must be empty.*/ + /* [5.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); { - chMtxUnlock(&m1); - test_assert(m1.owner == NULL, "still owned"); - test_assert(queue_isempty(&m1.queue), "queue not empty"); + chBSemSignal(&bsem); + test_assert_lock(chBSemGetStateI(&bsem) ==false, "still taken"); + test_assert_lock(chSemGetCounterI(&bsem.sem) == 1, "unexpected counter"); } - /* [5.6.6] Testing that priority has not changed after operations.*/ + /* [5.6.6] Signaling the binary semaphore again, the internal state + must not change from "not taken".*/ test_set_step(6); { - test_assert(chThdGetPriorityX() == prio, "wrong priority level"); - } - - /* [5.6.7] Testing consecutive chMtxTryLock()/chMtxTryLockS() calls - and a final chMtxUnlockAllS().*/ - test_set_step(7); - { - b = chMtxTryLock(&m1); - test_assert(b, "already locked"); - chSysLock(); - b = chMtxTryLockS(&m1); - chSysUnlock(); - test_assert(b, "already locked"); - test_assert(m1.cnt == 2, "invalid recursion counter"); - chSysLock(); - chMtxUnlockAllS(); - chSysUnlock(); - test_assert(m1.owner == NULL, "still owned"); - test_assert(queue_isempty(&m1.queue), "queue not empty"); - test_assert(m1.cnt == 0, "invalid recursion counter"); - } - - /* [5.6.8] Testing consecutive chMtxLock()/chMtxLockS() calls and a - final chMtxUnlockAll().*/ - test_set_step(8); - { - chMtxLock(&m1); - test_assert(m1.owner != NULL, "not owned"); - chSysLock(); - chMtxLockS(&m1); - chSysUnlock(); - test_assert(m1.owner != NULL, "not owned"); - test_assert(m1.cnt == 2, "invalid recursion counter"); - chMtxUnlockAll(); - test_assert(m1.owner == NULL, "still owned"); - test_assert(queue_isempty(&m1.queue), "queue not empty"); - test_assert(m1.cnt == 0, "invalid recursion counter"); - } - - /* [5.6.9] Testing that priority has not changed after operations.*/ - test_set_step(9); - { - test_assert(chThdGetPriorityX() == prio, "wrong priority level"); + chBSemSignal(&bsem); + test_assert_lock(chBSemGetStateI(&bsem) == false, "taken"); + test_assert_lock(chSemGetCounterI(&bsem.sem) == 1, "unexpected counter"); } } static const testcase_t test_005_006 = { - "Repeated locks using, recursive scenario", - test_005_006_setup, + "Testing Binary Semaphores special case", NULL, + test_005_006_teardown, test_005_006_execute }; -#endif /* CH_CFG_USE_MUTEXES_RECURSIVE */ - -#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__) -/** - * @page test_005_007 [5.7] Condition Variable signal test - * - *

Description

- * Five threads take a mutex and then enter a conditional variable - * queue, the tester thread then proceeds to signal the conditional - * variable five times atomically.
The test expects the threads to - * reach their goal in increasing priority order regardless of the - * initial order. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_CONDVARS - * . - * - *

Test Steps

- * - [5.7.1] Starting the five threads with increasing priority, the - * threads will queue on the condition variable. - * - [5.7.2] Atomically signaling the condition variable five times - * then waiting for the threads to terminate in priority order, the - * order is tested. - * . - */ - -static void test_005_007_setup(void) { - chCondObjectInit(&c1); - chMtxObjectInit(&m1); -} - -static void test_005_007_execute(void) { - - /* [5.7.1] Starting the five threads with increasing priority, the - threads will queue on the condition variable.*/ - test_set_step(1); - { - tprio_t prio = chThdGetPriorityX(); - threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread6, "E"); - threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread6, "D"); - threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread6, "C"); - threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread6, "B"); - threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread6, "A"); - } - - /* [5.7.2] Atomically signaling the condition variable five times - then waiting for the threads to terminate in priority order, the - order is tested.*/ - test_set_step(2); - { - chSysLock(); - chCondSignalI(&c1); - chCondSignalI(&c1); - chCondSignalI(&c1); - chCondSignalI(&c1); - chCondSignalI(&c1); - chSchRescheduleS(); - chSysUnlock(); - test_wait_threads(); - test_assert_sequence("ABCDE", "invalid sequence"); - } -} - -static const testcase_t test_005_007 = { - "Condition Variable signal test", - test_005_007_setup, - NULL, - test_005_007_execute -}; -#endif /* CH_CFG_USE_CONDVARS */ - -#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__) -/** - * @page test_005_008 [5.8] Condition Variable broadcast test - * - *

Description

- * Five threads take a mutex and then enter a conditional variable - * queue, the tester thread then proceeds to broadcast the conditional - * variable.
The test expects the threads to reach their goal in - * increasing priority order regardless of the initial order. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_CONDVARS - * . - * - *

Test Steps

- * - [5.8.1] Starting the five threads with increasing priority, the - * threads will queue on the condition variable. - * - [5.8.2] Broarcasting on the condition variable then waiting for - * the threads to terminate in priority order, the order is tested. - * . - */ - -static void test_005_008_setup(void) { - chCondObjectInit(&c1); - chMtxObjectInit(&m1); -} - -static void test_005_008_execute(void) { - - /* [5.8.1] Starting the five threads with increasing priority, the - threads will queue on the condition variable.*/ - test_set_step(1); - { - tprio_t prio = chThdGetPriorityX(); - threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread6, "E"); - threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread6, "D"); - threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread6, "C"); - threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread6, "B"); - threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread6, "A"); - } - - /* [5.8.2] Broarcasting on the condition variable then waiting for - the threads to terminate in priority order, the order is tested.*/ - test_set_step(2); - { - chCondBroadcast(&c1); - test_wait_threads(); - test_assert_sequence("ABCDE", "invalid sequence"); - } -} - -static const testcase_t test_005_008 = { - "Condition Variable broadcast test", - test_005_008_setup, - NULL, - test_005_008_execute -}; -#endif /* CH_CFG_USE_CONDVARS */ - -#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__) -/** - * @page test_005_009 [5.9] Condition Variable priority boost test - * - *

Description

- * This test case verifies the priority boost of a thread waiting on a - * conditional variable queue. It tests this very specific situation in - * order to improve code coverage. The created threads perform the - * following operations: TA{lock(M2), lock(M1), wait(C1), unlock(M1), - * unlock(M2)}, TB{lock(M2), wait(C1), unlock(M2)}. TC{lock(M1), - * unlock(M1)}. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_CONDVARS - * . - * - *

Test Steps

- * - [5.9.1] Reading current base priority. - * - [5.9.2] Thread A is created at priority P(+1), it locks M2, locks - * M1 and goes to wait on C1. - * - [5.9.3] Thread C is created at priority P(+2), it enqueues on M1 - * and boosts TA priority at P(+2). - * - [5.9.4] Thread B is created at priority P(+3), it enqueues on M2 - * and boosts TA priority at P(+3). - * - [5.9.5] Signaling C1: TA wakes up, unlocks M1 and priority goes to - * P(+2). TB locks M1, unlocks M1 and completes. TA unlocks M2 and - * priority goes to P(+1). TC waits on C1. TA completes. - * - [5.9.6] Signaling C1: TC wakes up, unlocks M1 and completes. - * - [5.9.7] Checking the order of operations. - * . - */ - -static void test_005_009_setup(void) { - chCondObjectInit(&c1); - chMtxObjectInit(&m1); - chMtxObjectInit(&m2); -} - -static void test_005_009_execute(void) { - tprio_t prio; - - /* [5.9.1] Reading current base priority.*/ - test_set_step(1); - { - prio = chThdGetPriorityX(); - } - - /* [5.9.2] Thread A is created at priority P(+1), it locks M2, locks - M1 and goes to wait on C1.*/ - test_set_step(2); - { - threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread8, "A"); - } - - /* [5.9.3] Thread C is created at priority P(+2), it enqueues on M1 - and boosts TA priority at P(+2).*/ - test_set_step(3); - { - threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread6, "C"); - } - - /* [5.9.4] Thread B is created at priority P(+3), it enqueues on M2 - and boosts TA priority at P(+3).*/ - test_set_step(4); - { - threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread9, "B"); - } - - /* [5.9.5] Signaling C1: TA wakes up, unlocks M1 and priority goes to - P(+2). TB locks M1, unlocks M1 and completes. TA unlocks M2 and - priority goes to P(+1). TC waits on C1. TA completes.*/ - test_set_step(5); - { - chCondSignal(&c1); - } - - /* [5.9.6] Signaling C1: TC wakes up, unlocks M1 and completes.*/ - test_set_step(6); - { - chCondSignal(&c1); - } - - /* [5.9.7] Checking the order of operations.*/ - test_set_step(7); - { - test_wait_threads(); - test_assert_sequence("ABC", "invalid sequence"); - } -} - -static const testcase_t test_005_009 = { - "Condition Variable priority boost test", - test_005_009_setup, - NULL, - test_005_009_execute -}; -#endif /* CH_CFG_USE_CONDVARS */ /**************************************************************************** * Exported data. ****************************************************************************/ /** - * @brief Mutexes, Condition Variables and Priority Inheritance. + * @brief Counter and Binary Semaphores. */ const testcase_t * const test_sequence_005[] = { &test_005_001, -#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__) &test_005_002, -#endif -#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__) &test_005_003, -#endif &test_005_004, -#if (!CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__) &test_005_005, -#endif -#if (CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__) &test_005_006, -#endif -#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__) - &test_005_007, -#endif -#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__) - &test_005_008, -#endif -#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__) - &test_005_009, -#endif NULL }; -#endif /* CH_CFG_USE_MUTEXES */ +#endif /* CH_CFG_USE_SEMAPHORES */ diff --git a/test/rt/source/test/test_sequence_006.c b/test/rt/source/test/test_sequence_006.c index 509a3a465..4c7ad2e52 100644 --- a/test/rt/source/test/test_sequence_006.c +++ b/test/rt/source/test/test_sequence_006.c @@ -22,102 +22,1048 @@ * @file test_sequence_006.c * @brief Test Sequence 006 code. * - * @page test_sequence_006 [6] Synchronous Messages + * @page test_sequence_006 [6] Mutexes, Condition Variables and Priority Inheritance * * File: @ref test_sequence_006.c * *

Description

- * This module implements the test sequence for the Synchronous - * Messages subsystem. + * This sequence tests the ChibiOS/RT functionalities related to + * mutexes, condition variables and priority inheritance algorithm. * *

Conditions

* This sequence is only executed if the following preprocessor condition * evaluates to true: - * - CH_CFG_USE_MESSAGES + * - CH_CFG_USE_MUTEXES * . * *

Test Cases

* - @subpage test_006_001 + * - @subpage test_006_002 + * - @subpage test_006_003 + * - @subpage test_006_004 + * - @subpage test_006_005 + * - @subpage test_006_006 + * - @subpage test_006_007 + * - @subpage test_006_008 + * - @subpage test_006_009 * . */ -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) +#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__) /**************************************************************************** * Shared code. ****************************************************************************/ -static THD_FUNCTION(msg_thread1, p) { +static MUTEX_DECL(m1); +static MUTEX_DECL(m2); +#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__) +static CONDVAR_DECL(c1); +#endif - chMsgSend(p, 'A'); - chMsgSend(p, 'B'); - chMsgSend(p, 'C'); - chMsgSend(p, 'D'); +#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__) +/** + * @brief CPU pulse. + * @note The current implementation is not totally reliable. + * + * @param[in] duration CPU pulse duration in milliseconds + */ +void test_cpu_pulse(unsigned duration) { + systime_t start, end, now; + + start = chThdGetTicksX(chThdGetSelfX()); + end = start + MS2ST(duration); + do { + now = chThdGetTicksX(chThdGetSelfX()); +#if defined(SIMULATOR) + _sim_check_for_interrupts(); +#endif + } + while (chVTIsTimeWithinX(now, start, end)); } +#endif /* CH_DBG_THREADS_PROFILING */ + +static THD_FUNCTION(thread1, p) { + + chMtxLock(&m1); + test_emit_token(*(char *)p); + chMtxUnlock(&m1); +} + +#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__) +/* Low priority thread */ +static THD_FUNCTION(thread2L, p) { + + (void)p; + chMtxLock(&m1); + test_cpu_pulse(40); + chMtxUnlock(&m1); + test_cpu_pulse(10); + test_emit_token('C'); +} + +/* Medium priority thread */ +static THD_FUNCTION(thread2M, p) { + + (void)p; + chThdSleepMilliseconds(20); + test_cpu_pulse(40); + test_emit_token('B'); +} + +/* High priority thread */ +static THD_FUNCTION(thread2H, p) { + + (void)p; + chThdSleepMilliseconds(40); + chMtxLock(&m1); + test_cpu_pulse(10); + chMtxUnlock(&m1); + test_emit_token('A'); +} + +/* Lowest priority thread */ +static THD_FUNCTION(thread3LL, p) { + + (void)p; + chMtxLock(&m1); + test_cpu_pulse(30); + chMtxUnlock(&m1); + test_emit_token('E'); +} + +/* Low priority thread */ +static THD_FUNCTION(thread3L, p) { + + (void)p; + chThdSleepMilliseconds(10); + chMtxLock(&m2); + test_cpu_pulse(20); + chMtxLock(&m1); + test_cpu_pulse(10); + chMtxUnlock(&m1); + test_cpu_pulse(10); + chMtxUnlock(&m2); + test_emit_token('D'); +} + +/* Medium priority thread */ +static THD_FUNCTION(thread3M, p) { + + (void)p; + chThdSleepMilliseconds(20); + chMtxLock(&m2); + test_cpu_pulse(10); + chMtxUnlock(&m2); + test_emit_token('C'); +} + +/* High priority thread */ +static THD_FUNCTION(thread3H, p) { + + (void)p; + chThdSleepMilliseconds(40); + test_cpu_pulse(20); + test_emit_token('B'); +} + +/* Highest priority thread */ +static THD_FUNCTION(thread3HH, p) { + + (void)p; + chThdSleepMilliseconds(50); + chMtxLock(&m2); + test_cpu_pulse(10); + chMtxUnlock(&m2); + test_emit_token('A'); +} +#endif /* CH_DBG_THREADS_PROFILING */ + +static THD_FUNCTION(thread4A, p) { + + (void)p; + chThdSleepMilliseconds(50); + chMtxLock(&m1); + chMtxUnlock(&m1); +} + +static THD_FUNCTION(thread4B, p) { + + (void)p; + chThdSleepMilliseconds(150); + chSysLock(); + chMtxLockS(&m2); /* For coverage of the chMtxLockS() function variant.*/ + chMtxUnlockS(&m2); /* For coverage of the chMtxUnlockS() function variant.*/ + chSchRescheduleS(); + chSysUnlock(); +} + +#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__) +static THD_FUNCTION(thread6, p) { + + chMtxLock(&m1); + chCondWait(&c1); + test_emit_token(*(char *)p); + chMtxUnlock(&m1); +} + +static THD_FUNCTION(thread8, p) { + + chMtxLock(&m2); + chMtxLock(&m1); +#if CH_CFG_USE_CONDVARS_TIMEOUT || defined(__DOXYGEN__) + chCondWaitTimeout(&c1, TIME_INFINITE); +#else + chCondWait(&c1); +#endif + test_emit_token(*(char *)p); + chMtxUnlock(&m1); + chMtxUnlock(&m2); +} + +static THD_FUNCTION(thread9, p) { + + chMtxLock(&m2); + test_emit_token(*(char *)p); + chMtxUnlock(&m2); +} +#endif /* CH_CFG_USE_CONDVARS */ /**************************************************************************** * Test cases. ****************************************************************************/ /** - * @page test_006_001 [6.1] Messages Server loop + * @page test_006_001 [6.1] Priority enqueuing test * *

Description

- * A messenger thread is spawned that sends four messages back to the - * tester thread.
The test expect to receive the messages in the - * correct sequence and to not find a fifth message waiting. + * Five threads, with increasing priority, are enqueued on a locked + * mutex then the mutex is unlocked. The test expects the threads to + * perform their operations in increasing priority order regardless of + * the initial order. * *

Test Steps

- * - [6.1.1] Starting the messenger thread. - * - [6.1.2] Waiting for four messages then testing the receive order. + * - [6.1.1] Getting the initial priority. + * - [6.1.2] Locking the mutex. + * - [6.1.3] Five threads are created that try to lock and unlock the + * mutex then terminate. The threads are created in ascending + * priority order. + * - [6.1.4] Unlocking the mutex, the threads will wakeup in priority + * order because the mutext queue is an ordered one. * . */ -static void test_006_001_execute(void) { - thread_t *tp; - msg_t msg; +static void test_006_001_setup(void) { + chMtxObjectInit(&m1); +} - /* [6.1.1] Starting the messenger thread.*/ +static void test_006_001_execute(void) { + tprio_t prio; + + /* [6.1.1] Getting the initial priority.*/ test_set_step(1); { - threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() + 1, - msg_thread1, chThdGetSelfX()); + prio = chThdGetPriorityX(); } - /* [6.1.2] Waiting for four messages then testing the receive - order.*/ + /* [6.1.2] Locking the mutex.*/ test_set_step(2); { - unsigned i; + chMtxLock(&m1); + } - for (i = 0; i < 4; i++) { - tp = chMsgWait(); - msg = chMsgGet(tp); - chMsgRelease(tp, msg); - test_emit_token(msg); - } + /* [6.1.3] Five threads are created that try to lock and unlock the + mutex then terminate. The threads are created in ascending + priority order.*/ + test_set_step(3); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread1, "E"); + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread1, "D"); + threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread1, "C"); + threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread1, "B"); + threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread1, "A"); + } + + /* [6.1.4] Unlocking the mutex, the threads will wakeup in priority + order because the mutext queue is an ordered one.*/ + test_set_step(4); + { + chMtxUnlock(&m1); test_wait_threads(); - test_assert_sequence("ABCD", "invalid sequence"); + test_assert(prio == chThdGetPriorityX(), "wrong priority level"); + test_assert_sequence("ABCDE", "invalid sequence"); } } static const testcase_t test_006_001 = { - "Messages Server loop", - NULL, + "Priority enqueuing test", + test_006_001_setup, NULL, test_006_001_execute }; +#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__) +/** + * @page test_006_002 [6.2] Priority inheritance, simple case + * + *

Description

+ * Three threads are involved in the classic priority inversion + * scenario, a medium priority thread tries to starve an high priority + * thread by blocking a low priority thread into a mutex lock zone. The + * test expects the threads to reach their goal in increasing priority + * order by rearranging their priorities in order to avoid the priority + * inversion trap. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_DBG_THREADS_PROFILING + * . + * + *

Test Steps

+ * - [6.2.1] Getting the system time for test duration measurement. + * - [6.2.2] The three contenders threads are created and let run + * atomically, the goals sequence is tested, the threads must + * complete in priority order. + * - [6.2.3] Testing that all threads completed within the specified + * time windows (100mS...100mS+ALLOWED_DELAY). + * . + */ + +static void test_006_002_setup(void) { + chMtxObjectInit(&m1); +} + +static void test_006_002_execute(void) { + systime_t time; + + /* [6.2.1] Getting the system time for test duration measurement.*/ + test_set_step(1); + { + time = test_wait_tick(); + } + + /* [6.2.2] The three contenders threads are created and let run + atomically, the goals sequence is tested, the threads must + complete in priority order.*/ + test_set_step(2); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread2H, 0); + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-2, thread2M, 0); + threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread2L, 0); + test_wait_threads(); + test_assert_sequence("ABC", "invalid sequence"); + } + + /* [6.2.3] Testing that all threads completed within the specified + time windows (100mS...100mS+ALLOWED_DELAY).*/ + test_set_step(3); + { + test_assert_time_window(time + MS2ST(100), time + MS2ST(100) + ALLOWED_DELAY, + "out of time window"); + } +} + +static const testcase_t test_006_002 = { + "Priority inheritance, simple case", + test_006_002_setup, + NULL, + test_006_002_execute +}; +#endif /* CH_DBG_THREADS_PROFILING */ + +#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__) +/** + * @page test_006_003 [6.3] Priority inheritance, complex case + * + *

Description

+ * Five threads are involved in the complex priority inversion + * scenario, the priority inheritance algorithm is tested for depths + * greater than one. The test expects the threads to perform their + * operations in increasing priority order by rearranging their + * priorities in order to avoid the priority inversion trap. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_DBG_THREADS_PROFILING + * . + * + *

Test Steps

+ * - [6.3.1] Getting the system time for test duration measurement. + * - [6.3.2] The five contenders threads are created and let run + * atomically, the goals sequence is tested, the threads must + * complete in priority order. + * - [6.3.3] Testing that all threads completed within the specified + * time windows (110mS...110mS+ALLOWED_DELAY). + * . + */ + +static void test_006_003_setup(void) { + chMtxObjectInit(&m1); /* Mutex B.*/ + chMtxObjectInit(&m2); /* Mutex A.*/ +} + +static void test_006_003_execute(void) { + systime_t time; + + /* [6.3.1] Getting the system time for test duration measurement.*/ + test_set_step(1); + { + time = test_wait_tick(); + } + + /* [6.3.2] The five contenders threads are created and let run + atomically, the goals sequence is tested, the threads must + complete in priority order.*/ + test_set_step(2); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread3LL, 0); + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread3L, 0); + threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread3M, 0); + threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread3H, 0); + threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread3HH, 0); + test_wait_threads(); + test_assert_sequence("ABCDE", "invalid sequence"); + } + + /* [6.3.3] Testing that all threads completed within the specified + time windows (110mS...110mS+ALLOWED_DELAY).*/ + test_set_step(3); + { + test_assert_time_window(time + MS2ST(110), time + MS2ST(110) + ALLOWED_DELAY, + "out of time window"); + } +} + +static const testcase_t test_006_003 = { + "Priority inheritance, complex case", + test_006_003_setup, + NULL, + test_006_003_execute +}; +#endif /* CH_DBG_THREADS_PROFILING */ + +/** + * @page test_006_004 [6.4] Priority return verification + * + *

Description

+ * Two threads are spawned that try to lock the mutexes already locked + * by the tester thread with precise timing. The test expects that the + * priority changes caused by the priority inheritance algorithm happen + * at the right moment and with the right values.
Thread A performs + * wait(50), lock(m1), unlock(m1), exit. Thread B performs wait(150), + * lock(m2), unlock(m2), exit. + * + *

Test Steps

+ * - [6.4.1] Getting current thread priority P(0) and assigning to the + * threads A and B priorities +1 and +2. + * - [6.4.2] Spawning threads A and B at priorities P(A) and P(B). + * - [6.4.3] Locking the mutex M1 before thread A has a chance to lock + * it. The priority must not change because A has not yet reached + * chMtxLock(M1). the mutex is not locked. + * - [6.4.4] Waiting 100mS, this makes thread A reach chMtxLock(M1) and + * get the mutex. This must boost the priority of the current thread + * at the same level of thread A. + * - [6.4.5] Locking the mutex M2 before thread B has a chance to lock + * it. The priority must not change because B has not yet reached + * chMtxLock(M2). the mutex is not locked. + * - [6.4.6] Waiting 100mS, this makes thread B reach chMtxLock(M2) and + * get the mutex. This must boost the priority of the current thread + * at the same level of thread B. + * - [6.4.7] Unlocking M2, the priority should fall back to P(A). + * - [6.4.8] Unlocking M1, the priority should fall back to P(0). + * . + */ + +static void test_006_004_setup(void) { + chMtxObjectInit(&m1); + chMtxObjectInit(&m2); +} + +static void test_006_004_teardown(void) { + test_wait_threads(); +} + +static void test_006_004_execute(void) { + tprio_t p, pa, pb; + + /* [6.4.1] Getting current thread priority P(0) and assigning to the + threads A and B priorities +1 and +2.*/ + test_set_step(1); + { + p = chThdGetPriorityX(); + pa = p + 1; + pb = p + 2; + } + + /* [6.4.2] Spawning threads A and B at priorities P(A) and P(B).*/ + test_set_step(2); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, pa, thread4A, "A"); + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, pb, thread4B, "B"); + } + + /* [6.4.3] Locking the mutex M1 before thread A has a chance to lock + it. The priority must not change because A has not yet reached + chMtxLock(M1). the mutex is not locked.*/ + test_set_step(3); + { + chMtxLock(&m1); + test_assert(chThdGetPriorityX() == p, "wrong priority level"); + } + + /* [6.4.4] Waiting 100mS, this makes thread A reach chMtxLock(M1) and + get the mutex. This must boost the priority of the current thread + at the same level of thread A.*/ + test_set_step(4); + { + chThdSleepMilliseconds(100); + test_assert(chThdGetPriorityX() == pa, "wrong priority level"); + } + + /* [6.4.5] Locking the mutex M2 before thread B has a chance to lock + it. The priority must not change because B has not yet reached + chMtxLock(M2). the mutex is not locked.*/ + test_set_step(5); + { + chMtxLock(&m2); + test_assert(chThdGetPriorityX() == pa, "wrong priority level"); + } + + /* [6.4.6] Waiting 100mS, this makes thread B reach chMtxLock(M2) and + get the mutex. This must boost the priority of the current thread + at the same level of thread B.*/ + test_set_step(6); + { + chThdSleepMilliseconds(100); + test_assert(chThdGetPriorityX() == pb, "wrong priority level"); + } + + /* [6.4.7] Unlocking M2, the priority should fall back to P(A).*/ + test_set_step(7); + { + chMtxUnlock(&m2); + test_assert(chThdGetPriorityX() == pa, "wrong priority level"); + } + + /* [6.4.8] Unlocking M1, the priority should fall back to P(0).*/ + test_set_step(8); + { + chMtxUnlock(&m1); + test_assert(chThdGetPriorityX() == p, "wrong priority level"); + } +} + +static const testcase_t test_006_004 = { + "Priority return verification", + test_006_004_setup, + test_006_004_teardown, + test_006_004_execute +}; + +#if (!CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__) +/** + * @page test_006_005 [6.5] Repeated locks, non recursive scenario + * + *

Description

+ * The behavior of multiple mutex locks from the same thread is tested + * when recursion is disabled. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - !CH_CFG_USE_MUTEXES_RECURSIVE + * . + * + *

Test Steps

+ * - [6.5.1] Getting current thread priority for later checks. + * - [6.5.2] Locking the mutex first time, it must be possible because + * it is not owned. + * - [6.5.3] Locking the mutex second time, it must fail because it is + * already owned. + * - [6.5.4] Unlocking the mutex then it must not be owned anymore and + * the queue must be empty. + * - [6.5.5] Testing that priority has not changed after operations. + * - [6.5.6] Testing chMtxUnlockAll() behavior. + * - [6.5.7] Testing that priority has not changed after operations. + * . + */ + +static void test_006_005_setup(void) { + chMtxObjectInit(&m1); +} + +static void test_006_005_execute(void) { + bool b; + tprio_t prio; + + /* [6.5.1] Getting current thread priority for later checks.*/ + test_set_step(1); + { + prio = chThdGetPriorityX(); + } + + /* [6.5.2] Locking the mutex first time, it must be possible because + it is not owned.*/ + test_set_step(2); + { + b = chMtxTryLock(&m1); + test_assert(b, "already locked"); + } + + /* [6.5.3] Locking the mutex second time, it must fail because it is + already owned.*/ + test_set_step(3); + { + b = chMtxTryLock(&m1); + test_assert(!b, "not locked"); + } + + /* [6.5.4] Unlocking the mutex then it must not be owned anymore and + the queue must be empty.*/ + test_set_step(4); + { + chMtxUnlock(&m1); + test_assert(m1.owner == NULL, "still owned"); + test_assert(queue_isempty(&m1.queue), "queue not empty"); + } + + /* [6.5.5] Testing that priority has not changed after operations.*/ + test_set_step(5); + { + test_assert(chThdGetPriorityX() == prio, "wrong priority level"); + } + + /* [6.5.6] Testing chMtxUnlockAll() behavior.*/ + test_set_step(6); + { + b = chMtxTryLock(&m1); + test_assert(b, "already locked"); + b = chMtxTryLock(&m1); + test_assert(!b, "not locked"); + + chMtxUnlockAll(); + test_assert(m1.owner == NULL, "still owned"); + test_assert(queue_isempty(&m1.queue), "queue not empty"); + } + + /* [6.5.7] Testing that priority has not changed after operations.*/ + test_set_step(7); + { + test_assert(chThdGetPriorityX() == prio, "wrong priority level"); + } +} + +static const testcase_t test_006_005 = { + "Repeated locks, non recursive scenario", + test_006_005_setup, + NULL, + test_006_005_execute +}; +#endif /* !CH_CFG_USE_MUTEXES_RECURSIVE */ + +#if (CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__) +/** + * @page test_006_006 [6.6] Repeated locks using, recursive scenario + * + *

Description

+ * The behavior of multiple mutex locks from the same thread is tested + * when recursion is enabled. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_MUTEXES_RECURSIVE + * . + * + *

Test Steps

+ * - [6.6.1] Getting current thread priority for later checks. + * - [6.6.2] Locking the mutex first time, it must be possible because + * it is not owned. + * - [6.6.3] Locking the mutex second time, it must be possible because + * it is recursive. + * - [6.6.4] Unlocking the mutex then it must be still owned because + * recursivity. + * - [6.6.5] Unlocking the mutex then it must not be owned anymore and + * the queue must be empty. + * - [6.6.6] Testing that priority has not changed after operations. + * - [6.6.7] Testing consecutive chMtxTryLock()/chMtxTryLockS() calls + * and a final chMtxUnlockAllS(). + * - [6.6.8] Testing consecutive chMtxLock()/chMtxLockS() calls and a + * final chMtxUnlockAll(). + * - [6.6.9] Testing that priority has not changed after operations. + * . + */ + +static void test_006_006_setup(void) { + chMtxObjectInit(&m1); +} + +static void test_006_006_execute(void) { + bool b; + tprio_t prio; + + /* [6.6.1] Getting current thread priority for later checks.*/ + test_set_step(1); + { + prio = chThdGetPriorityX(); + } + + /* [6.6.2] Locking the mutex first time, it must be possible because + it is not owned.*/ + test_set_step(2); + { + b = chMtxTryLock(&m1); + test_assert(b, "already locked"); + } + + /* [6.6.3] Locking the mutex second time, it must be possible because + it is recursive.*/ + test_set_step(3); + { + b = chMtxTryLock(&m1); + test_assert(b, "already locked"); + } + + /* [6.6.4] Unlocking the mutex then it must be still owned because + recursivity.*/ + test_set_step(4); + { + chMtxUnlock(&m1); + test_assert(m1.owner != NULL, "not owned"); + } + + /* [6.6.5] Unlocking the mutex then it must not be owned anymore and + the queue must be empty.*/ + test_set_step(5); + { + chMtxUnlock(&m1); + test_assert(m1.owner == NULL, "still owned"); + test_assert(queue_isempty(&m1.queue), "queue not empty"); + } + + /* [6.6.6] Testing that priority has not changed after operations.*/ + test_set_step(6); + { + test_assert(chThdGetPriorityX() == prio, "wrong priority level"); + } + + /* [6.6.7] Testing consecutive chMtxTryLock()/chMtxTryLockS() calls + and a final chMtxUnlockAllS().*/ + test_set_step(7); + { + b = chMtxTryLock(&m1); + test_assert(b, "already locked"); + chSysLock(); + b = chMtxTryLockS(&m1); + chSysUnlock(); + test_assert(b, "already locked"); + test_assert(m1.cnt == 2, "invalid recursion counter"); + chSysLock(); + chMtxUnlockAllS(); + chSysUnlock(); + test_assert(m1.owner == NULL, "still owned"); + test_assert(queue_isempty(&m1.queue), "queue not empty"); + test_assert(m1.cnt == 0, "invalid recursion counter"); + } + + /* [6.6.8] Testing consecutive chMtxLock()/chMtxLockS() calls and a + final chMtxUnlockAll().*/ + test_set_step(8); + { + chMtxLock(&m1); + test_assert(m1.owner != NULL, "not owned"); + chSysLock(); + chMtxLockS(&m1); + chSysUnlock(); + test_assert(m1.owner != NULL, "not owned"); + test_assert(m1.cnt == 2, "invalid recursion counter"); + chMtxUnlockAll(); + test_assert(m1.owner == NULL, "still owned"); + test_assert(queue_isempty(&m1.queue), "queue not empty"); + test_assert(m1.cnt == 0, "invalid recursion counter"); + } + + /* [6.6.9] Testing that priority has not changed after operations.*/ + test_set_step(9); + { + test_assert(chThdGetPriorityX() == prio, "wrong priority level"); + } +} + +static const testcase_t test_006_006 = { + "Repeated locks using, recursive scenario", + test_006_006_setup, + NULL, + test_006_006_execute +}; +#endif /* CH_CFG_USE_MUTEXES_RECURSIVE */ + +#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__) +/** + * @page test_006_007 [6.7] Condition Variable signal test + * + *

Description

+ * Five threads take a mutex and then enter a conditional variable + * queue, the tester thread then proceeds to signal the conditional + * variable five times atomically.
The test expects the threads to + * reach their goal in increasing priority order regardless of the + * initial order. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_CONDVARS + * . + * + *

Test Steps

+ * - [6.7.1] Starting the five threads with increasing priority, the + * threads will queue on the condition variable. + * - [6.7.2] Atomically signaling the condition variable five times + * then waiting for the threads to terminate in priority order, the + * order is tested. + * . + */ + +static void test_006_007_setup(void) { + chCondObjectInit(&c1); + chMtxObjectInit(&m1); +} + +static void test_006_007_execute(void) { + + /* [6.7.1] Starting the five threads with increasing priority, the + threads will queue on the condition variable.*/ + test_set_step(1); + { + tprio_t prio = chThdGetPriorityX(); + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread6, "E"); + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread6, "D"); + threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread6, "C"); + threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread6, "B"); + threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread6, "A"); + } + + /* [6.7.2] Atomically signaling the condition variable five times + then waiting for the threads to terminate in priority order, the + order is tested.*/ + test_set_step(2); + { + chSysLock(); + chCondSignalI(&c1); + chCondSignalI(&c1); + chCondSignalI(&c1); + chCondSignalI(&c1); + chCondSignalI(&c1); + chSchRescheduleS(); + chSysUnlock(); + test_wait_threads(); + test_assert_sequence("ABCDE", "invalid sequence"); + } +} + +static const testcase_t test_006_007 = { + "Condition Variable signal test", + test_006_007_setup, + NULL, + test_006_007_execute +}; +#endif /* CH_CFG_USE_CONDVARS */ + +#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__) +/** + * @page test_006_008 [6.8] Condition Variable broadcast test + * + *

Description

+ * Five threads take a mutex and then enter a conditional variable + * queue, the tester thread then proceeds to broadcast the conditional + * variable.
The test expects the threads to reach their goal in + * increasing priority order regardless of the initial order. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_CONDVARS + * . + * + *

Test Steps

+ * - [6.8.1] Starting the five threads with increasing priority, the + * threads will queue on the condition variable. + * - [6.8.2] Broarcasting on the condition variable then waiting for + * the threads to terminate in priority order, the order is tested. + * . + */ + +static void test_006_008_setup(void) { + chCondObjectInit(&c1); + chMtxObjectInit(&m1); +} + +static void test_006_008_execute(void) { + + /* [6.8.1] Starting the five threads with increasing priority, the + threads will queue on the condition variable.*/ + test_set_step(1); + { + tprio_t prio = chThdGetPriorityX(); + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread6, "E"); + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread6, "D"); + threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread6, "C"); + threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread6, "B"); + threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread6, "A"); + } + + /* [6.8.2] Broarcasting on the condition variable then waiting for + the threads to terminate in priority order, the order is tested.*/ + test_set_step(2); + { + chCondBroadcast(&c1); + test_wait_threads(); + test_assert_sequence("ABCDE", "invalid sequence"); + } +} + +static const testcase_t test_006_008 = { + "Condition Variable broadcast test", + test_006_008_setup, + NULL, + test_006_008_execute +}; +#endif /* CH_CFG_USE_CONDVARS */ + +#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__) +/** + * @page test_006_009 [6.9] Condition Variable priority boost test + * + *

Description

+ * This test case verifies the priority boost of a thread waiting on a + * conditional variable queue. It tests this very specific situation in + * order to improve code coverage. The created threads perform the + * following operations: TA{lock(M2), lock(M1), wait(C1), unlock(M1), + * unlock(M2)}, TB{lock(M2), wait(C1), unlock(M2)}. TC{lock(M1), + * unlock(M1)}. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_CONDVARS + * . + * + *

Test Steps

+ * - [6.9.1] Reading current base priority. + * - [6.9.2] Thread A is created at priority P(+1), it locks M2, locks + * M1 and goes to wait on C1. + * - [6.9.3] Thread C is created at priority P(+2), it enqueues on M1 + * and boosts TA priority at P(+2). + * - [6.9.4] Thread B is created at priority P(+3), it enqueues on M2 + * and boosts TA priority at P(+3). + * - [6.9.5] Signaling C1: TA wakes up, unlocks M1 and priority goes to + * P(+2). TB locks M1, unlocks M1 and completes. TA unlocks M2 and + * priority goes to P(+1). TC waits on C1. TA completes. + * - [6.9.6] Signaling C1: TC wakes up, unlocks M1 and completes. + * - [6.9.7] Checking the order of operations. + * . + */ + +static void test_006_009_setup(void) { + chCondObjectInit(&c1); + chMtxObjectInit(&m1); + chMtxObjectInit(&m2); +} + +static void test_006_009_execute(void) { + tprio_t prio; + + /* [6.9.1] Reading current base priority.*/ + test_set_step(1); + { + prio = chThdGetPriorityX(); + } + + /* [6.9.2] Thread A is created at priority P(+1), it locks M2, locks + M1 and goes to wait on C1.*/ + test_set_step(2); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread8, "A"); + } + + /* [6.9.3] Thread C is created at priority P(+2), it enqueues on M1 + and boosts TA priority at P(+2).*/ + test_set_step(3); + { + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread6, "C"); + } + + /* [6.9.4] Thread B is created at priority P(+3), it enqueues on M2 + and boosts TA priority at P(+3).*/ + test_set_step(4); + { + threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread9, "B"); + } + + /* [6.9.5] Signaling C1: TA wakes up, unlocks M1 and priority goes to + P(+2). TB locks M1, unlocks M1 and completes. TA unlocks M2 and + priority goes to P(+1). TC waits on C1. TA completes.*/ + test_set_step(5); + { + chCondSignal(&c1); + } + + /* [6.9.6] Signaling C1: TC wakes up, unlocks M1 and completes.*/ + test_set_step(6); + { + chCondSignal(&c1); + } + + /* [6.9.7] Checking the order of operations.*/ + test_set_step(7); + { + test_wait_threads(); + test_assert_sequence("ABC", "invalid sequence"); + } +} + +static const testcase_t test_006_009 = { + "Condition Variable priority boost test", + test_006_009_setup, + NULL, + test_006_009_execute +}; +#endif /* CH_CFG_USE_CONDVARS */ + /**************************************************************************** * Exported data. ****************************************************************************/ /** - * @brief Synchronous Messages. + * @brief Mutexes, Condition Variables and Priority Inheritance. */ const testcase_t * const test_sequence_006[] = { &test_006_001, +#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__) + &test_006_002, +#endif +#if (CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__) + &test_006_003, +#endif + &test_006_004, +#if (!CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__) + &test_006_005, +#endif +#if (CH_CFG_USE_MUTEXES_RECURSIVE) || defined(__DOXYGEN__) + &test_006_006, +#endif +#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__) + &test_006_007, +#endif +#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__) + &test_006_008, +#endif +#if (CH_CFG_USE_CONDVARS) || defined(__DOXYGEN__) + &test_006_009, +#endif NULL }; -#endif /* CH_CFG_USE_MESSAGES */ +#endif /* CH_CFG_USE_MUTEXES */ diff --git a/test/rt/source/test/test_sequence_007.c b/test/rt/source/test/test_sequence_007.c index fc4c3f0ec..cf7828f90 100644 --- a/test/rt/source/test/test_sequence_007.c +++ b/test/rt/source/test/test_sequence_007.c @@ -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 * *

Description

- * This module implements the test sequence for the Events subsystem. + * This module implements the test sequence for the Synchronous + * Messages subsystem. * *

Conditions

* This sequence is only executed if the following preprocessor condition * evaluates to true: - * - CH_CFG_USE_EVENTS + * - CH_CFG_USE_MESSAGES * . * *

Test Cases

* - @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 * *

Description

- * Two event listeners are registered on an event source and then - * unregistered in the same order.
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.
The test expect to receive the messages in the + * correct sequence and to not find a fifth message waiting. * *

Test Steps

- * - [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 - * - *

Description

- * The test dispatches three event flags and verifies that the - * associated event handlers are invoked in LSb-first order. - * - *

Test Steps

- * - [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() - * - *

Description

- * Functionality of chEvtWaitOne() is tested under various scenarios. - * - *

Test Steps

- * - [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() - * - *

Description

- * Functionality of chEvtWaitAny() is tested under various scenarios. - * - *

Test Steps

- * - [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() - * - *

Description

- * Functionality of chEvtWaitAll() is tested under various scenarios. - * - *

Test Steps

- * - [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 - * - *

Description

- * Timeout functionality is tested for chEvtWaitOneTimeout(), - * chEvtWaitAnyTimeout() and chEvtWaitAllTimeout(). - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_EVENTS_TIMEOUT - * . - * - *

Test Steps

- * - [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() - * - *

Description

- * Functionality of chEvtBroadcast() is tested. - * - *

Test Steps

- * - [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 */ diff --git a/test/rt/source/test/test_sequence_008.c b/test/rt/source/test/test_sequence_008.c index 349e1a9d0..bc3b222ab 100644 --- a/test/rt/source/test/test_sequence_008.c +++ b/test/rt/source/test/test_sequence_008.c @@ -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 * *

Description

- * This sequence tests the ChibiOS/RT functionalities related to - * mailboxes. + * This module implements the test sequence for the Events subsystem. * *

Conditions

* This sequence is only executed if the following preprocessor condition * evaluates to true: - * - CH_CFG_USE_MAILBOXES + * - CH_CFG_USE_EVENTS * . * *

Test Cases

* - @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 * *

Description

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

Test Steps

- * - [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 * *

Description

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

Test Steps

- * - [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() * *

Description

- * The mailbox API is tested for timeouts. + * Functionality of chEvtWaitOne() is tested under various scenarios. * *

Test Steps

- * - [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() + * + *

Description

+ * Functionality of chEvtWaitAny() is tested under various scenarios. + * + *

Test Steps

+ * - [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() + * + *

Description

+ * Functionality of chEvtWaitAll() is tested under various scenarios. + * + *

Test Steps

+ * - [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 + * + *

Description

+ * Timeout functionality is tested for chEvtWaitOneTimeout(), + * chEvtWaitAnyTimeout() and chEvtWaitAllTimeout(). + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_EVENTS_TIMEOUT + * . + * + *

Test Steps

+ * - [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() + * + *

Description

+ * Functionality of chEvtBroadcast() is tested. + * + *

Test Steps

+ * - [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 */ diff --git a/test/rt/source/test/test_sequence_009.c b/test/rt/source/test/test_sequence_009.c index 6f4650b8a..e722da0c4 100644 --- a/test/rt/source/test/test_sequence_009.c +++ b/test/rt/source/test/test_sequence_009.c @@ -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 * *

Description

- * This sequence tests the ChibiOS/RT functionalities related to memory - * pools. + * This sequence tests the ChibiOS/RT functionalities related to + * mailboxes. * *

Conditions

* This sequence is only executed if the following preprocessor condition * evaluates to true: - * - CH_CFG_USE_MEMPOOLS + * - CH_CFG_USE_MAILBOXES * . * *

Test Cases

@@ -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 * *

Description

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

Test Steps

- * - [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 * *

Description

- * The memory pool functionality is tested by loading and emptying it, - * all conditions are tested. - * - *

Conditions

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

Test Steps

- * - [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 * *

Description

- * The timeout features for the Guarded Memory Pools is tested. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_SEMAPHORES - * . + * The mailbox API is tested for timeouts. * *

Test Steps

- * - [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 */ diff --git a/test/rt/source/test/test_sequence_010.c b/test/rt/source/test/test_sequence_010.c index 480021eb6..72828ad86 100644 --- a/test/rt/source/test/test_sequence_010.c +++ b/test/rt/source/test/test_sequence_010.c @@ -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 * *

Description

* This sequence tests the ChibiOS/RT functionalities related to memory - * heaps. + * pools. * *

Conditions

* This sequence is only executed if the following preprocessor condition * evaluates to true: - * - CH_CFG_USE_HEAP + * - CH_CFG_USE_MEMPOOLS * . * *

Test Cases

* - @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 * *

Description

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

Test Steps

- * - [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 * *

Description

- * 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. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . * *

Test Steps

- * - [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 + * + *

Description

+ * The timeout features for the Guarded Memory Pools is tested. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . + * + *

Test Steps

+ * - [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 */ diff --git a/test/rt/source/test/test_sequence_011.c b/test/rt/source/test/test_sequence_011.c index 14ac5c051..1e5b4ee5f 100644 --- a/test/rt/source/test/test_sequence_011.c +++ b/test/rt/source/test/test_sequence_011.c @@ -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 * *

Description

- * This module implements the test sequence for the dynamic thread - * creation APIs. + * This sequence tests the ChibiOS/RT functionalities related to memory + * heaps. * *

Conditions

* This sequence is only executed if the following preprocessor condition * evaluates to true: - * - CH_CFG_USE_DYNAMIC + * - CH_CFG_USE_HEAP * . * *

Test Cases

@@ -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 * *

Description

- * Two threads are started by allocating the memory from the Memory - * Heap then a third thread is started with a huge stack - * requirement.
The test expects the first two threads to - * successfully start and the third one to fail. - * - *

Conditions

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

Test Steps

- * - [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 * *

Description

- * Five thread creation are attempted from a pool containing only four - * elements.
The test expects the first four threads to - * successfully start and the last one to fail. - * - *

Conditions

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

Test Steps

- * - [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 */ diff --git a/test/rt/source/test/test_sequence_012.c b/test/rt/source/test/test_sequence_012.c index 1ce965916..834239758 100644 --- a/test/rt/source/test/test_sequence_012.c +++ b/test/rt/source/test/test_sequence_012.c @@ -22,1010 +22,263 @@ * @file test_sequence_012.c * @brief Test Sequence 012 code. * - * @page test_sequence_012 [12] Benchmarks + * @page test_sequence_012 [12] Dynamic threads * * File: @ref test_sequence_012.c * *

Description

- * This module implements a series of system benchmarks. The benchmarks - * are useful as a stress test and as a reference when comparing - * ChibiOS/RT with similar systems.
Objective of the test sequence - * is to provide a performance index for the most critical system - * subsystems. The performance numbers allow to discover performance - * regressions between successive ChibiOS/RT releases. + * This module implements the test sequence for the dynamic thread + * creation APIs. + * + *

Conditions

+ * This sequence is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_DYNAMIC + * . * *

Test Cases

* - @subpage test_012_001 * - @subpage test_012_002 - * - @subpage test_012_003 - * - @subpage test_012_004 - * - @subpage test_012_005 - * - @subpage test_012_006 - * - @subpage test_012_007 - * - @subpage test_012_008 - * - @subpage test_012_009 - * - @subpage test_012_010 - * - @subpage test_012_011 - * - @subpage test_012_012 * . */ +#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__) + /**************************************************************************** * Shared code. ****************************************************************************/ -#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__) -static semaphore_t sem1; +#if CH_CFG_USE_HEAP +static memory_heap_t heap1; #endif -#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__) -static mutex_t mtx1; +#if CH_CFG_USE_MEMPOOLS +static memory_pool_t mp1; #endif -static void tmo(void *param) {(void)param;} +static THD_FUNCTION(dyn_thread1, p) { -#if CH_CFG_USE_MESSAGES -static THD_FUNCTION(bmk_thread1, p) { - thread_t *tp; - msg_t msg; - - (void)p; - do { - tp = chMsgWait(); - msg = chMsgGet(tp); - chMsgRelease(tp, msg); - } while (msg); -} - -NOINLINE static unsigned int msg_loop_test(thread_t *tp) { - systime_t start, end; - - uint32_t n = 0; - start = test_wait_tick(); - end = start + MS2ST(1000); - do { - (void)chMsgSend(tp, 1); - n++; -#if defined(SIMULATOR) - _sim_check_for_interrupts(); -#endif - } while (chVTIsSystemTimeWithinX(start, end)); - (void)chMsgSend(tp, 0); - return n; -} -#endif - -static THD_FUNCTION(bmk_thread3, p) { - - chThdExit((msg_t)p); -} - -static THD_FUNCTION(bmk_thread4, p) { - msg_t msg; - thread_t *self = chThdGetSelfX(); - - (void)p; - chSysLock(); - do { - chSchGoSleepS(CH_STATE_SUSPENDED); - msg = self->u.rdymsg; - } while (msg == MSG_OK); - chSysUnlock(); -} - -#if CH_CFG_USE_SEMAPHORES -static THD_FUNCTION(bmk_thread7, p) { - - (void)p; - while (!chThdShouldTerminateX()) - chSemWait(&sem1); -} -#endif - -static THD_FUNCTION(bmk_thread8, p) { - - do { - chThdYield(); - chThdYield(); - chThdYield(); - chThdYield(); - (*(uint32_t *)p) += 4; -#if defined(SIMULATOR) - _sim_check_for_interrupts(); -#endif - } while(!chThdShouldTerminateX()); + test_emit_token(*(char *)p); } /**************************************************************************** * Test cases. ****************************************************************************/ -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) +#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__) /** - * @page test_012_001 [12.1] Messages performance #1 + * @page test_012_001 [12.1] Threads creation from Memory Heap * *

Description

- * A message server thread is created with a lower priority than the - * client thread, the messages throughput per second is measured and - * the result printed on the output log. + * Two threads are started by allocating the memory from the Memory + * Heap then a third thread is started with a huge stack + * requirement.
The test expects the first two threads to + * successfully start and the third one to fail. * *

Conditions

* This test is only executed if the following preprocessor condition * evaluates to true: - * - CH_CFG_USE_MESSAGES + * - CH_CFG_USE_HEAP * . * *

Test Steps

- * - [12.1.1] The messenger thread is started at a lower priority than - * the current thread. - * - [12.1.2] The number of messages exchanged is counted in a one - * second time window. - * - [12.1.3] Score is printed. + * - [12.1.1] Getting base priority for threads. + * - [12.1.2] Getting heap info before the test. + * - [12.1.3] Creating thread 1, it is expected to succeed. + * - [12.1.4] Creating thread 2, it is expected to succeed. + * - [12.1.5] Creating thread 3, it is expected to fail. + * - [12.1.6] Letting threads execute then checking the start order and + * freeing memory. + * - [12.1.7] Getting heap info again for verification. * . */ -static void test_012_001_execute(void) { - uint32_t n; +static void test_012_001_setup(void) { + chHeapObjectInit(&heap1, test_buffer, sizeof test_buffer); +} - /* [12.1.1] The messenger thread is started at a lower priority than - the current thread.*/ +static void test_012_001_execute(void) { + size_t n1, total1, largest1; + size_t n2, total2, largest2; + tprio_t prio; + + /* [12.1.1] Getting base priority for threads.*/ test_set_step(1); { - threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, bmk_thread1, NULL); + prio = chThdGetPriorityX(); } - /* [12.1.2] The number of messages exchanged is counted in a one - second time window.*/ + /* [12.1.2] Getting heap info before the test.*/ test_set_step(2); { - n = msg_loop_test(threads[0]); - test_wait_threads(); + n1 = chHeapStatus(&heap1, &total1, &largest1); + test_assert(n1 == 1, "heap fragmented"); } - /* [12.1.3] Score is printed.*/ + /* [12.1.3] Creating thread 1, it is expected to succeed.*/ test_set_step(3); { - test_print("--- Score : "); - test_printn(n); - test_print(" msgs/S, "); - test_printn(n << 1); - test_println(" ctxswc/S"); + 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"); + } + + /* [12.1.4] Creating thread 2, it is expected to succeed.*/ + 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"); + } + + /* [12.1.5] Creating thread 3, it is expected to fail.*/ + 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"); + } + + /* [12.1.6] Letting threads execute then checking the start order and + freeing memory.*/ + test_set_step(6); + { + test_wait_threads(); + test_assert_sequence("AB", "invalid sequence"); + } + + /* [12.1.7] Getting heap info again for verification.*/ + 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"); } } static const testcase_t test_012_001 = { - "Messages performance #1", - NULL, + "Threads creation from Memory Heap", + test_012_001_setup, NULL, test_012_001_execute }; -#endif /* CH_CFG_USE_MESSAGES */ +#endif /* CH_CFG_USE_HEAP */ -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) +#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__) /** - * @page test_012_002 [12.2] Messages performance #2 + * @page test_012_002 [12.2] Threads creation from Memory Pool * *

Description

- * A message server thread is created with an higher priority than the - * client thread, the messages throughput per second is measured and - * the result printed on the output log. + * Five thread creation are attempted from a pool containing only four + * elements.
The test expects the first four threads to + * successfully start and the last one to fail. * *

Conditions

* This test is only executed if the following preprocessor condition * evaluates to true: - * - CH_CFG_USE_MESSAGES + * - CH_CFG_USE_MEMPOOLS * . * *

Test Steps

- * - [12.2.1] The messenger thread is started at an higher priority - * than the current thread. - * - [12.2.2] The number of messages exchanged is counted in a one - * second time window. - * - [12.2.3] Score is printed. + * - [12.2.1] Adding four working areas to the pool. + * - [12.2.2] Getting base priority for threads. + * - [12.2.3] Creating the five threads. + * - [12.2.4] Testing that only the fifth thread creation failed. + * - [12.2.5] Letting them run, free the memory then checking the + * execution sequence. + * - [12.2.6] Testing that the pool contains four elements again. * . */ -static void test_012_002_execute(void) { - uint32_t n; +static void test_012_002_setup(void) { + chPoolObjectInit(&mp1, THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), NULL); +} - /* [12.2.1] The messenger thread is started at an higher priority - than the current thread.*/ +static void test_012_002_execute(void) { + unsigned i; + tprio_t prio; + + /* [12.2.1] Adding four working areas to the pool.*/ test_set_step(1); { - threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, bmk_thread1, NULL); + for (i = 0; i < 4; i++) + chPoolFree(&mp1, wa[i]); } - /* [12.2.2] The number of messages exchanged is counted in a one - second time window.*/ + /* [12.2.2] Getting base priority for threads.*/ test_set_step(2); { - n = msg_loop_test(threads[0]); - test_wait_threads(); + prio = chThdGetPriorityX(); } - /* [12.2.3] Score is printed.*/ + /* [12.2.3] Creating the five threads.*/ test_set_step(3); { - test_print("--- Score : "); - test_printn(n); - test_print(" msgs/S, "); - test_printn(n << 1); - test_println(" ctxswc/S"); + 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"); + } + + /* [12.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"); + } + + /* [12.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"); + } + + /* [12.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"); } } static const testcase_t test_012_002 = { - "Messages performance #2", - NULL, + "Threads creation from Memory Pool", + test_012_002_setup, NULL, test_012_002_execute }; -#endif /* CH_CFG_USE_MESSAGES */ - -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) -/** - * @page test_012_003 [12.3] Messages performance #3 - * - *

Description

- * A message server thread is created with an higher priority than the - * client thread, four lower priority threads crowd the ready list, the - * messages throughput per second is measured while the ready list and - * the result printed on the output log. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_MESSAGES - * . - * - *

Test Steps

- * - [12.3.1] The messenger thread is started at an higher priority - * than the current thread. - * - [12.3.2] Four threads are started at a lower priority than the - * current thread. - * - [12.3.3] The number of messages exchanged is counted in a one - * second time window. - * - [12.3.4] Score is printed. - * . - */ - -static void test_012_003_execute(void) { - uint32_t n; - - /* [12.3.1] The messenger thread is started at an higher priority - than the current thread.*/ - test_set_step(1); - { - threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, bmk_thread1, NULL); - } - - /* [12.3.2] Four threads are started at a lower priority than the - current thread.*/ - test_set_step(2); - { - threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-2, bmk_thread3, NULL); - threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, bmk_thread3, NULL); - threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-4, bmk_thread3, NULL); - threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-5, bmk_thread3, NULL); - } - - /* [12.3.3] The number of messages exchanged is counted in a one - second time window.*/ - test_set_step(3); - { - n = msg_loop_test(threads[0]); - test_wait_threads(); - } - - /* [12.3.4] Score is printed.*/ - test_set_step(4); - { - test_print("--- Score : "); - test_printn(n); - test_print(" msgs/S, "); - test_printn(n << 1); - test_println(" ctxswc/S"); - } -} - -static const testcase_t test_012_003 = { - "Messages performance #3", - NULL, - NULL, - test_012_003_execute -}; -#endif /* CH_CFG_USE_MESSAGES */ - -/** - * @page test_012_004 [12.4] Context Switch performance - * - *

Description

- * A thread is created that just performs a @p chSchGoSleepS() into a - * loop, the thread is awakened as fast is possible by the tester - * thread.
The Context Switch performance is calculated by - * measuring the number of iterations after a second of continuous - * operations. - * - *

Test Steps

- * - [12.4.1] Starting the target thread at an higher priority level. - * - [12.4.2] Waking up the thread as fast as possible in a one second - * time window. - * - [12.4.3] Stopping the target thread. - * - [12.4.4] Score is printed. - * . - */ - -static void test_012_004_execute(void) { - thread_t *tp; - uint32_t n; - - /* [12.4.1] Starting the target thread at an higher priority level.*/ - test_set_step(1); - { - tp = threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, - bmk_thread4, NULL); - } - - /* [12.4.2] Waking up the thread as fast as possible in a one second - time window.*/ - test_set_step(2); - { - systime_t start, end; - - n = 0; - start = test_wait_tick(); - end = start + MS2ST(1000); - do { - chSysLock(); - chSchWakeupS(tp, MSG_OK); - chSchWakeupS(tp, MSG_OK); - chSchWakeupS(tp, MSG_OK); - chSchWakeupS(tp, MSG_OK); - chSysUnlock(); - n += 4; -#if defined(SIMULATOR) - _sim_check_for_interrupts(); -#endif - } while (chVTIsSystemTimeWithinX(start, end)); - } - - /* [12.4.3] Stopping the target thread.*/ - test_set_step(3); - { - chSysLock(); - chSchWakeupS(tp, MSG_TIMEOUT); - chSysUnlock(); - test_wait_threads(); - } - - /* [12.4.4] Score is printed.*/ - test_set_step(4); - { - test_print("--- Score : "); - test_printn(n * 2); - test_println(" ctxswc/S"); - } -} - -static const testcase_t test_012_004 = { - "Context Switch performance", - NULL, - NULL, - test_012_004_execute -}; - -/** - * @page test_012_005 [12.5] Threads performance, full cycle - * - *

Description

- * Threads are continuously created and terminated into a loop. A full - * chThdCreateStatic() / @p chThdExit() / @p chThdWait() cycle is - * performed in each iteration.
The performance is calculated by - * measuring the number of iterations after a second of continuous - * operations. - * - *

Test Steps

- * - [12.5.1] A thread is created at a lower priority level and its - * termination detected using @p chThdWait(). The operation is - * repeated continuously in a one-second time window. - * - [12.5.2] Score is printed. - * . - */ - -static void test_012_005_execute(void) { - uint32_t n; - tprio_t prio = chThdGetPriorityX() - 1; - systime_t start, end; - - /* [12.5.1] A thread is created at a lower priority level and its - termination detected using @p chThdWait(). The operation is - repeated continuously in a one-second time window.*/ - test_set_step(1); - { - n = 0; - start = test_wait_tick(); - end = start + MS2ST(1000); - do { - chThdWait(chThdCreateStatic(wa[0], WA_SIZE, prio, bmk_thread3, NULL)); - n++; -#if defined(SIMULATOR) - _sim_check_for_interrupts(); -#endif - } while (chVTIsSystemTimeWithinX(start, end)); - } - - /* [12.5.2] Score is printed.*/ - test_set_step(2); - { - test_print("--- Score : "); - test_printn(n); - test_println(" threads/S"); - } -} - -static const testcase_t test_012_005 = { - "Threads performance, full cycle", - NULL, - NULL, - test_012_005_execute -}; - -/** - * @page test_012_006 [12.6] Threads performance, create/exit only - * - *

Description

- * Threads are continuously created and terminated into a loop. A - * partial @p chThdCreateStatic() / @p chThdExit() cycle is performed - * in each iteration, the @p chThdWait() is not necessary because the - * thread is created at an higher priority so there is no need to wait - * for it to terminate.
The performance is calculated by measuring - * the number of iterations after a second of continuous operations. - * - *

Test Steps

- * - [12.6.1] A thread is created at an higher priority level and let - * terminate immediately. The operation is repeated continuously in a - * one-second time window. - * - [12.6.2] Score is printed. - * . - */ - -static void test_012_006_execute(void) { - uint32_t n; - tprio_t prio = chThdGetPriorityX() + 1; - systime_t start, end; - - /* [12.6.1] A thread is created at an higher priority level and let - terminate immediately. The operation is repeated continuously in a - one-second time window.*/ - test_set_step(1); - { - n = 0; - start = test_wait_tick(); - end = start + MS2ST(1000); - do { -#if CH_CFG_USE_REGISTRY - chThdRelease(chThdCreateStatic(wa[0], WA_SIZE, prio, bmk_thread3, NULL)); -#else - chThdCreateStatic(wa[0], WA_SIZE, prio, bmk_thread3, NULL); -#endif - n++; -#if defined(SIMULATOR) - _sim_check_for_interrupts(); -#endif - } while (chVTIsSystemTimeWithinX(start, end)); - } - - /* [12.6.2] Score is printed.*/ - test_set_step(2); - { - test_print("--- Score : "); - test_printn(n); - test_println(" threads/S"); - } -} - -static const testcase_t test_012_006 = { - "Threads performance, create/exit only", - NULL, - NULL, - test_012_006_execute -}; - -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) -/** - * @page test_012_007 [12.7] Mass reschedule performance - * - *

Description

- * Five threads are created and atomically rescheduled by resetting the - * semaphore where they are waiting on. The operation is performed into - * a continuous loop.
The performance is calculated by measuring - * the number of iterations after a second of continuous operations. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_SEMAPHORES - * . - * - *

Test Steps

- * - [12.7.1] Five threads are created at higher priority that - * immediately enqueue on a semaphore. - * - [12.7.2] The semaphore is reset waking up the five threads. The - * operation is repeated continuously in a one-second time window. - * - [12.7.3] The five threads are terminated. - * - [12.7.4] The score is printed. - * . - */ - -static void test_012_007_setup(void) { - chSemObjectInit(&sem1, 0); -} - -static void test_012_007_execute(void) { - uint32_t n; - - /* [12.7.1] Five threads are created at higher priority that - immediately enqueue on a semaphore.*/ - test_set_step(1); - { - threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, bmk_thread7, NULL); - threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+4, bmk_thread7, NULL); - threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, bmk_thread7, NULL); - threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+2, bmk_thread7, NULL); - threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+1, bmk_thread7, NULL); - } - - /* [12.7.2] The semaphore is reset waking up the five threads. The - operation is repeated continuously in a one-second time window.*/ - test_set_step(2); - { - systime_t start, end; - - n = 0; - start = test_wait_tick(); - end = start + MS2ST(1000); - do { - chSemReset(&sem1, 0); - n++; -#if defined(SIMULATOR) - _sim_check_for_interrupts(); -#endif - } while (chVTIsSystemTimeWithinX(start, end)); - } - - /* [12.7.3] The five threads are terminated.*/ - test_set_step(3); - { - test_terminate_threads(); - chSemReset(&sem1, 0); - test_wait_threads(); - } - - /* [12.7.4] The score is printed.*/ - test_set_step(4); - { - test_print("--- Score : "); - test_printn(n); - test_print(" reschedules/S, "); - test_printn(n * 6); - test_println(" ctxswc/S"); - } -} - -static const testcase_t test_012_007 = { - "Mass reschedule performance", - test_012_007_setup, - NULL, - test_012_007_execute -}; -#endif /* CH_CFG_USE_SEMAPHORES */ - -/** - * @page test_012_008 [12.8] Round-Robin voluntary reschedule - * - *

Description

- * Five threads are created at equal priority, each thread just - * increases a variable and yields.
The performance is calculated - * by measuring the number of iterations after a second of continuous - * operations. - * - *

Test Steps

- * - [12.8.1] The five threads are created at lower priority. The - * threds have equal priority and start calling @p chThdYield() - * continuously. - * - [12.8.2] Waiting one second then terminating the 5 threads. - * - [12.8.3] The score is printed. - * . - */ - -static void test_012_008_execute(void) { - uint32_t n; - - /* [12.8.1] The five threads are created at lower priority. The - threds have equal priority and start calling @p chThdYield() - continuously.*/ - test_set_step(1); - { - n = 0; - test_wait_tick();threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n); - - threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n); - threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n); - threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n); - threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n); - } - - /* [12.8.2] Waiting one second then terminating the 5 threads.*/ - test_set_step(2); - { - chThdSleepSeconds(1); - test_terminate_threads(); - test_wait_threads(); - } - - /* [12.8.3] The score is printed.*/ - test_set_step(3); - { - test_print("--- Score : "); - test_printn(n); - test_println(" ctxswc/S"); - } -} - -static const testcase_t test_012_008 = { - "Round-Robin voluntary reschedule", - NULL, - NULL, - test_012_008_execute -}; - -/** - * @page test_012_009 [12.9] Virtual Timers set/reset performance - * - *

Description

- * A virtual timer is set and immediately reset into a continuous - * loop.
The performance is calculated by measuring the number of - * iterations after a second of continuous operations. - * - *

Test Steps

- * - [12.9.1] Two timers are set then reset without waiting for their - * counter to elapse. The operation is repeated continuously in a - * one-second time window. - * - [12.9.2] The score is printed. - * . - */ - -static void test_012_009_execute(void) { - static virtual_timer_t vt1, vt2; - uint32_t n; - - /* [12.9.1] Two timers are set then reset without waiting for their - counter to elapse. The operation is repeated continuously in a - one-second time window.*/ - test_set_step(1); - { - systime_t start, end; - - n = 0; - start = test_wait_tick(); - end = start + MS2ST(1000); - do { - chSysLock(); - chVTDoSetI(&vt1, 1, tmo, NULL); - chVTDoSetI(&vt2, 10000, tmo, NULL); - chVTDoResetI(&vt1); - chVTDoResetI(&vt2); - chSysUnlock(); - n++; -#if defined(SIMULATOR) - _sim_check_for_interrupts(); -#endif - } while (chVTIsSystemTimeWithinX(start, end)); - } - - /* [12.9.2] The score is printed.*/ - test_set_step(2); - { - test_print("--- Score : "); - test_printn(n * 2); - test_println(" timers/S"); - } -} - -static const testcase_t test_012_009 = { - "Virtual Timers set/reset performance", - NULL, - NULL, - test_012_009_execute -}; - -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) -/** - * @page test_012_010 [12.10] Semaphores wait/signal performance - * - *

Description

- * A counting semaphore is taken/released into a continuous loop, no - * Context Switch happens because the counter is always non - * negative.
The performance is calculated by measuring the number - * of iterations after a second of continuous operations. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_SEMAPHORES - * . - * - *

Test Steps

- * - [12.10.1] A semaphore is teken and released. The operation is - * repeated continuously in a one-second time window. - * - [12.10.2] The score is printed. - * . - */ - -static void test_012_010_setup(void) { - chSemObjectInit(&sem1, 1); -} - -static void test_012_010_execute(void) { - uint32_t n; - - /* [12.10.1] A semaphore is teken and released. The operation is - repeated continuously in a one-second time window.*/ - test_set_step(1); - { - systime_t start, end; - - n = 0; - start = test_wait_tick(); - end = start + MS2ST(1000); - do { - chSemWait(&sem1); - chSemSignal(&sem1); - chSemWait(&sem1); - chSemSignal(&sem1); - chSemWait(&sem1); - chSemSignal(&sem1); - chSemWait(&sem1); - chSemSignal(&sem1); - n++; -#if defined(SIMULATOR) - _sim_check_for_interrupts(); -#endif - } while (chVTIsSystemTimeWithinX(start, end)); - } - - /* [12.10.2] The score is printed.*/ - test_set_step(2); - { - test_print("--- Score : "); - test_printn(n * 4); - test_println(" wait+signal/S"); - } -} - -static const testcase_t test_012_010 = { - "Semaphores wait/signal performance", - test_012_010_setup, - NULL, - test_012_010_execute -}; -#endif /* CH_CFG_USE_SEMAPHORES */ - -#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__) -/** - * @page test_012_011 [12.11] Mutexes lock/unlock performance - * - *

Description

- * A mutex is locked/unlocked into a continuous loop, no Context Switch - * happens because there are no other threads asking for the mutex.
- * The performance is calculated by measuring the number of iterations - * after a second of continuous operations. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_MUTEXES - * . - * - *

Test Steps

- * - [12.11.1] A mutex is locked and unlocked. The operation is - * repeated continuously in a one-second time window. - * - [12.11.2] The score is printed. - * . - */ - -static void test_012_011_setup(void) { - chMtxObjectInit(&mtx1); -} - -static void test_012_011_execute(void) { - uint32_t n; - - /* [12.11.1] A mutex is locked and unlocked. The operation is - repeated continuously in a one-second time window.*/ - test_set_step(1); - { - systime_t start, end; - - n = 0; - start = test_wait_tick(); - end = start + MS2ST(1000); - do { - chMtxLock(&mtx1); - chMtxUnlock(&mtx1); - chMtxLock(&mtx1); - chMtxUnlock(&mtx1); - chMtxLock(&mtx1); - chMtxUnlock(&mtx1); - chMtxLock(&mtx1); - chMtxUnlock(&mtx1); - n++; -#if defined(SIMULATOR) - _sim_check_for_interrupts(); -#endif - } while (chVTIsSystemTimeWithinX(start, end)); - } - - /* [12.11.2] The score is printed.*/ - test_set_step(2); - { - test_print("--- Score : "); - test_printn(n * 4); - test_println(" lock+unlock/S"); - } -} - -static const testcase_t test_012_011 = { - "Mutexes lock/unlock performance", - test_012_011_setup, - NULL, - test_012_011_execute -}; -#endif /* CH_CFG_USE_MUTEXES */ - -/** - * @page test_012_012 [12.12] RAM Footprint - * - *

Description

- * The memory size of the various kernel objects is printed. - * - *

Test Steps

- * - [12.12.1] The size of the system area is printed. - * - [12.12.2] The size of a thread structure is printed. - * - [12.12.3] The size of a virtual timer structure is printed. - * - [12.12.4] The size of a semaphore structure is printed. - * - [12.12.5] The size of a mutex is printed. - * - [12.12.6] The size of a condition variable is printed. - * - [12.12.7] The size of an event source is printed. - * - [12.12.8] The size of an event listener is printed. - * - [12.12.9] The size of a mailbox is printed. - * . - */ - -static void test_012_012_execute(void) { - - /* [12.12.1] The size of the system area is printed.*/ - test_set_step(1); - { - test_print("--- System: "); - test_printn(sizeof(ch_system_t)); - test_println(" bytes"); - } - - /* [12.12.2] The size of a thread structure is printed.*/ - test_set_step(2); - { - test_print("--- Thread: "); - test_printn(sizeof(thread_t)); - test_println(" bytes"); - } - - /* [12.12.3] The size of a virtual timer structure is printed.*/ - test_set_step(3); - { - test_print("--- Timer : "); - test_printn(sizeof(virtual_timer_t)); - test_println(" bytes"); - } - - /* [12.12.4] The size of a semaphore structure is printed.*/ - test_set_step(4); - { -#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__) - test_print("--- Semaph: "); - test_printn(sizeof(semaphore_t)); - test_println(" bytes"); -#endif - } - - /* [12.12.5] The size of a mutex is printed.*/ - test_set_step(5); - { -#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__) - test_print("--- Mutex : "); - test_printn(sizeof(mutex_t)); - test_println(" bytes"); -#endif - } - - /* [12.12.6] The size of a condition variable is printed.*/ - test_set_step(6); - { -#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__) - test_print("--- CondV.: "); - test_printn(sizeof(condition_variable_t)); - test_println(" bytes"); -#endif - } - - /* [12.12.7] The size of an event source is printed.*/ - test_set_step(7); - { -#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__) - test_print("--- EventS: "); - test_printn(sizeof(event_source_t)); - test_println(" bytes"); -#endif - } - - /* [12.12.8] The size of an event listener is printed.*/ - test_set_step(8); - { -#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__) - test_print("--- EventL: "); - test_printn(sizeof(event_listener_t)); - test_println(" bytes"); -#endif - } - - /* [12.12.9] The size of a mailbox is printed.*/ - test_set_step(9); - { -#if CH_CFG_USE_MAILBOXES || defined(__DOXYGEN__) - test_print("--- MailB.: "); - test_printn(sizeof(mailbox_t)); - test_println(" bytes"); -#endif - } -} - -static const testcase_t test_012_012 = { - "RAM Footprint", - NULL, - NULL, - test_012_012_execute -}; +#endif /* CH_CFG_USE_MEMPOOLS */ /**************************************************************************** * Exported data. ****************************************************************************/ /** - * @brief Benchmarks. + * @brief Dynamic threads. */ const testcase_t * const test_sequence_012[] = { -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) +#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__) &test_012_001, #endif -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) +#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__) &test_012_002, #endif -#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) - &test_012_003, -#endif - &test_012_004, - &test_012_005, - &test_012_006, -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) - &test_012_007, -#endif - &test_012_008, - &test_012_009, -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) - &test_012_010, -#endif -#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__) - &test_012_011, -#endif - &test_012_012, NULL }; + +#endif /* CH_CFG_USE_DYNAMIC */ diff --git a/test/rt/source/test/test_sequence_013.c b/test/rt/source/test/test_sequence_013.c new file mode 100644 index 000000000..126f94ad3 --- /dev/null +++ b/test/rt/source/test/test_sequence_013.c @@ -0,0 +1,1031 @@ +/* + 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_013.c + * @brief Test Sequence 013 code. + * + * @page test_sequence_013 [13] Benchmarks + * + * File: @ref test_sequence_013.c + * + *

Description

+ * This module implements a series of system benchmarks. The benchmarks + * are useful as a stress test and as a reference when comparing + * ChibiOS/RT with similar systems.
Objective of the test sequence + * is to provide a performance index for the most critical system + * subsystems. The performance numbers allow to discover performance + * regressions between successive ChibiOS/RT releases. + * + *

Test Cases

+ * - @subpage test_013_001 + * - @subpage test_013_002 + * - @subpage test_013_003 + * - @subpage test_013_004 + * - @subpage test_013_005 + * - @subpage test_013_006 + * - @subpage test_013_007 + * - @subpage test_013_008 + * - @subpage test_013_009 + * - @subpage test_013_010 + * - @subpage test_013_011 + * - @subpage test_013_012 + * . + */ + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__) +static semaphore_t sem1; +#endif +#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__) +static mutex_t mtx1; +#endif + +static void tmo(void *param) {(void)param;} + +#if CH_CFG_USE_MESSAGES +static THD_FUNCTION(bmk_thread1, p) { + thread_t *tp; + msg_t msg; + + (void)p; + do { + tp = chMsgWait(); + msg = chMsgGet(tp); + chMsgRelease(tp, msg); + } while (msg); +} + +NOINLINE static unsigned int msg_loop_test(thread_t *tp) { + systime_t start, end; + + uint32_t n = 0; + start = test_wait_tick(); + end = start + MS2ST(1000); + do { + (void)chMsgSend(tp, 1); + n++; +#if defined(SIMULATOR) + _sim_check_for_interrupts(); +#endif + } while (chVTIsSystemTimeWithinX(start, end)); + (void)chMsgSend(tp, 0); + return n; +} +#endif + +static THD_FUNCTION(bmk_thread3, p) { + + chThdExit((msg_t)p); +} + +static THD_FUNCTION(bmk_thread4, p) { + msg_t msg; + thread_t *self = chThdGetSelfX(); + + (void)p; + chSysLock(); + do { + chSchGoSleepS(CH_STATE_SUSPENDED); + msg = self->u.rdymsg; + } while (msg == MSG_OK); + chSysUnlock(); +} + +#if CH_CFG_USE_SEMAPHORES +static THD_FUNCTION(bmk_thread7, p) { + + (void)p; + while (!chThdShouldTerminateX()) + chSemWait(&sem1); +} +#endif + +static THD_FUNCTION(bmk_thread8, p) { + + do { + chThdYield(); + chThdYield(); + chThdYield(); + chThdYield(); + (*(uint32_t *)p) += 4; +#if defined(SIMULATOR) + _sim_check_for_interrupts(); +#endif + } while(!chThdShouldTerminateX()); +} + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) +/** + * @page test_013_001 [13.1] Messages performance #1 + * + *

Description

+ * A message server thread is created with a lower priority than the + * client thread, the messages throughput per second is measured and + * the result printed on the output log. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_MESSAGES + * . + * + *

Test Steps

+ * - [13.1.1] The messenger thread is started at a lower priority than + * the current thread. + * - [13.1.2] The number of messages exchanged is counted in a one + * second time window. + * - [13.1.3] Score is printed. + * . + */ + +static void test_013_001_execute(void) { + uint32_t n; + + /* [13.1.1] The messenger thread is started at a lower priority than + the current thread.*/ + test_set_step(1); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, bmk_thread1, NULL); + } + + /* [13.1.2] The number of messages exchanged is counted in a one + second time window.*/ + test_set_step(2); + { + n = msg_loop_test(threads[0]); + test_wait_threads(); + } + + /* [13.1.3] Score is printed.*/ + test_set_step(3); + { + test_print("--- Score : "); + test_printn(n); + test_print(" msgs/S, "); + test_printn(n << 1); + test_println(" ctxswc/S"); + } +} + +static const testcase_t test_013_001 = { + "Messages performance #1", + NULL, + NULL, + test_013_001_execute +}; +#endif /* CH_CFG_USE_MESSAGES */ + +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) +/** + * @page test_013_002 [13.2] Messages performance #2 + * + *

Description

+ * A message server thread is created with an higher priority than the + * client thread, the messages throughput per second is measured and + * the result printed on the output log. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_MESSAGES + * . + * + *

Test Steps

+ * - [13.2.1] The messenger thread is started at an higher priority + * than the current thread. + * - [13.2.2] The number of messages exchanged is counted in a one + * second time window. + * - [13.2.3] Score is printed. + * . + */ + +static void test_013_002_execute(void) { + uint32_t n; + + /* [13.2.1] The messenger thread is started at an higher priority + than the current thread.*/ + test_set_step(1); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, bmk_thread1, NULL); + } + + /* [13.2.2] The number of messages exchanged is counted in a one + second time window.*/ + test_set_step(2); + { + n = msg_loop_test(threads[0]); + test_wait_threads(); + } + + /* [13.2.3] Score is printed.*/ + test_set_step(3); + { + test_print("--- Score : "); + test_printn(n); + test_print(" msgs/S, "); + test_printn(n << 1); + test_println(" ctxswc/S"); + } +} + +static const testcase_t test_013_002 = { + "Messages performance #2", + NULL, + NULL, + test_013_002_execute +}; +#endif /* CH_CFG_USE_MESSAGES */ + +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) +/** + * @page test_013_003 [13.3] Messages performance #3 + * + *

Description

+ * A message server thread is created with an higher priority than the + * client thread, four lower priority threads crowd the ready list, the + * messages throughput per second is measured while the ready list and + * the result printed on the output log. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_MESSAGES + * . + * + *

Test Steps

+ * - [13.3.1] The messenger thread is started at an higher priority + * than the current thread. + * - [13.3.2] Four threads are started at a lower priority than the + * current thread. + * - [13.3.3] The number of messages exchanged is counted in a one + * second time window. + * - [13.3.4] Score is printed. + * . + */ + +static void test_013_003_execute(void) { + uint32_t n; + + /* [13.3.1] The messenger thread is started at an higher priority + than the current thread.*/ + test_set_step(1); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, bmk_thread1, NULL); + } + + /* [13.3.2] Four threads are started at a lower priority than the + current thread.*/ + test_set_step(2); + { + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-2, bmk_thread3, NULL); + threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, bmk_thread3, NULL); + threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-4, bmk_thread3, NULL); + threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-5, bmk_thread3, NULL); + } + + /* [13.3.3] The number of messages exchanged is counted in a one + second time window.*/ + test_set_step(3); + { + n = msg_loop_test(threads[0]); + test_wait_threads(); + } + + /* [13.3.4] Score is printed.*/ + test_set_step(4); + { + test_print("--- Score : "); + test_printn(n); + test_print(" msgs/S, "); + test_printn(n << 1); + test_println(" ctxswc/S"); + } +} + +static const testcase_t test_013_003 = { + "Messages performance #3", + NULL, + NULL, + test_013_003_execute +}; +#endif /* CH_CFG_USE_MESSAGES */ + +/** + * @page test_013_004 [13.4] Context Switch performance + * + *

Description

+ * A thread is created that just performs a @p chSchGoSleepS() into a + * loop, the thread is awakened as fast is possible by the tester + * thread.
The Context Switch performance is calculated by + * measuring the number of iterations after a second of continuous + * operations. + * + *

Test Steps

+ * - [13.4.1] Starting the target thread at an higher priority level. + * - [13.4.2] Waking up the thread as fast as possible in a one second + * time window. + * - [13.4.3] Stopping the target thread. + * - [13.4.4] Score is printed. + * . + */ + +static void test_013_004_execute(void) { + thread_t *tp; + uint32_t n; + + /* [13.4.1] Starting the target thread at an higher priority level.*/ + test_set_step(1); + { + tp = threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, + bmk_thread4, NULL); + } + + /* [13.4.2] Waking up the thread as fast as possible in a one second + time window.*/ + test_set_step(2); + { + systime_t start, end; + + n = 0; + start = test_wait_tick(); + end = start + MS2ST(1000); + do { + chSysLock(); + chSchWakeupS(tp, MSG_OK); + chSchWakeupS(tp, MSG_OK); + chSchWakeupS(tp, MSG_OK); + chSchWakeupS(tp, MSG_OK); + chSysUnlock(); + n += 4; +#if defined(SIMULATOR) + _sim_check_for_interrupts(); +#endif + } while (chVTIsSystemTimeWithinX(start, end)); + } + + /* [13.4.3] Stopping the target thread.*/ + test_set_step(3); + { + chSysLock(); + chSchWakeupS(tp, MSG_TIMEOUT); + chSysUnlock(); + test_wait_threads(); + } + + /* [13.4.4] Score is printed.*/ + test_set_step(4); + { + test_print("--- Score : "); + test_printn(n * 2); + test_println(" ctxswc/S"); + } +} + +static const testcase_t test_013_004 = { + "Context Switch performance", + NULL, + NULL, + test_013_004_execute +}; + +/** + * @page test_013_005 [13.5] Threads performance, full cycle + * + *

Description

+ * Threads are continuously created and terminated into a loop. A full + * chThdCreateStatic() / @p chThdExit() / @p chThdWait() cycle is + * performed in each iteration.
The performance is calculated by + * measuring the number of iterations after a second of continuous + * operations. + * + *

Test Steps

+ * - [13.5.1] A thread is created at a lower priority level and its + * termination detected using @p chThdWait(). The operation is + * repeated continuously in a one-second time window. + * - [13.5.2] Score is printed. + * . + */ + +static void test_013_005_execute(void) { + uint32_t n; + tprio_t prio = chThdGetPriorityX() - 1; + systime_t start, end; + + /* [13.5.1] A thread is created at a lower priority level and its + termination detected using @p chThdWait(). The operation is + repeated continuously in a one-second time window.*/ + test_set_step(1); + { + n = 0; + start = test_wait_tick(); + end = start + MS2ST(1000); + do { + chThdWait(chThdCreateStatic(wa[0], WA_SIZE, prio, bmk_thread3, NULL)); + n++; +#if defined(SIMULATOR) + _sim_check_for_interrupts(); +#endif + } while (chVTIsSystemTimeWithinX(start, end)); + } + + /* [13.5.2] Score is printed.*/ + test_set_step(2); + { + test_print("--- Score : "); + test_printn(n); + test_println(" threads/S"); + } +} + +static const testcase_t test_013_005 = { + "Threads performance, full cycle", + NULL, + NULL, + test_013_005_execute +}; + +/** + * @page test_013_006 [13.6] Threads performance, create/exit only + * + *

Description

+ * Threads are continuously created and terminated into a loop. A + * partial @p chThdCreateStatic() / @p chThdExit() cycle is performed + * in each iteration, the @p chThdWait() is not necessary because the + * thread is created at an higher priority so there is no need to wait + * for it to terminate.
The performance is calculated by measuring + * the number of iterations after a second of continuous operations. + * + *

Test Steps

+ * - [13.6.1] A thread is created at an higher priority level and let + * terminate immediately. The operation is repeated continuously in a + * one-second time window. + * - [13.6.2] Score is printed. + * . + */ + +static void test_013_006_execute(void) { + uint32_t n; + tprio_t prio = chThdGetPriorityX() + 1; + systime_t start, end; + + /* [13.6.1] A thread is created at an higher priority level and let + terminate immediately. The operation is repeated continuously in a + one-second time window.*/ + test_set_step(1); + { + n = 0; + start = test_wait_tick(); + end = start + MS2ST(1000); + do { +#if CH_CFG_USE_REGISTRY + chThdRelease(chThdCreateStatic(wa[0], WA_SIZE, prio, bmk_thread3, NULL)); +#else + chThdCreateStatic(wa[0], WA_SIZE, prio, bmk_thread3, NULL); +#endif + n++; +#if defined(SIMULATOR) + _sim_check_for_interrupts(); +#endif + } while (chVTIsSystemTimeWithinX(start, end)); + } + + /* [13.6.2] Score is printed.*/ + test_set_step(2); + { + test_print("--- Score : "); + test_printn(n); + test_println(" threads/S"); + } +} + +static const testcase_t test_013_006 = { + "Threads performance, create/exit only", + NULL, + NULL, + test_013_006_execute +}; + +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) +/** + * @page test_013_007 [13.7] Mass reschedule performance + * + *

Description

+ * Five threads are created and atomically rescheduled by resetting the + * semaphore where they are waiting on. The operation is performed into + * a continuous loop.
The performance is calculated by measuring + * the number of iterations after a second of continuous operations. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . + * + *

Test Steps

+ * - [13.7.1] Five threads are created at higher priority that + * immediately enqueue on a semaphore. + * - [13.7.2] The semaphore is reset waking up the five threads. The + * operation is repeated continuously in a one-second time window. + * - [13.7.3] The five threads are terminated. + * - [13.7.4] The score is printed. + * . + */ + +static void test_013_007_setup(void) { + chSemObjectInit(&sem1, 0); +} + +static void test_013_007_execute(void) { + uint32_t n; + + /* [13.7.1] Five threads are created at higher priority that + immediately enqueue on a semaphore.*/ + test_set_step(1); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, bmk_thread7, NULL); + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+4, bmk_thread7, NULL); + threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, bmk_thread7, NULL); + threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+2, bmk_thread7, NULL); + threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+1, bmk_thread7, NULL); + } + + /* [13.7.2] The semaphore is reset waking up the five threads. The + operation is repeated continuously in a one-second time window.*/ + test_set_step(2); + { + systime_t start, end; + + n = 0; + start = test_wait_tick(); + end = start + MS2ST(1000); + do { + chSemReset(&sem1, 0); + n++; +#if defined(SIMULATOR) + _sim_check_for_interrupts(); +#endif + } while (chVTIsSystemTimeWithinX(start, end)); + } + + /* [13.7.3] The five threads are terminated.*/ + test_set_step(3); + { + test_terminate_threads(); + chSemReset(&sem1, 0); + test_wait_threads(); + } + + /* [13.7.4] The score is printed.*/ + test_set_step(4); + { + test_print("--- Score : "); + test_printn(n); + test_print(" reschedules/S, "); + test_printn(n * 6); + test_println(" ctxswc/S"); + } +} + +static const testcase_t test_013_007 = { + "Mass reschedule performance", + test_013_007_setup, + NULL, + test_013_007_execute +}; +#endif /* CH_CFG_USE_SEMAPHORES */ + +/** + * @page test_013_008 [13.8] Round-Robin voluntary reschedule + * + *

Description

+ * Five threads are created at equal priority, each thread just + * increases a variable and yields.
The performance is calculated + * by measuring the number of iterations after a second of continuous + * operations. + * + *

Test Steps

+ * - [13.8.1] The five threads are created at lower priority. The + * threds have equal priority and start calling @p chThdYield() + * continuously. + * - [13.8.2] Waiting one second then terminating the 5 threads. + * - [13.8.3] The score is printed. + * . + */ + +static void test_013_008_execute(void) { + uint32_t n; + + /* [13.8.1] The five threads are created at lower priority. The + threds have equal priority and start calling @p chThdYield() + continuously.*/ + test_set_step(1); + { + n = 0; + test_wait_tick();threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n); + + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n); + threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n); + threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n); + threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n); + } + + /* [13.8.2] Waiting one second then terminating the 5 threads.*/ + test_set_step(2); + { + chThdSleepSeconds(1); + test_terminate_threads(); + test_wait_threads(); + } + + /* [13.8.3] The score is printed.*/ + test_set_step(3); + { + test_print("--- Score : "); + test_printn(n); + test_println(" ctxswc/S"); + } +} + +static const testcase_t test_013_008 = { + "Round-Robin voluntary reschedule", + NULL, + NULL, + test_013_008_execute +}; + +/** + * @page test_013_009 [13.9] Virtual Timers set/reset performance + * + *

Description

+ * A virtual timer is set and immediately reset into a continuous + * loop.
The performance is calculated by measuring the number of + * iterations after a second of continuous operations. + * + *

Test Steps

+ * - [13.9.1] Two timers are set then reset without waiting for their + * counter to elapse. The operation is repeated continuously in a + * one-second time window. + * - [13.9.2] The score is printed. + * . + */ + +static void test_013_009_execute(void) { + static virtual_timer_t vt1, vt2; + uint32_t n; + + /* [13.9.1] Two timers are set then reset without waiting for their + counter to elapse. The operation is repeated continuously in a + one-second time window.*/ + test_set_step(1); + { + systime_t start, end; + + n = 0; + start = test_wait_tick(); + end = start + MS2ST(1000); + do { + chSysLock(); + chVTDoSetI(&vt1, 1, tmo, NULL); + chVTDoSetI(&vt2, 10000, tmo, NULL); + chVTDoResetI(&vt1); + chVTDoResetI(&vt2); + chSysUnlock(); + n++; +#if defined(SIMULATOR) + _sim_check_for_interrupts(); +#endif + } while (chVTIsSystemTimeWithinX(start, end)); + } + + /* [13.9.2] The score is printed.*/ + test_set_step(2); + { + test_print("--- Score : "); + test_printn(n * 2); + test_println(" timers/S"); + } +} + +static const testcase_t test_013_009 = { + "Virtual Timers set/reset performance", + NULL, + NULL, + test_013_009_execute +}; + +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) +/** + * @page test_013_010 [13.10] Semaphores wait/signal performance + * + *

Description

+ * A counting semaphore is taken/released into a continuous loop, no + * Context Switch happens because the counter is always non + * negative.
The performance is calculated by measuring the number + * of iterations after a second of continuous operations. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . + * + *

Test Steps

+ * - [13.10.1] A semaphore is teken and released. The operation is + * repeated continuously in a one-second time window. + * - [13.10.2] The score is printed. + * . + */ + +static void test_013_010_setup(void) { + chSemObjectInit(&sem1, 1); +} + +static void test_013_010_execute(void) { + uint32_t n; + + /* [13.10.1] A semaphore is teken and released. The operation is + repeated continuously in a one-second time window.*/ + test_set_step(1); + { + systime_t start, end; + + n = 0; + start = test_wait_tick(); + end = start + MS2ST(1000); + do { + chSemWait(&sem1); + chSemSignal(&sem1); + chSemWait(&sem1); + chSemSignal(&sem1); + chSemWait(&sem1); + chSemSignal(&sem1); + chSemWait(&sem1); + chSemSignal(&sem1); + n++; +#if defined(SIMULATOR) + _sim_check_for_interrupts(); +#endif + } while (chVTIsSystemTimeWithinX(start, end)); + } + + /* [13.10.2] The score is printed.*/ + test_set_step(2); + { + test_print("--- Score : "); + test_printn(n * 4); + test_println(" wait+signal/S"); + } +} + +static const testcase_t test_013_010 = { + "Semaphores wait/signal performance", + test_013_010_setup, + NULL, + test_013_010_execute +}; +#endif /* CH_CFG_USE_SEMAPHORES */ + +#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__) +/** + * @page test_013_011 [13.11] Mutexes lock/unlock performance + * + *

Description

+ * A mutex is locked/unlocked into a continuous loop, no Context Switch + * happens because there are no other threads asking for the mutex.
+ * The performance is calculated by measuring the number of iterations + * after a second of continuous operations. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_MUTEXES + * . + * + *

Test Steps

+ * - [13.11.1] A mutex is locked and unlocked. The operation is + * repeated continuously in a one-second time window. + * - [13.11.2] The score is printed. + * . + */ + +static void test_013_011_setup(void) { + chMtxObjectInit(&mtx1); +} + +static void test_013_011_execute(void) { + uint32_t n; + + /* [13.11.1] A mutex is locked and unlocked. The operation is + repeated continuously in a one-second time window.*/ + test_set_step(1); + { + systime_t start, end; + + n = 0; + start = test_wait_tick(); + end = start + MS2ST(1000); + do { + chMtxLock(&mtx1); + chMtxUnlock(&mtx1); + chMtxLock(&mtx1); + chMtxUnlock(&mtx1); + chMtxLock(&mtx1); + chMtxUnlock(&mtx1); + chMtxLock(&mtx1); + chMtxUnlock(&mtx1); + n++; +#if defined(SIMULATOR) + _sim_check_for_interrupts(); +#endif + } while (chVTIsSystemTimeWithinX(start, end)); + } + + /* [13.11.2] The score is printed.*/ + test_set_step(2); + { + test_print("--- Score : "); + test_printn(n * 4); + test_println(" lock+unlock/S"); + } +} + +static const testcase_t test_013_011 = { + "Mutexes lock/unlock performance", + test_013_011_setup, + NULL, + test_013_011_execute +}; +#endif /* CH_CFG_USE_MUTEXES */ + +/** + * @page test_013_012 [13.12] RAM Footprint + * + *

Description

+ * The memory size of the various kernel objects is printed. + * + *

Test Steps

+ * - [13.12.1] The size of the system area is printed. + * - [13.12.2] The size of a thread structure is printed. + * - [13.12.3] The size of a virtual timer structure is printed. + * - [13.12.4] The size of a semaphore structure is printed. + * - [13.12.5] The size of a mutex is printed. + * - [13.12.6] The size of a condition variable is printed. + * - [13.12.7] The size of an event source is printed. + * - [13.12.8] The size of an event listener is printed. + * - [13.12.9] The size of a mailbox is printed. + * . + */ + +static void test_013_012_execute(void) { + + /* [13.12.1] The size of the system area is printed.*/ + test_set_step(1); + { + test_print("--- System: "); + test_printn(sizeof(ch_system_t)); + test_println(" bytes"); + } + + /* [13.12.2] The size of a thread structure is printed.*/ + test_set_step(2); + { + test_print("--- Thread: "); + test_printn(sizeof(thread_t)); + test_println(" bytes"); + } + + /* [13.12.3] The size of a virtual timer structure is printed.*/ + test_set_step(3); + { + test_print("--- Timer : "); + test_printn(sizeof(virtual_timer_t)); + test_println(" bytes"); + } + + /* [13.12.4] The size of a semaphore structure is printed.*/ + test_set_step(4); + { +#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__) + test_print("--- Semaph: "); + test_printn(sizeof(semaphore_t)); + test_println(" bytes"); +#endif + } + + /* [13.12.5] The size of a mutex is printed.*/ + test_set_step(5); + { +#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__) + test_print("--- Mutex : "); + test_printn(sizeof(mutex_t)); + test_println(" bytes"); +#endif + } + + /* [13.12.6] The size of a condition variable is printed.*/ + test_set_step(6); + { +#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__) + test_print("--- CondV.: "); + test_printn(sizeof(condition_variable_t)); + test_println(" bytes"); +#endif + } + + /* [13.12.7] The size of an event source is printed.*/ + test_set_step(7); + { +#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__) + test_print("--- EventS: "); + test_printn(sizeof(event_source_t)); + test_println(" bytes"); +#endif + } + + /* [13.12.8] The size of an event listener is printed.*/ + test_set_step(8); + { +#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__) + test_print("--- EventL: "); + test_printn(sizeof(event_listener_t)); + test_println(" bytes"); +#endif + } + + /* [13.12.9] The size of a mailbox is printed.*/ + test_set_step(9); + { +#if CH_CFG_USE_MAILBOXES || defined(__DOXYGEN__) + test_print("--- MailB.: "); + test_printn(sizeof(mailbox_t)); + test_println(" bytes"); +#endif + } +} + +static const testcase_t test_013_012 = { + "RAM Footprint", + NULL, + NULL, + test_013_012_execute +}; + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Benchmarks. + */ +const testcase_t * const test_sequence_013[] = { +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) + &test_013_001, +#endif +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) + &test_013_002, +#endif +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) + &test_013_003, +#endif + &test_013_004, + &test_013_005, + &test_013_006, +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) + &test_013_007, +#endif + &test_013_008, + &test_013_009, +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) + &test_013_010, +#endif +#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__) + &test_013_011, +#endif + &test_013_012, + NULL +}; diff --git a/test/rt/source/test/test_sequence_013.h b/test/rt/source/test/test_sequence_013.h new file mode 100644 index 000000000..acf57a0b9 --- /dev/null +++ b/test/rt/source/test/test_sequence_013.h @@ -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 */ diff --git a/test/rt/test.mk b/test/rt/test.mk index f6495c2ad..e9c74676a 100644 --- a/test/rt/test.mk +++ b/test/rt/test.mk @@ -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 \