aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorGiovanni Di Sirio <gdisirio@gmail.com>2017-09-17 15:38:40 +0000
committerGiovanni Di Sirio <gdisirio@gmail.com>2017-09-17 15:38:40 +0000
commit3b3afb7d55d3822b4ae734d166022e327ee0c563 (patch)
tree9419c8346dbc6436ea569053c24c212c90deead6 /test
parentfb355909fa1e96f24087c1380daef19cc0eb0532 (diff)
downloadChibiOS-3b3afb7d55d3822b4ae734d166022e327ee0c563.tar.gz
ChibiOS-3b3afb7d55d3822b4ae734d166022e327ee0c563.tar.bz2
ChibiOS-3b3afb7d55d3822b4ae734d166022e327ee0c563.zip
Improved RT and NIL test suite.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10614 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'test')
-rw-r--r--test/nil/configuration.xml150
-rw-r--r--test/nil/source/test/test_root.c12
-rw-r--r--test/nil/source/test/test_root.h1
-rw-r--r--test/nil/source/test/test_sequence_001.c162
-rw-r--r--test/nil/source/test/test_sequence_002.c226
-rw-r--r--test/nil/source/test/test_sequence_003.c234
-rw-r--r--test/nil/source/test/test_sequence_004.c387
-rw-r--r--test/nil/source/test/test_sequence_005.c342
-rw-r--r--test/nil/source/test/test_sequence_006.c297
-rw-r--r--test/nil/source/test/test_sequence_007.c273
-rw-r--r--test/nil/source/test/test_sequence_007.h27
-rw-r--r--test/nil/test.mk3
-rw-r--r--test/rt/configuration.xml204
-rw-r--r--test/rt/source/test/test_root.c20
-rw-r--r--test/rt/source/test/test_root.h1
-rw-r--r--test/rt/source/test/test_sequence_001.c317
-rw-r--r--test/rt/source/test/test_sequence_002.c296
-rw-r--r--test/rt/source/test/test_sequence_003.c306
-rw-r--r--test/rt/source/test/test_sequence_004.c458
-rw-r--r--test/rt/source/test/test_sequence_005.c1007
-rw-r--r--test/rt/source/test/test_sequence_006.c1016
-rw-r--r--test/rt/source/test/test_sequence_007.c516
-rw-r--r--test/rt/source/test/test_sequence_008.c620
-rw-r--r--test/rt/source/test/test_sequence_009.c345
-rw-r--r--test/rt/source/test/test_sequence_010.c297
-rw-r--r--test/rt/source/test/test_sequence_011.c286
-rw-r--r--test/rt/source/test/test_sequence_012.c1011
-rw-r--r--test/rt/source/test/test_sequence_013.c1031
-rw-r--r--test/rt/source/test/test_sequence_013.h27
-rw-r--r--test/rt/test.mk3
30 files changed, 5348 insertions, 4527 deletions
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
@@ -82,6 +82,156 @@ THD_FUNCTION(test_support, arg) {
<value>Internal Tests</value>
</type>
<brief>
+ <value>Information.</value>
+ </brief>
+ <description>
+ <value>This sequence reports configuration and version information about the NIL kernel.</value>
+ </description>
+ <condition>
+ <value />
+ </condition>
+ <shared_code>
+ <value><![CDATA[#include "ch.h"]]></value>
+ </shared_code>
+ <cases>
+ <case>
+ <brief>
+ <value>Kernel Info.</value>
+ </brief>
+ <description>
+ <value>The version numbers are reported.</value>
+ </description>
+ <condition>
+ <value />
+ </condition>
+ <various_code>
+ <setup_code>
+ <value />
+ </setup_code>
+ <teardown_code>
+ <value />
+ </teardown_code>
+ <local_variables>
+ <value />
+ </local_variables>
+ </various_code>
+ <steps>
+ <step>
+ <description>
+ <value>Prints the version string.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[test_println("*** Product: ChibiOS/NIL");
+test_print("*** Stable Flag: ");
+test_printn(CH_KERNEL_STABLE);
+test_println("");
+test_print("*** Version String: ");
+test_println(CH_KERNEL_VERSION);
+test_print("*** Major Number: ");
+test_printn(CH_KERNEL_MAJOR);
+test_println("");
+test_print("*** Minor Number: ");
+test_printn(CH_KERNEL_MINOR);
+test_println("");
+test_print("*** Patch Number: ");
+test_printn(CH_KERNEL_PATCH);
+test_println("");]]></value>
+ </code>
+ </step>
+ </steps>
+ </case>
+ <case>
+ <brief>
+ <value>Kernel Settings.</value>
+ </brief>
+ <description>
+ <value>The static kernel settings are reported.</value>
+ </description>
+ <condition>
+ <value />
+ </condition>
+ <various_code>
+ <setup_code>
+ <value />
+ </setup_code>
+ <teardown_code>
+ <value />
+ </teardown_code>
+ <local_variables>
+ <value />
+ </local_variables>
+ </various_code>
+ <steps>
+ <step>
+ <description>
+ <value>Prints the configuration options settings.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[test_print("*** CH_CFG_NUM_THREADS: ");
+test_printn(CH_CFG_NUM_THREADS);
+test_println("");
+test_print("*** CH_CFG_ST_RESOLUTION: ");
+test_printn(CH_CFG_ST_RESOLUTION);
+test_println("");
+test_print("*** CH_CFG_ST_FREQUENCY: ");
+test_printn(CH_CFG_ST_FREQUENCY);
+test_println("");
+test_print("*** CH_CFG_ST_TIMEDELTA: ");
+test_printn(CH_CFG_ST_TIMEDELTA);
+test_println("");
+test_print("*** CH_CFG_USE_SEMAPHORES: ");
+test_printn(CH_CFG_USE_SEMAPHORES);
+test_println("");
+test_print("*** CH_CFG_USE_MUTEXES: ");
+test_printn(CH_CFG_USE_MUTEXES);
+test_println("");
+test_print("*** CH_CFG_USE_EVENTS: ");
+test_printn(CH_CFG_USE_EVENTS);
+test_println("");
+test_print("*** CH_CFG_USE_MAILBOXES: ");
+test_printn(CH_CFG_USE_MAILBOXES);
+test_println("");
+test_print("*** CH_CFG_USE_MEMCORE: ");
+test_printn(CH_CFG_USE_MEMCORE);
+test_println("");
+test_print("*** CH_CFG_USE_HEAP: ");
+test_printn(CH_CFG_USE_HEAP);
+test_println("");
+test_print("*** CH_CFG_USE_MEMPOOLS: ");
+test_printn(CH_CFG_USE_MEMPOOLS);
+test_println("");
+test_print("*** CH_DBG_STATISTICS: ");
+test_printn(CH_DBG_STATISTICS);
+test_println("");
+test_print("*** CH_DBG_SYSTEM_STATE_CHECK: ");
+test_printn(CH_DBG_SYSTEM_STATE_CHECK);
+test_println("");
+test_print("*** CH_DBG_ENABLE_CHECKS: ");
+test_printn(CH_DBG_ENABLE_CHECKS);
+test_println("");
+test_print("*** CH_DBG_ENABLE_ASSERTS: ");
+test_printn(CH_DBG_ENABLE_ASSERTS);
+test_println("");
+test_print("*** CH_DBG_ENABLE_STACK_CHECK: ");
+test_printn(CH_DBG_ENABLE_STACK_CHECK);
+test_println("");]]></value>
+ </code>
+ </step>
+ </steps>
+ </case>
+ </cases>
+ </sequence>
+ <sequence>
+ <type index="0">
+ <value>Internal Tests</value>
+ </type>
+ <brief>
<value>Threads Functionality.</value>
</brief>
<description>
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__)
+#endif
test_sequence_004,
+#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
+ test_sequence_005,
#endif
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
- test_sequence_005,
+ test_sequence_006,
#endif
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
- test_sequence_006,
+ 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
*
* <h2>Description</h2>
- * This sequence tests the ChibiOS/NIL functionalities related to
- * threading.
+ * This sequence reports configuration and version information about
+ * the NIL kernel.
*
* <h2>Test Cases</h2>
* - @subpage test_001_001
@@ -47,123 +47,115 @@
****************************************************************************/
/**
- * @page test_001_001 [1.1] System Tick Counter functionality
+ * @page test_001_001 [1.1] Kernel Info
*
* <h2>Description</h2>
- * The functionality of the API @p chVTGetSystemTimeX() is tested.
+ * The version numbers are reported.
*
* <h2>Test Steps</h2>
- * - [1.1.1] A System Tick Counter increment is expected, the test
- * simply hangs if it does not happen.
+ * - [1.1.1] Prints the version string.
* .
*/
static void test_001_001_execute(void) {
- /* [1.1.1] A System Tick Counter increment is expected, the test
- simply hangs if it does not happen.*/
+ /* [1.1.1] Prints the version string.*/
test_set_step(1);
{
- systime_t time = chVTGetSystemTimeX();
- while (time == chVTGetSystemTimeX()) {
- }
+ test_println("*** Product: ChibiOS/NIL");
+ test_print("*** Stable Flag: ");
+ test_printn(CH_KERNEL_STABLE);
+ test_println("");
+ test_print("*** Version String: ");
+ test_println(CH_KERNEL_VERSION);
+ test_print("*** Major Number: ");
+ test_printn(CH_KERNEL_MAJOR);
+ test_println("");
+ test_print("*** Minor Number: ");
+ test_printn(CH_KERNEL_MINOR);
+ test_println("");
+ test_print("*** Patch Number: ");
+ test_printn(CH_KERNEL_PATCH);
+ test_println("");
}
}
static const testcase_t test_001_001 = {
- "System Tick Counter functionality",
+ "Kernel Info",
NULL,
NULL,
test_001_001_execute
};
/**
- * @page test_001_002 [1.2] Thread Sleep functionality
+ * @page test_001_002 [1.2] Kernel Settings
*
* <h2>Description</h2>
- * The functionality of @p chThdSleep() and derivatives is tested.
+ * The static kernel settings are reported.
*
* <h2>Test Steps</h2>
- * - [1.2.1] The current system time is read then a sleep is performed
- * for 100 system ticks and on exit the system time is verified
- * again.
- * - [1.2.2] The current system time is read then a sleep is performed
- * for 100000 microseconds and on exit the system time is verified
- * again.
- * - [1.2.3] The current system time is read then a sleep is performed
- * for 100 milliseconds and on exit the system time is verified
- * again.
- * - [1.2.4] The current system time is read then a sleep is performed
- * for 1 second and on exit the system time is verified again.
- * - [1.2.5] Function chThdSleepUntil() is tested with a timeline of
- * "now" + 100 ticks.
+ * - [1.2.1] Prints the configuration options settings.
* .
*/
static void test_001_002_execute(void) {
- systime_t time;
- /* [1.2.1] The current system time is read then a sleep is performed
- for 100 system ticks and on exit the system time is verified
- again.*/
+ /* [1.2.1] Prints the configuration options settings.*/
test_set_step(1);
{
- time = chVTGetSystemTimeX();
- chThdSleep(100);
- test_assert_time_window(time + 100,
- time + 100 + 1,
- "out of time window");
- }
-
- /* [1.2.2] The current system time is read then a sleep is performed
- for 100000 microseconds and on exit the system time is verified
- again.*/
- test_set_step(2);
- {
- time = chVTGetSystemTimeX();
- chThdSleepMicroseconds(100000);
- test_assert_time_window(time + US2ST(100000),
- time + US2ST(100000) + 1,
- "out of time window");
- }
-
- /* [1.2.3] The current system time is read then a sleep is performed
- for 100 milliseconds and on exit the system time is verified
- again.*/
- test_set_step(3);
- {
- time = chVTGetSystemTimeX();
- chThdSleepMilliseconds(100);
- test_assert_time_window(time + MS2ST(100),
- time + MS2ST(100) + 1,
- "out of time window");
- }
-
- /* [1.2.4] The current system time is read then a sleep is performed
- for 1 second and on exit the system time is verified again.*/
- test_set_step(4);
- {
- time = chVTGetSystemTimeX();
- chThdSleepSeconds(1);
- test_assert_time_window(time + S2ST(1),
- time + S2ST(1) + 1,
- "out of time window");
- }
-
- /* [1.2.5] Function chThdSleepUntil() is tested with a timeline of
- "now" + 100 ticks.*/
- test_set_step(5);
- {
- time = chVTGetSystemTimeX();
- chThdSleepUntil(time + 100);
- test_assert_time_window(time + 100,
- time + 100 + 1,
- "out of time window");
+ test_print("*** CH_CFG_NUM_THREADS: ");
+ test_printn(CH_CFG_NUM_THREADS);
+ test_println("");
+ test_print("*** CH_CFG_ST_RESOLUTION: ");
+ test_printn(CH_CFG_ST_RESOLUTION);
+ test_println("");
+ test_print("*** CH_CFG_ST_FREQUENCY: ");
+ test_printn(CH_CFG_ST_FREQUENCY);
+ test_println("");
+ test_print("*** CH_CFG_ST_TIMEDELTA: ");
+ test_printn(CH_CFG_ST_TIMEDELTA);
+ test_println("");
+ test_print("*** CH_CFG_USE_SEMAPHORES: ");
+ test_printn(CH_CFG_USE_SEMAPHORES);
+ test_println("");
+ test_print("*** CH_CFG_USE_MUTEXES: ");
+ test_printn(CH_CFG_USE_MUTEXES);
+ test_println("");
+ test_print("*** CH_CFG_USE_EVENTS: ");
+ test_printn(CH_CFG_USE_EVENTS);
+ test_println("");
+ test_print("*** CH_CFG_USE_MAILBOXES: ");
+ test_printn(CH_CFG_USE_MAILBOXES);
+ test_println("");
+ test_print("*** CH_CFG_USE_MEMCORE: ");
+ test_printn(CH_CFG_USE_MEMCORE);
+ test_println("");
+ test_print("*** CH_CFG_USE_HEAP: ");
+ test_printn(CH_CFG_USE_HEAP);
+ test_println("");
+ test_print("*** CH_CFG_USE_MEMPOOLS: ");
+ test_printn(CH_CFG_USE_MEMPOOLS);
+ test_println("");
+ test_print("*** CH_DBG_STATISTICS: ");
+ test_printn(CH_DBG_STATISTICS);
+ test_println("");
+ test_print("*** CH_DBG_SYSTEM_STATE_CHECK: ");
+ test_printn(CH_DBG_SYSTEM_STATE_CHECK);
+ test_println("");
+ test_print("*** CH_DBG_ENABLE_CHECKS: ");
+ test_printn(CH_DBG_ENABLE_CHECKS);
+ test_println("");
+ test_print("*** CH_DBG_ENABLE_ASSERTS: ");
+ test_printn(CH_DBG_ENABLE_ASSERTS);
+ test_println("");
+ test_print("*** CH_DBG_ENABLE_STACK_CHECK: ");
+ test_printn(CH_DBG_ENABLE_STACK_CHECK);
+ test_println("");
}
}
static const testcase_t test_001_002 = {
- "Thread Sleep functionality",
+ "Kernel Settings",
NULL,
NULL,
test_001_002_execute
@@ -174,7 +166,7 @@ static const testcase_t test_001_002 = {
****************************************************************************/
/**
- * @brief Threads Functionality.
+ * @brief Information.
*/
const testcase_t * const test_sequence_001[] = {
&test_001_001,
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,224 +22,151 @@
* @file test_sequence_002.c
* @brief Test Sequence 002 code.
*
- * @page test_sequence_002 [2] Semaphores
+ * @page test_sequence_002 [2] Threads Functionality
*
* File: @ref test_sequence_002.c
*
* <h2>Description</h2>
* This sequence tests the ChibiOS/NIL functionalities related to
- * counter semaphores.
- *
- * <h2>Conditions</h2>
- * This sequence is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_SEMAPHORES
- * .
+ * threading.
*
* <h2>Test Cases</h2>
* - @subpage test_002_001
* - @subpage test_002_002
- * - @subpage test_002_003
* .
*/
-#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
-
/****************************************************************************
* Shared code.
****************************************************************************/
#include "ch.h"
-static semaphore_t sem1;
-
/****************************************************************************
* Test cases.
****************************************************************************/
/**
- * @page test_002_001 [2.1] Semaphore primitives, no state change
+ * @page test_002_001 [2.1] System Tick Counter functionality
*
* <h2>Description</h2>
- * Wait, Signal and Reset primitives are tested. The testing thread
- * does not trigger a state change.
+ * The functionality of the API @p chVTGetSystemTimeX() is tested.
*
* <h2>Test Steps</h2>
- * - [2.1.1] The function chSemWait() is invoked, after return the
- * counter and the returned message are tested.
- * - [2.1.2] The function chSemSignal() is invoked, after return the
- * counter is tested.
- * - [2.1.3] The function chSemReset() is invoked, after return the
- * counter is tested.
+ * - [2.1.1] A System Tick Counter increment is expected, the test
+ * simply hangs if it does not happen.
* .
*/
-static void test_002_001_setup(void) {
- chSemObjectInit(&sem1, 1);
-}
-
-static void test_002_001_teardown(void) {
- chSemReset(&sem1, 0);
-}
-
static void test_002_001_execute(void) {
- /* [2.1.1] The function chSemWait() is invoked, after return the
- counter and the returned message are tested.*/
+ /* [2.1.1] A System Tick Counter increment is expected, the test
+ simply hangs if it does not happen.*/
test_set_step(1);
{
- msg_t msg;
-
- msg = chSemWait(&sem1);
- test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
- test_assert(MSG_OK == msg, "wrong returned message");
- }
-
- /* [2.1.2] The function chSemSignal() is invoked, after return the
- counter is tested.*/
- test_set_step(2);
- {
- chSemSignal(&sem1);
- test_assert_lock(chSemGetCounterI(&sem1) == 1, "wrong counter value");
- }
-
- /* [2.1.3] The function chSemReset() is invoked, after return the
- counter is tested.*/
- test_set_step(3);
- {
- chSemReset(&sem1, 2);
- test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value");
+ systime_t time = chVTGetSystemTimeX();
+ while (time == chVTGetSystemTimeX()) {
+ }
}
}
static const testcase_t test_002_001 = {
- "Semaphore primitives, no state change",
- test_002_001_setup,
- test_002_001_teardown,
+ "System Tick Counter functionality",
+ NULL,
+ NULL,
test_002_001_execute
};
/**
- * @page test_002_002 [2.2] Semaphore primitives, with state change
+ * @page test_002_002 [2.2] Thread Sleep functionality
*
* <h2>Description</h2>
- * Wait, Signal and Reset primitives are tested. The testing thread
- * triggers a state change.
+ * The functionality of @p chThdSleep() and derivatives is tested.
*
* <h2>Test Steps</h2>
- * - [2.2.1] The function chSemWait() is invoked, after return the
- * counter and the returned message are tested. The semaphore is
- * signaled by another thread.
- * - [2.2.2] The function chSemWait() is invoked, after return the
- * counter and the returned message are tested. The semaphore is
- * reset by another thread.
+ * - [2.2.1] The current system time is read then a sleep is performed
+ * for 100 system ticks and on exit the system time is verified
+ * again.
+ * - [2.2.2] The current system time is read then a sleep is performed
+ * for 100000 microseconds and on exit the system time is verified
+ * again.
+ * - [2.2.3] The current system time is read then a sleep is performed
+ * for 100 milliseconds and on exit the system time is verified
+ * again.
+ * - [2.2.4] The current system time is read then a sleep is performed
+ * for 1 second and on exit the system time is verified again.
+ * - [2.2.5] Function chThdSleepUntil() is tested with a timeline of
+ * "now" + 100 ticks.
* .
*/
-static void test_002_002_setup(void) {
- chSemObjectInit(&gsem1, 0);
-}
-
-static void test_002_002_teardown(void) {
- chSemReset(&gsem1, 0);
-}
-
static void test_002_002_execute(void) {
+ systime_t time;
- /* [2.2.1] The function chSemWait() is invoked, after return the
- counter and the returned message are tested. The semaphore is
- signaled by another thread.*/
+ /* [2.2.1] The current system time is read then a sleep is performed
+ for 100 system ticks and on exit the system time is verified
+ again.*/
test_set_step(1);
{
- msg_t msg;
-
- msg = chSemWait(&gsem1);
- test_assert_lock(chSemGetCounterI(&gsem1) == 0, "wrong counter value");
- test_assert(MSG_OK == msg, "wrong returned message");
+ time = chVTGetSystemTimeX();
+ chThdSleep(100);
+ test_assert_time_window(time + 100,
+ time + 100 + 1,
+ "out of time window");
}
- /* [2.2.2] The function chSemWait() is invoked, after return the
- counter and the returned message are tested. The semaphore is
- reset by another thread.*/
+ /* [2.2.2] The current system time is read then a sleep is performed
+ for 100000 microseconds and on exit the system time is verified
+ again.*/
test_set_step(2);
{
- msg_t msg;
-
- msg = chSemWait(&gsem2);
- test_assert_lock(chSemGetCounterI(&gsem2) == 0,"wrong counter value");
- test_assert(MSG_RESET == msg, "wrong returned message");
+ time = chVTGetSystemTimeX();
+ chThdSleepMicroseconds(100000);
+ test_assert_time_window(time + US2ST(100000),
+ time + US2ST(100000) + 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,
- test_002_002_execute
-};
-
-/**
- * @page test_002_003 [2.3] Semaphores timeout
- *
- * <h2>Description</h2>
- * Timeout on semaphores is tested.
- *
- * <h2>Test Steps</h2>
- * - [2.3.1] The function chSemWaitTimeout() is invoked a first time,
- * after return the system time, the counter and the returned message
- * are tested.
- * - [2.3.2] The function chSemWaitTimeout() is invoked again, after
- * return the system time, the counter and the returned message are
- * tested.
- * .
- */
-
-static void test_002_003_setup(void) {
- chSemObjectInit(&sem1, 0);
-}
-
-static void test_002_003_teardown(void) {
- chSemReset(&sem1, 0);
-}
-static void test_002_003_execute(void) {
- systime_t time;
- msg_t msg;
+ /* [2.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.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);
+ /* [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();
- msg = chSemWaitTimeout(&sem1, MS2ST(1000));
- test_assert_time_window(time + MS2ST(1000),
- time + MS2ST(1000) + 1,
+ chThdSleepSeconds(1);
+ test_assert_time_window(time + S2ST(1),
+ time + S2ST(1) + 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);
+ /* [2.2.5] Function chThdSleepUntil() is tested with a timeline of
+ "now" + 100 ticks.*/
+ test_set_step(5);
{
time = chVTGetSystemTimeX();
- msg = chSemWaitTimeout(&sem1, MS2ST(1000));
- test_assert_time_window(time + MS2ST(1000),
- time + MS2ST(1000) + 1,
+ chThdSleepUntil(time + 100);
+ test_assert_time_window(time + 100,
+ time + 100 + 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
+static const testcase_t test_002_002 = {
+ "Thread Sleep functionality",
+ NULL,
+ NULL,
+ test_002_002_execute
};
/****************************************************************************
@@ -247,13 +174,10 @@ static const testcase_t test_002_003 = {
****************************************************************************/
/**
- * @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
*
* <h2>Description</h2>
* This sequence tests the ChibiOS/NIL functionalities related to
- * threads suspend/resume and event flags.
+ * counter semaphores.
+ *
+ * <h2>Conditions</h2>
+ * This sequence is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_SEMAPHORES
+ * .
*
* <h2>Test Cases</h2>
* - @subpage test_003_001
* - @subpage test_003_002
+ * - @subpage test_003_003
* .
*/
+#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
+
/****************************************************************************
* Shared code.
****************************************************************************/
-static thread_reference_t tr1;
+#include "ch.h"
+
+static semaphore_t sem1;
/****************************************************************************
* Test cases.
****************************************************************************/
/**
- * @page test_003_001 [3.1] Suspend and Resume functionality
+ * @page test_003_001 [3.1] Semaphore primitives, no state change
*
* <h2>Description</h2>
- * The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
- * tested.
+ * Wait, Signal and Reset primitives are tested. The testing thread
+ * does not trigger a state change.
*
* <h2>Test Steps</h2>
- * - [3.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
- * is remotely resumed with message @p MSG_OK. On return the message
- * and the state of the reference are tested.
- * - [3.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
- * is not resumed so a timeout must occur. On return the message and
- * the state of the reference are tested.
+ * - [3.1.1] The function chSemWait() is invoked, after return the
+ * counter and the returned message are tested.
+ * - [3.1.2] The function chSemSignal() is invoked, after return the
+ * counter is tested.
+ * - [3.1.3] The function chSemReset() is invoked, after return the
+ * counter is tested.
* .
*/
static void test_003_001_setup(void) {
- tr1 = NULL;
+ chSemObjectInit(&sem1, 1);
+}
+
+static void test_003_001_teardown(void) {
+ chSemReset(&sem1, 0);
}
static void test_003_001_execute(void) {
- systime_t time;
- msg_t msg;
- /* [3.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
- is remotely resumed with message @p MSG_OK. On return the message
- and the state of the reference are tested.*/
+ /* [3.1.1] The function chSemWait() is invoked, after return the
+ counter and the returned message are tested.*/
test_set_step(1);
{
- chSysLock();
- msg = chThdSuspendTimeoutS(&gtr1, TIME_INFINITE);
- chSysUnlock();
- test_assert(NULL == gtr1, "not NULL");
- test_assert(MSG_OK == msg,"wrong returned message");
+ msg_t msg;
+
+ msg = chSemWait(&sem1);
+ test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
+ test_assert(MSG_OK == msg, "wrong returned message");
}
- /* [3.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
- is not resumed so a timeout must occur. On return the message and
- the state of the reference are tested.*/
+ /* [3.1.2] The function chSemSignal() is invoked, after return the
+ counter is tested.*/
test_set_step(2);
{
- chSysLock();
- time = chVTGetSystemTimeX();
- msg = chThdSuspendTimeoutS(&tr1, MS2ST(1000));
- chSysUnlock();
- test_assert_time_window(time + MS2ST(1000),
- time + MS2ST(1000) + 1,
- "out of time window");
- test_assert(NULL == tr1, "not NULL");
- test_assert(MSG_TIMEOUT == msg, "wrong returned message");
+ chSemSignal(&sem1);
+ test_assert_lock(chSemGetCounterI(&sem1) == 1, "wrong counter value");
+ }
+
+ /* [3.1.3] The function chSemReset() is invoked, after return the
+ counter is tested.*/
+ test_set_step(3);
+ {
+ chSemReset(&sem1, 2);
+ test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value");
}
}
static const testcase_t test_003_001 = {
- "Suspend and Resume functionality",
+ "Semaphore primitives, no state change",
test_003_001_setup,
- NULL,
+ test_003_001_teardown,
test_003_001_execute
};
-#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
/**
- * @page test_003_002 [3.2] Events Flags functionality
+ * @page test_003_002 [3.2] Semaphore primitives, with state change
*
* <h2>Description</h2>
- * Event flags functionality is tested.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_EVENTS
- * .
+ * Wait, Signal and Reset primitives are tested. The testing thread
+ * triggers a state change.
*
* <h2>Test Steps</h2>
- * - [3.2.1] A set of event flags are set on the current thread then
- * the function chEvtWaitAnyTimeout() is invoked, the function is
- * supposed to return immediately because the event flags are already
- * pending, after return the events mask is tested.
- * - [3.2.2] The pending event flags mask is cleared then the function
- * chEvtWaitAnyTimeout() is invoked, after return the events mask is
- * tested. The thread is signaled by another thread.
- * - [3.2.3] The function chEvtWaitAnyTimeout() is invoked, no event
- * can wakeup the thread, the function must return because timeout.
+ * - [3.2.1] The function chSemWait() is invoked, after return the
+ * counter and the returned message are tested. The semaphore is
+ * signaled by another thread.
+ * - [3.2.2] The function chSemWait() is invoked, after return the
+ * counter and the returned message are tested. The semaphore is
+ * reset by another thread.
* .
*/
+static void test_003_002_setup(void) {
+ chSemObjectInit(&gsem1, 0);
+}
+
+static void test_003_002_teardown(void) {
+ chSemReset(&gsem1, 0);
+}
+
static void test_003_002_execute(void) {
- systime_t time;
- eventmask_t events;
- /* [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.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);
{
+ msg_t msg;
+
+ 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 = {
+ "Semaphore primitives, with state change",
+ test_003_002_setup,
+ test_003_002_teardown,
+ test_003_002_execute
+};
+
+/**
+ * @page test_003_003 [3.3] Semaphores timeout
+ *
+ * <h2>Description</h2>
+ * Timeout on semaphores is tested.
+ *
+ * <h2>Test Steps</h2>
+ * - [3.3.1] The function chSemWaitTimeout() is invoked a first time,
+ * after return the system time, the counter and the returned message
+ * are tested.
+ * - [3.3.2] The function chSemWaitTimeout() is invoked again, after
+ * return the system time, the counter and the returned message are
+ * tested.
+ * .
+ */
+
+static void test_003_003_setup(void) {
+ chSemObjectInit(&sem1, 0);
+}
+
+static void test_003_003_teardown(void) {
+ chSemReset(&sem1, 0);
+}
+
+static void test_003_003_execute(void) {
+ systime_t time;
+ msg_t msg;
+
+ /* [3.3.1] The function chSemWaitTimeout() is invoked a first time,
+ after return the system time, the counter and the returned message
+ are tested.*/
+ test_set_step(1);
+ {
time = chVTGetSystemTimeX();
- 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 = 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.2.3] The function chEvtWaitAnyTimeout() is invoked, no event
- can wakeup the thread, the function must return because timeout.*/
- test_set_step(3);
+ /* [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();
- events = chEvtWaitAnyTimeout(0, MS2ST(1000));
+ msg = chSemWaitTimeout(&sem1, 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");
+ test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
+ test_assert(MSG_TIMEOUT == msg, "wrong timeout message");
}
}
-static const testcase_t test_003_002 = {
- "Events Flags functionality",
- NULL,
- NULL,
- test_003_002_execute
+static const testcase_t test_003_003 = {
+ "Semaphores timeout",
+ test_003_003_setup,
+ test_003_003_teardown,
+ test_003_003_execute
};
-#endif /* CH_CFG_USE_EVENTS */
/****************************************************************************
* 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
*
* <h2>Description</h2>
* This sequence tests the ChibiOS/NIL functionalities related to
- * mailboxes.
- *
- * <h2>Conditions</h2>
- * This sequence is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_MAILBOXES
- * .
+ * threads suspend/resume and event flags.
*
* <h2>Test Cases</h2>
* - @subpage test_004_001
* - @subpage test_004_002
- * - @subpage test_004_003
* .
*/
-#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
-
/****************************************************************************
* Shared code.
****************************************************************************/
-#define ALLOWED_DELAY MS2ST(5)
-#define MB_SIZE 4
-
-static msg_t mb_buffer[MB_SIZE];
-static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE);
+static thread_reference_t tr1;
/****************************************************************************
* Test cases.
****************************************************************************/
/**
- * @page test_004_001 [4.1] Mailbox normal API, non-blocking tests
+ * @page test_004_001 [4.1] Suspend and Resume functionality
*
* <h2>Description</h2>
- * The mailbox normal API is tested without triggering blocking
- * conditions.
+ * The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
+ * tested.
*
* <h2>Test Steps</h2>
- * - [4.1.1] Testing the mailbox size.
- * - [4.1.2] Resetting the mailbox, conditions are checked, no errors
- * expected.
- * - [4.1.3] Testing the behavior of API when the mailbox is in reset
- * state then return in active state.
- * - [4.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
- * once, no errors expected.
- * - [4.1.5] Testing intermediate conditions. Data pointers must be
- * aligned, semaphore counters are checked.
- * - [4.1.6] Emptying the mailbox using chMBFetch(), no errors
- * expected.
- * - [4.1.7] Posting and then fetching one more message, no errors
- * expected.
- * - [4.1.8] Testing final conditions. Data pointers must be aligned to
- * buffer start, semaphore counters are checked.
+ * - [4.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
+ * is remotely resumed with message @p MSG_OK. On return the message
+ * and the state of the reference are tested.
+ * - [4.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
+ * is not resumed so a timeout must occur. On return the message and
+ * the state of the reference are tested.
* .
*/
static void test_004_001_setup(void) {
- chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
-}
-
-static void test_004_001_teardown(void) {
- chMBReset(&mb1);
+ tr1 = NULL;
}
static void test_004_001_execute(void) {
- msg_t msg1, msg2;
- unsigned i;
+ systime_t time;
+ msg_t msg;
- /* [4.1.1] Testing the mailbox size.*/
+ /* [4.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
+ is remotely resumed with message @p MSG_OK. On return the message
+ and the state of the reference are tested.*/
test_set_step(1);
{
- test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
+ chSysLock();
+ msg = chThdSuspendTimeoutS(&gtr1, TIME_INFINITE);
+ chSysUnlock();
+ test_assert(NULL == gtr1, "not NULL");
+ test_assert(MSG_OK == msg,"wrong returned message");
}
- /* [4.1.2] Resetting the mailbox, conditions are checked, no errors
- expected.*/
+ /* [4.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
+ is not resumed so a timeout must occur. On return the message and
+ the state of the reference are tested.*/
test_set_step(2);
{
- chMBReset(&mb1);
- test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
- test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
- test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
- test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
- }
-
- /* [4.1.3] Testing the behavior of API when the mailbox is in reset
- state then return in active state.*/
- test_set_step(3);
- {
- msg1 = chMBPost(&mb1, (msg_t)0, TIME_INFINITE);
- test_assert(msg1 == MSG_RESET, "not in reset state");
- msg1 = chMBPostAhead(&mb1, (msg_t)0, TIME_INFINITE);
- test_assert(msg1 == MSG_RESET, "not in reset state");
- msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
- test_assert(msg1 == MSG_RESET, "not in reset state");
- chMBResumeX(&mb1);
- }
-
- /* [4.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
- once, no errors expected.*/
- test_set_step(4);
- {
- for (i = 0; i < MB_SIZE - 1; i++) {
- msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
- test_assert(msg1 == MSG_OK, "wrong wake-up message");
- }
- msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE);
- test_assert(msg1 == MSG_OK, "wrong wake-up message");
- }
-
- /* [4.1.5] Testing intermediate conditions. Data pointers must be
- aligned, semaphore counters are checked.*/
- test_set_step(5);
- {
- test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
- test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
- test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
- }
-
- /* [4.1.6] Emptying the mailbox using chMBFetch(), no errors
- expected.*/
- test_set_step(6);
- {
- for (i = 0; i < MB_SIZE; i++) {
- msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
- test_assert(msg1 == MSG_OK, "wrong wake-up message");
- test_emit_token(msg2);
- }
- test_assert_sequence("ABCD", "wrong get sequence");
- }
-
- /* [4.1.7] Posting and then fetching one more message, no errors
- expected.*/
- test_set_step(7);
- {
- msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
- test_assert(msg1 == MSG_OK, "wrong wake-up message");
- msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
- test_assert(msg1 == MSG_OK, "wrong wake-up message");
- }
-
- /* [4.1.8] Testing final conditions. Data pointers must be aligned to
- buffer start, semaphore counters are checked.*/
- test_set_step(8);
- {
- test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
- test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
- test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
- test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
+ chSysLock();
+ time = chVTGetSystemTimeX();
+ msg = chThdSuspendTimeoutS(&tr1, MS2ST(1000));
+ chSysUnlock();
+ test_assert_time_window(time + MS2ST(1000),
+ time + MS2ST(1000) + 1,
+ "out of time window");
+ test_assert(NULL == tr1, "not NULL");
+ test_assert(MSG_TIMEOUT == msg, "wrong returned message");
}
}
static const testcase_t test_004_001 = {
- "Mailbox normal API, non-blocking tests",
+ "Suspend and Resume functionality",
test_004_001_setup,
- test_004_001_teardown,
+ NULL,
test_004_001_execute
};
+#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
/**
- * @page test_004_002 [4.2] Mailbox I-Class API, non-blocking tests
+ * @page test_004_002 [4.2] Events Flags functionality
*
* <h2>Description</h2>
- * The mailbox I-Class API is tested without triggering blocking
- * conditions.
+ * Event flags functionality is tested.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_EVENTS
+ * .
*
* <h2>Test Steps</h2>
- * - [4.2.1] Testing the mailbox size.
- * - [4.2.2] Resetting the mailbox, conditions are checked, no errors
- * expected.
- * - [4.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
- * once, no errors expected.
- * - [4.2.4] Testing intermediate conditions. Data pointers must be
- * aligned, semaphore counters are checked.
- * - [4.2.5] Emptying the mailbox using chMBFetchI(), no errors
- * expected.
- * - [4.2.6] Posting and then fetching one more message, no errors
- * expected.
- * - [4.2.7] Testing final conditions. Data pointers must be aligned to
- * buffer start, semaphore counters are checked.
+ * - [4.2.1] A set of event flags are set on the current thread then
+ * the function chEvtWaitAnyTimeout() is invoked, the function is
+ * supposed to return immediately because the event flags are already
+ * pending, after return the events mask is tested.
+ * - [4.2.2] The pending event flags mask is cleared then the function
+ * chEvtWaitAnyTimeout() is invoked, after return the events mask is
+ * tested. The thread is signaled by another thread.
+ * - [4.2.3] The function chEvtWaitAnyTimeout() is invoked, no event
+ * can wakeup the thread, the function must return because timeout.
* .
*/
-static void test_004_002_setup(void) {
- chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
-}
-
-static void test_004_002_teardown(void) {
- chMBReset(&mb1);
-}
-
static void test_004_002_execute(void) {
- msg_t msg1, msg2;
- unsigned i;
+ systime_t time;
+ eventmask_t events;
- /* [4.2.1] Testing the mailbox size.*/
+ /* [4.2.1] A set of event flags are set on the current thread then
+ the function chEvtWaitAnyTimeout() is invoked, the function is
+ supposed to return immediately because the event flags are already
+ pending, after return the events mask is tested.*/
test_set_step(1);
{
- test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
+ time = chVTGetSystemTimeX();
+ chEvtSignal(chThdGetSelfX(), 0x55);
+ events = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000));
+ test_assert((eventmask_t)0 != events, "timed out");
+ test_assert((eventmask_t)0x55 == events, "wrong events mask");
}
- /* [4.2.2] Resetting the mailbox, conditions are checked, no errors
- expected.*/
+ /* [4.2.2] The pending event flags mask is cleared then the function
+ chEvtWaitAnyTimeout() is invoked, after return the events mask is
+ tested. The thread is signaled by another thread.*/
test_set_step(2);
{
- chSysLock();
- chMBResetI(&mb1);
- chSysUnlock();
- test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
- test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
- test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
- test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
- chMBResumeX(&mb1);
+ time = chVTGetSystemTimeX();
+ chThdGetSelfX()->epmask = 0;
+ events = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000));
+ test_assert((eventmask_t)0 != events, "timed out");
+ test_assert((eventmask_t)0x55 == events, "wrong events mask");
}
- /* [4.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
- once, no errors expected.*/
+ /* [4.2.3] The function chEvtWaitAnyTimeout() is invoked, no event
+ can wakeup the thread, the function must return because timeout.*/
test_set_step(3);
{
- for (i = 0; i < MB_SIZE - 1; i++) {
- chSysLock();
- msg1 = chMBPostI(&mb1, 'B' + i);
- chSysUnlock();
- test_assert(msg1 == MSG_OK, "wrong wake-up message");
- }
- chSysLock();
- msg1 = chMBPostAheadI(&mb1, 'A');
- chSysUnlock();
- test_assert(msg1 == MSG_OK, "wrong wake-up message");
- }
-
- /* [4.2.4] Testing intermediate conditions. Data pointers must be
- aligned, semaphore counters are checked.*/
- test_set_step(4);
- {
- test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
- test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
- test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
- }
-
- /* [4.2.5] Emptying the mailbox using chMBFetchI(), no errors
- expected.*/
- test_set_step(5);
- {
- for (i = 0; i < MB_SIZE; i++) {
- chSysLock();
- msg1 = chMBFetchI(&mb1, &msg2);
- chSysUnlock();
- test_assert(msg1 == MSG_OK, "wrong wake-up message");
- test_emit_token(msg2);
- }
- test_assert_sequence("ABCD", "wrong get sequence");
- }
-
- /* [4.2.6] Posting and then fetching one more message, no errors
- expected.*/
- test_set_step(6);
- {
- msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
- test_assert(msg1 == MSG_OK, "wrong wake-up message");
- msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
- test_assert(msg1 == MSG_OK, "wrong wake-up message");
- }
-
- /* [4.2.7] Testing final conditions. Data pointers must be aligned to
- buffer start, semaphore counters are checked.*/
- test_set_step(7);
- {
- test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
- test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
- test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
- test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
+ time = chVTGetSystemTimeX();
+ events = chEvtWaitAnyTimeout(0, MS2ST(1000));
+ test_assert_time_window(time + MS2ST(1000),
+ time + MS2ST(1000) + 1,
+ "out of time window");
+ test_assert((eventmask_t)0 == events, "wrong events mask");
}
}
static const testcase_t test_004_002 = {
- "Mailbox I-Class API, non-blocking tests",
- test_004_002_setup,
- test_004_002_teardown,
+ "Events Flags functionality",
+ NULL,
+ NULL,
test_004_002_execute
};
-
-/**
- * @page test_004_003 [4.3] Mailbox timeouts
- *
- * <h2>Description</h2>
- * The mailbox API is tested for timeouts.
- *
- * <h2>Test Steps</h2>
- * - [4.3.1] Filling the mailbox.
- * - [4.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
- * chMBPostAheadI() timeout.
- * - [4.3.3] Resetting the mailbox.
- * - [4.3.4] Testing chMBFetch() and chMBFetchI() timeout.
- * .
- */
-
-static void test_004_003_setup(void) {
- chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
-}
-
-static void test_004_003_teardown(void) {
- chMBReset(&mb1);
-}
-
-static void test_004_003_execute(void) {
- msg_t msg1, msg2;
- unsigned i;
-
- /* [4.3.1] Filling the mailbox.*/
- test_set_step(1);
- {
- for (i = 0; i < MB_SIZE; i++) {
- msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
- test_assert(msg1 == MSG_OK, "wrong wake-up message");
- }
- }
-
- /* [4.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
- chMBPostAheadI() timeout.*/
- test_set_step(2);
- {
- msg1 = chMBPost(&mb1, 'X', 1);
- test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
- chSysLock();
- msg1 = chMBPostI(&mb1, 'X');
- chSysUnlock();
- test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
- msg1 = chMBPostAhead(&mb1, 'X', 1);
- test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
- chSysLock();
- msg1 = chMBPostAheadI(&mb1, 'X');
- chSysUnlock();
- test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
- }
-
- /* [4.3.3] Resetting the mailbox.*/
- test_set_step(3);
- {
- chMBReset(&mb1);;
- chMBResumeX(&mb1);
- }
-
- /* [4.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/
- test_set_step(4);
- {
- msg1 = chMBFetch(&mb1, &msg2, 1);
- test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
- chSysLock();
- msg1 = chMBFetchI(&mb1, &msg2);
- chSysUnlock();
- test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
- }
-}
-
-static const testcase_t test_004_003 = {
- "Mailbox timeouts",
- test_004_003_setup,
- test_004_003_teardown,
- test_004_003_execute
-};
+#endif /* CH_CFG_USE_EVENTS */
/****************************************************************************
* Exported data.
****************************************************************************/
/**
- * @brief Mailboxes.
+ * @brief Suspend/Resume and Event Flags.
*/
const testcase_t * const test_sequence_004[] = {
&test_004_001,
+#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
&test_004_002,
- &test_004_003,
+#endif
NULL
};
-
-#endif /* CH_CFG_USE_MAILBOXES */
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
*
* <h2>Description</h2>
* This sequence tests the ChibiOS/NIL functionalities related to
- * memory pools.
+ * mailboxes.
*
* <h2>Conditions</h2>
* This sequence is only executed if the following preprocessor condition
* evaluates to true:
- * - CH_CFG_USE_MEMPOOLS
+ * - CH_CFG_USE_MAILBOXES
* .
*
* <h2>Test Cases</h2>
@@ -43,254 +43,366 @@
* .
*/
-#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
+#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
/****************************************************************************
* Shared code.
****************************************************************************/
-#define MEMORY_POOL_SIZE 4
+#define ALLOWED_DELAY MS2ST(5)
+#define MB_SIZE 4
-static uint32_t objects[MEMORY_POOL_SIZE];
-static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL);
-
-#if CH_CFG_USE_SEMAPHORES
-static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t));
-#endif
-
-static void *null_provider(size_t size, unsigned align) {
-
- (void)size;
- (void)align;
-
- return NULL;
-}
+static msg_t mb_buffer[MB_SIZE];
+static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE);
/****************************************************************************
* Test cases.
****************************************************************************/
/**
- * @page test_005_001 [5.1] Loading and emptying a memory pool
+ * @page test_005_001 [5.1] Mailbox normal API, non-blocking tests
*
* <h2>Description</h2>
- * The memory pool functionality is tested by loading and emptying it,
- * all conditions are tested.
+ * The mailbox normal API is tested without triggering blocking
+ * conditions.
*
* <h2>Test Steps</h2>
- * - [5.1.1] Adding the objects to the pool using chPoolLoadArray().
- * - [5.1.2] Emptying the pool using chPoolAlloc().
- * - [5.1.3] Now must be empty.
- * - [5.1.4] Adding the objects to the pool using chPoolFree().
- * - [5.1.5] Emptying the pool using chPoolAlloc() again.
- * - [5.1.6] Now must be empty again.
- * - [5.1.7] Covering the case where a provider is unable to return
- * more memory.
+ * - [5.1.1] Testing the mailbox size.
+ * - [5.1.2] Resetting the mailbox, conditions are checked, no errors
+ * expected.
+ * - [5.1.3] Testing the behavior of API when the mailbox is in reset
+ * state then return in active state.
+ * - [5.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
+ * once, no errors expected.
+ * - [5.1.5] Testing intermediate conditions. Data pointers must be
+ * aligned, semaphore counters are checked.
+ * - [5.1.6] Emptying the mailbox using chMBFetch(), no errors
+ * expected.
+ * - [5.1.7] Posting and then fetching one more message, no errors
+ * expected.
+ * - [5.1.8] Testing final conditions. Data pointers must be aligned to
+ * buffer start, semaphore counters are checked.
* .
*/
static void test_005_001_setup(void) {
- chPoolObjectInit(&mp1, sizeof (uint32_t), NULL);
+ chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
+}
+
+static void test_005_001_teardown(void) {
+ chMBReset(&mb1);
}
static void test_005_001_execute(void) {
+ msg_t msg1, msg2;
unsigned i;
- /* [5.1.1] Adding the objects to the pool using chPoolLoadArray().*/
+ /* [5.1.1] Testing the mailbox size.*/
test_set_step(1);
{
- chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE);
+ test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
}
- /* [5.1.2] Emptying the pool using chPoolAlloc().*/
+ /* [5.1.2] Resetting the mailbox, conditions are checked, no errors
+ expected.*/
test_set_step(2);
{
- for (i = 0; i < MEMORY_POOL_SIZE; i++)
- test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
+ chMBReset(&mb1);
+ test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
+ test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
+ test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
+ test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
}
- /* [5.1.3] Now must be empty.*/
+ /* [5.1.3] Testing the behavior of API when the mailbox is in reset
+ state then return in active state.*/
test_set_step(3);
{
- test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
+ msg1 = chMBPost(&mb1, (msg_t)0, TIME_INFINITE);
+ test_assert(msg1 == MSG_RESET, "not in reset state");
+ msg1 = chMBPostAhead(&mb1, (msg_t)0, TIME_INFINITE);
+ test_assert(msg1 == MSG_RESET, "not in reset state");
+ msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
+ test_assert(msg1 == MSG_RESET, "not in reset state");
+ chMBResumeX(&mb1);
}
- /* [5.1.4] Adding the objects to the pool using chPoolFree().*/
+ /* [5.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
+ once, no errors expected.*/
test_set_step(4);
{
- for (i = 0; i < MEMORY_POOL_SIZE; i++)
- chPoolFree(&mp1, &objects[i]);
+ for (i = 0; i < MB_SIZE - 1; i++) {
+ msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ }
+ msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
}
- /* [5.1.5] Emptying the pool using chPoolAlloc() again.*/
+ /* [5.1.5] Testing intermediate conditions. Data pointers must be
+ aligned, semaphore counters are checked.*/
test_set_step(5);
{
- for (i = 0; i < MEMORY_POOL_SIZE; i++)
- test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
+ test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
+ test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
+ test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
}
- /* [5.1.6] Now must be empty again.*/
+ /* [5.1.6] Emptying the mailbox using chMBFetch(), no errors
+ expected.*/
test_set_step(6);
{
- test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
+ for (i = 0; i < MB_SIZE; i++) {
+ msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ test_emit_token(msg2);
+ }
+ test_assert_sequence("ABCD", "wrong get sequence");
}
- /* [5.1.7] Covering the case where a provider is unable to return
- more memory.*/
+ /* [5.1.7] Posting and then fetching one more message, no errors
+ expected.*/
test_set_step(7);
{
- chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider);
- test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory");
+ msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ }
+
+ /* [5.1.8] Testing final conditions. Data pointers must be aligned to
+ buffer start, semaphore counters are checked.*/
+ test_set_step(8);
+ {
+ test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
+ test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
+ test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
+ test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
}
}
static const testcase_t test_005_001 = {
- "Loading and emptying a memory pool",
+ "Mailbox normal API, non-blocking tests",
test_005_001_setup,
- NULL,
+ test_005_001_teardown,
test_005_001_execute
};
-#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
/**
- * @page test_005_002 [5.2] Loading and emptying a guarded memory pool without waiting
+ * @page test_005_002 [5.2] Mailbox I-Class API, non-blocking tests
*
* <h2>Description</h2>
- * The memory pool functionality is tested by loading and emptying it,
- * all conditions are tested.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_SEMAPHORES
- * .
+ * The mailbox I-Class API is tested without triggering blocking
+ * conditions.
*
* <h2>Test Steps</h2>
- * - [5.2.1] Adding the objects to the pool using
- * chGuardedPoolLoadArray().
- * - [5.2.2] Emptying the pool using chGuardedPoolAllocTimeout().
- * - [5.2.3] Now must be empty.
- * - [5.2.4] Adding the objects to the pool using chGuardedPoolFree().
- * - [5.2.5] Emptying the pool using chGuardedPoolAllocTimeout() again.
- * - [5.2.6] Now must be empty again.
+ * - [5.2.1] Testing the mailbox size.
+ * - [5.2.2] Resetting the mailbox, conditions are checked, no errors
+ * expected.
+ * - [5.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
+ * once, no errors expected.
+ * - [5.2.4] Testing intermediate conditions. Data pointers must be
+ * aligned, semaphore counters are checked.
+ * - [5.2.5] Emptying the mailbox using chMBFetchI(), no errors
+ * expected.
+ * - [5.2.6] Posting and then fetching one more message, no errors
+ * expected.
+ * - [5.2.7] Testing final conditions. Data pointers must be aligned to
+ * buffer start, semaphore counters are checked.
* .
*/
static void test_005_002_setup(void) {
- chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
+ chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
+}
+
+static void test_005_002_teardown(void) {
+ chMBReset(&mb1);
}
static void test_005_002_execute(void) {
+ msg_t msg1, msg2;
unsigned i;
- /* [5.2.1] Adding the objects to the pool using
- chGuardedPoolLoadArray().*/
+ /* [5.2.1] Testing the mailbox size.*/
test_set_step(1);
{
- chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE);
+ test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
}
- /* [5.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/
+ /* [5.2.2] Resetting the mailbox, conditions are checked, no errors
+ expected.*/
test_set_step(2);
{
- for (i = 0; i < MEMORY_POOL_SIZE; i++)
- test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
+ chSysLock();
+ chMBResetI(&mb1);
+ chSysUnlock();
+ test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
+ test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
+ test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
+ test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
+ chMBResumeX(&mb1);
}
- /* [5.2.3] Now must be empty.*/
+ /* [5.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
+ once, no errors expected.*/
test_set_step(3);
{
- test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
+ for (i = 0; i < MB_SIZE - 1; i++) {
+ chSysLock();
+ msg1 = chMBPostI(&mb1, 'B' + i);
+ chSysUnlock();
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ }
+ chSysLock();
+ msg1 = chMBPostAheadI(&mb1, 'A');
+ chSysUnlock();
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
}
- /* [5.2.4] Adding the objects to the pool using
- chGuardedPoolFree().*/
+ /* [5.2.4] Testing intermediate conditions. Data pointers must be
+ aligned, semaphore counters are checked.*/
test_set_step(4);
{
- for (i = 0; i < MEMORY_POOL_SIZE; i++)
- chGuardedPoolFree(&gmp1, &objects[i]);
+ test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
+ test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
+ test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
}
- /* [5.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
- again.*/
+ /* [5.2.5] Emptying the mailbox using chMBFetchI(), no errors
+ expected.*/
test_set_step(5);
{
- for (i = 0; i < MEMORY_POOL_SIZE; i++)
- test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
+ for (i = 0; i < MB_SIZE; i++) {
+ chSysLock();
+ msg1 = chMBFetchI(&mb1, &msg2);
+ chSysUnlock();
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ test_emit_token(msg2);
+ }
+ test_assert_sequence("ABCD", "wrong get sequence");
}
- /* [5.2.6] Now must be empty again.*/
+ /* [5.2.6] Posting and then fetching one more message, no errors
+ expected.*/
test_set_step(6);
{
- test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
+ msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ }
+
+ /* [5.2.7] Testing final conditions. Data pointers must be aligned to
+ buffer start, semaphore counters are checked.*/
+ test_set_step(7);
+ {
+ test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
+ test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
+ test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
+ test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
}
}
static const testcase_t test_005_002 = {
- "Loading and emptying a guarded memory pool without waiting",
+ "Mailbox I-Class API, non-blocking tests",
test_005_002_setup,
- NULL,
+ test_005_002_teardown,
test_005_002_execute
};
-#endif /* CH_CFG_USE_SEMAPHORES */
-#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
/**
- * @page test_005_003 [5.3] Guarded Memory Pools timeout
+ * @page test_005_003 [5.3] Mailbox timeouts
*
* <h2>Description</h2>
- * The timeout features for the Guarded Memory Pools is tested.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_SEMAPHORES
- * .
+ * The mailbox API is tested for timeouts.
*
* <h2>Test Steps</h2>
- * - [5.3.1] Trying to allocate with 100mS timeout, must fail because
- * the pool is empty.
+ * - [5.3.1] Filling the mailbox.
+ * - [5.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
+ * chMBPostAheadI() timeout.
+ * - [5.3.3] Resetting the mailbox.
+ * - [5.3.4] Testing chMBFetch() and chMBFetchI() timeout.
* .
*/
static void test_005_003_setup(void) {
- chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
+ chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
+}
+
+static void test_005_003_teardown(void) {
+ chMBReset(&mb1);
}
static void test_005_003_execute(void) {
+ msg_t msg1, msg2;
+ unsigned i;
- /* [5.3.1] Trying to allocate with 100mS timeout, must fail because
- the pool is empty.*/
+ /* [5.3.1] Filling the mailbox.*/
test_set_step(1);
{
- test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty");
+ for (i = 0; i < MB_SIZE; i++) {
+ msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ }
+ }
+
+ /* [5.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
+ chMBPostAheadI() timeout.*/
+ test_set_step(2);
+ {
+ msg1 = chMBPost(&mb1, 'X', 1);
+ test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
+ chSysLock();
+ msg1 = chMBPostI(&mb1, 'X');
+ chSysUnlock();
+ test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
+ msg1 = chMBPostAhead(&mb1, 'X', 1);
+ test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
+ chSysLock();
+ msg1 = chMBPostAheadI(&mb1, 'X');
+ chSysUnlock();
+ test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
+ }
+
+ /* [5.3.3] Resetting the mailbox.*/
+ test_set_step(3);
+ {
+ chMBReset(&mb1);;
+ chMBResumeX(&mb1);
+ }
+
+ /* [5.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/
+ test_set_step(4);
+ {
+ msg1 = chMBFetch(&mb1, &msg2, 1);
+ test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
+ chSysLock();
+ msg1 = chMBFetchI(&mb1, &msg2);
+ chSysUnlock();
+ test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
}
}
static const testcase_t test_005_003 = {
- "Guarded Memory Pools timeout",
+ "Mailbox timeouts",
test_005_003_setup,
- NULL,
+ test_005_003_teardown,
test_005_003_execute
};
-#endif /* CH_CFG_USE_SEMAPHORES */
/****************************************************************************
* Exported data.
****************************************************************************/
/**
- * @brief Memory Pools.
+ * @brief Mailboxes.
*/
const testcase_t * const test_sequence_005[] = {
&test_005_001,
-#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
&test_005_002,
-#endif
-#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
&test_005_003,
-#endif
NULL
};
-#endif /* CH_CFG_USE_MEMPOOLS */
+#endif /* CH_CFG_USE_MAILBOXES */
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
*
* <h2>Description</h2>
* This sequence tests the ChibiOS/NIL functionalities related to
- * memory heaps.
+ * memory pools.
*
* <h2>Conditions</h2>
* This sequence is only executed if the following preprocessor condition
* evaluates to true:
- * - CH_CFG_USE_HEAP
+ * - CH_CFG_USE_MEMPOOLS
* .
*
* <h2>Test Cases</h2>
* - @subpage test_006_001
* - @subpage test_006_002
+ * - @subpage test_006_003
* .
*/
-#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
+#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
/****************************************************************************
* Shared code.
****************************************************************************/
-#define ALLOC_SIZE 16
-#define HEAP_SIZE (ALLOC_SIZE * 8)
+#define MEMORY_POOL_SIZE 4
-static memory_heap_t test_heap;
-static CH_HEAP_AREA(myheap, HEAP_SIZE);
+static uint32_t objects[MEMORY_POOL_SIZE];
+static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL);
+
+#if CH_CFG_USE_SEMAPHORES
+static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t));
+#endif
+
+static void *null_provider(size_t size, unsigned align) {
+
+ (void)size;
+ (void)align;
+
+ return NULL;
+}
/****************************************************************************
* Test cases.
****************************************************************************/
/**
- * @page test_006_001 [6.1] Allocation and fragmentation
+ * @page test_006_001 [6.1] Loading and emptying a memory pool
*
* <h2>Description</h2>
- * Series of allocations/deallocations are performed in carefully
- * designed sequences in order to stimulate all the possible code paths
- * inside the allocator. The test expects to find the heap back to the
- * initial status after each sequence.
+ * The memory pool functionality is tested by loading and emptying it,
+ * all conditions are tested.
*
* <h2>Test Steps</h2>
- * - [6.1.1] Testing initial conditions, the heap must not be
- * fragmented and one free block present.
- * - [6.1.2] Trying to allocate an block bigger than available space,
- * an error is expected.
- * - [6.1.3] Single block allocation using chHeapAlloc() then the block
- * is freed using chHeapFree(), must not fail.
- * - [6.1.4] Using chHeapStatus() to assess the heap state. There must
- * be at least one free block of sufficient size.
- * - [6.1.5] Allocating then freeing in the same order.
- * - [6.1.6] Allocating then freeing in reverse order.
- * - [6.1.7] Small fragments handling. Checking the behavior when
- * allocating blocks with size not multiple of alignment unit.
- * - [6.1.8] Skipping a fragment, the first fragment in the list is too
- * small so the allocator must pick the second one.
- * - [6.1.9] Allocating the whole available space.
- * - [6.1.10] Testing final conditions. The heap geometry must be the
- * same than the one registered at beginning.
+ * - [6.1.1] Adding the objects to the pool using chPoolLoadArray().
+ * - [6.1.2] Emptying the pool using chPoolAlloc().
+ * - [6.1.3] Now must be empty.
+ * - [6.1.4] Adding the objects to the pool using chPoolFree().
+ * - [6.1.5] Emptying the pool using chPoolAlloc() again.
+ * - [6.1.6] Now must be empty again.
+ * - [6.1.7] Covering the case where a provider is unable to return
+ * more memory.
* .
*/
static void test_006_001_setup(void) {
- chHeapObjectInit(&test_heap, myheap, sizeof(myheap));
+ chPoolObjectInit(&mp1, sizeof (uint32_t), NULL);
}
static void test_006_001_execute(void) {
- void *p1, *p2, *p3;
- size_t n, sz;
+ unsigned i;
- /* [6.1.1] Testing initial conditions, the heap must not be
- fragmented and one free block present.*/
+ /* [6.1.1] Adding the objects to the pool using chPoolLoadArray().*/
test_set_step(1);
{
- test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented");
+ chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE);
}
- /* [6.1.2] Trying to allocate an block bigger than available space,
- an error is expected.*/
+ /* [6.1.2] Emptying the pool using chPoolAlloc().*/
test_set_step(2);
{
- p1 = chHeapAlloc(&test_heap, HEAP_SIZE * 2);
- test_assert(p1 == NULL, "allocation not failed");
+ for (i = 0; i < MEMORY_POOL_SIZE; i++)
+ test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
}
- /* [6.1.3] Single block allocation using chHeapAlloc() then the block
- is freed using chHeapFree(), must not fail.*/
+ /* [6.1.3] Now must be empty.*/
test_set_step(3);
{
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- test_assert(p1 != NULL, "allocation failed");
- chHeapFree(p1);
+ test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
}
- /* [6.1.4] Using chHeapStatus() to assess the heap state. There must
- be at least one free block of sufficient size.*/
+ /* [6.1.4] Adding the objects to the pool using chPoolFree().*/
test_set_step(4);
{
- size_t total_size, largest_size;
-
- n = chHeapStatus(&test_heap, &total_size, &largest_size);
- test_assert(n == 1, "missing free block");
- test_assert(total_size >= ALLOC_SIZE, "unexpected heap state");
- test_assert(total_size == largest_size, "unexpected heap state");
+ for (i = 0; i < MEMORY_POOL_SIZE; i++)
+ chPoolFree(&mp1, &objects[i]);
}
- /* [6.1.5] Allocating then freeing in the same order.*/
+ /* [6.1.5] Emptying the pool using chPoolAlloc() again.*/
test_set_step(5);
{
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- chHeapFree(p1); /* Does not merge.*/
- chHeapFree(p2); /* Merges backward.*/
- chHeapFree(p3); /* Merges both sides.*/
- test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
+ for (i = 0; i < MEMORY_POOL_SIZE; i++)
+ test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
}
- /* [6.1.6] Allocating then freeing in reverse order.*/
+ /* [6.1.6] Now must be empty again.*/
test_set_step(6);
{
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- chHeapFree(p3); /* Merges forward.*/
- chHeapFree(p2); /* Merges forward.*/
- chHeapFree(p1); /* Merges forward.*/
- test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
+ test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
}
- /* [6.1.7] Small fragments handling. Checking the behavior when
- allocating blocks with size not multiple of alignment unit.*/
+ /* [6.1.7] Covering the case where a provider is unable to return
+ more memory.*/
test_set_step(7);
{
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1);
- p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- chHeapFree(p1);
- test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- /* Note, the first situation happens when the alignment size is smaller
- than the header size, the second in the other cases.*/
- test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) ||
- (chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
- chHeapFree(p2);
- chHeapFree(p1);
- test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
- }
-
- /* [6.1.8] Skipping a fragment, the first fragment in the list is too
- small so the allocator must pick the second one.*/
- test_set_step(8);
- {
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- chHeapFree(p1);
- test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/
- chHeapFree(p1);
- chHeapFree(p2);
- test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
- }
-
- /* [6.1.9] Allocating the whole available space.*/
- test_set_step(9);
- {
- (void)chHeapStatus(&test_heap, &n, NULL);
- p1 = chHeapAlloc(&test_heap, n);
- test_assert(p1 != NULL, "allocation failed");
- test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty");
- chHeapFree(p1);
- }
-
- /* [6.1.10] Testing final conditions. The heap geometry must be the
- same than the one registered at beginning.*/
- test_set_step(10);
- {
- test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
- test_assert(n == sz, "size changed");
+ chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider);
+ test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory");
}
}
static const testcase_t test_006_001 = {
- "Allocation and fragmentation",
+ "Loading and emptying a memory pool",
test_006_001_setup,
NULL,
test_006_001_execute
};
+#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
/**
- * @page test_006_002 [6.2] Default Heap
+ * @page test_006_002 [6.2] Loading and emptying a guarded memory pool without waiting
*
* <h2>Description</h2>
- * The default heap is pre-allocated in the system. We test base
- * functionality.
+ * The memory pool functionality is tested by loading and emptying it,
+ * all conditions are tested.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_SEMAPHORES
+ * .
*
* <h2>Test Steps</h2>
- * - [6.2.1] Single block allocation using chHeapAlloc() then the block
- * is freed using chHeapFree(), must not fail.
- * - [6.2.2] Testing allocation failure.
+ * - [6.2.1] Adding the objects to the pool using
+ * chGuardedPoolLoadArray().
+ * - [6.2.2] Emptying the pool using chGuardedPoolAllocTimeout().
+ * - [6.2.3] Now must be empty.
+ * - [6.2.4] Adding the objects to the pool using chGuardedPoolFree().
+ * - [6.2.5] Emptying the pool using chGuardedPoolAllocTimeout() again.
+ * - [6.2.6] Now must be empty again.
* .
*/
+static void test_006_002_setup(void) {
+ chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
+}
+
static void test_006_002_execute(void) {
- void *p1;
- size_t total_size, largest_size;
+ unsigned i;
- /* [6.2.1] Single block allocation using chHeapAlloc() then the block
- is freed using chHeapFree(), must not fail.*/
+ /* [6.2.1] Adding the objects to the pool using
+ chGuardedPoolLoadArray().*/
test_set_step(1);
{
- (void)chHeapStatus(NULL, &total_size, &largest_size);
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- test_assert(p1 != NULL, "allocation failed");
- chHeapFree(p1);
+ chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE);
}
- /* [6.2.2] Testing allocation failure.*/
+ /* [6.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/
test_set_step(2);
{
- p1 = chHeapAlloc(NULL, (size_t)-256);
- test_assert(p1 == NULL, "allocation not failed");
+ for (i = 0; i < MEMORY_POOL_SIZE; i++)
+ test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
+ }
+
+ /* [6.2.3] Now must be empty.*/
+ test_set_step(3);
+ {
+ test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
+ }
+
+ /* [6.2.4] Adding the objects to the pool using
+ chGuardedPoolFree().*/
+ test_set_step(4);
+ {
+ for (i = 0; i < MEMORY_POOL_SIZE; i++)
+ chGuardedPoolFree(&gmp1, &objects[i]);
+ }
+
+ /* [6.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
+ again.*/
+ test_set_step(5);
+ {
+ for (i = 0; i < MEMORY_POOL_SIZE; i++)
+ test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
+ }
+
+ /* [6.2.6] Now must be empty again.*/
+ test_set_step(6);
+ {
+ test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
}
}
static const testcase_t test_006_002 = {
- "Default Heap",
- NULL,
+ "Loading and emptying a guarded memory pool without waiting",
+ test_006_002_setup,
NULL,
test_006_002_execute
};
+#endif /* CH_CFG_USE_SEMAPHORES */
+
+#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
+/**
+ * @page test_006_003 [6.3] Guarded Memory Pools timeout
+ *
+ * <h2>Description</h2>
+ * The timeout features for the Guarded Memory Pools is tested.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_SEMAPHORES
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [6.3.1] Trying to allocate with 100mS timeout, must fail because
+ * the pool is empty.
+ * .
+ */
+
+static void test_006_003_setup(void) {
+ chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
+}
+
+static void test_006_003_execute(void) {
+
+ /* [6.3.1] Trying to allocate with 100mS timeout, must fail because
+ the pool is empty.*/
+ test_set_step(1);
+ {
+ test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty");
+ }
+}
+
+static const testcase_t test_006_003 = {
+ "Guarded Memory Pools timeout",
+ test_006_003_setup,
+ NULL,
+ test_006_003_execute
+};
+#endif /* CH_CFG_USE_SEMAPHORES */
/****************************************************************************
* Exported data.
****************************************************************************/
/**
- * @brief Memory Heaps.
+ * @brief Memory Pools.
*/
const testcase_t * const test_sequence_006[] = {
&test_006_001,
+#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
&test_006_002,
+#endif
+#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
+ &test_006_003,
+#endif
NULL
};
-#endif /* CH_CFG_USE_HEAP */
+#endif /* CH_CFG_USE_MEMPOOLS */
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
+ *
+ * <h2>Description</h2>
+ * This sequence tests the ChibiOS/NIL functionalities related to
+ * memory heaps.
+ *
+ * <h2>Conditions</h2>
+ * This sequence is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_HEAP
+ * .
+ *
+ * <h2>Test Cases</h2>
+ * - @subpage test_007_001
+ * - @subpage test_007_002
+ * .
+ */
+
+#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
+
+/****************************************************************************
+ * Shared code.
+ ****************************************************************************/
+
+#define ALLOC_SIZE 16
+#define HEAP_SIZE (ALLOC_SIZE * 8)
+
+static memory_heap_t test_heap;
+static CH_HEAP_AREA(myheap, HEAP_SIZE);
+
+/****************************************************************************
+ * Test cases.
+ ****************************************************************************/
+
+/**
+ * @page test_007_001 [7.1] Allocation and fragmentation
+ *
+ * <h2>Description</h2>
+ * Series of allocations/deallocations are performed in carefully
+ * designed sequences in order to stimulate all the possible code paths
+ * inside the allocator. The test expects to find the heap back to the
+ * initial status after each sequence.
+ *
+ * <h2>Test Steps</h2>
+ * - [7.1.1] Testing initial conditions, the heap must not be
+ * fragmented and one free block present.
+ * - [7.1.2] Trying to allocate an block bigger than available space,
+ * an error is expected.
+ * - [7.1.3] Single block allocation using chHeapAlloc() then the block
+ * is freed using chHeapFree(), must not fail.
+ * - [7.1.4] Using chHeapStatus() to assess the heap state. There must
+ * be at least one free block of sufficient size.
+ * - [7.1.5] Allocating then freeing in the same order.
+ * - [7.1.6] Allocating then freeing in reverse order.
+ * - [7.1.7] Small fragments handling. Checking the behavior when
+ * allocating blocks with size not multiple of alignment unit.
+ * - [7.1.8] Skipping a fragment, the first fragment in the list is too
+ * small so the allocator must pick the second one.
+ * - [7.1.9] Allocating the whole available space.
+ * - [7.1.10] Testing final conditions. The heap geometry must be the
+ * same than the one registered at beginning.
+ * .
+ */
+
+static void test_007_001_setup(void) {
+ chHeapObjectInit(&test_heap, myheap, sizeof(myheap));
+}
+
+static void test_007_001_execute(void) {
+ void *p1, *p2, *p3;
+ size_t n, sz;
+
+ /* [7.1.1] Testing initial conditions, the heap must not be
+ fragmented and one free block present.*/
+ test_set_step(1);
+ {
+ test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented");
+ }
+
+ /* [7.1.2] Trying to allocate an block bigger than available space,
+ an error is expected.*/
+ test_set_step(2);
+ {
+ p1 = chHeapAlloc(&test_heap, HEAP_SIZE * 2);
+ test_assert(p1 == NULL, "allocation not failed");
+ }
+
+ /* [7.1.3] Single block allocation using chHeapAlloc() then the block
+ is freed using chHeapFree(), must not fail.*/
+ test_set_step(3);
+ {
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ test_assert(p1 != NULL, "allocation failed");
+ chHeapFree(p1);
+ }
+
+ /* [7.1.4] Using chHeapStatus() to assess the heap state. There must
+ be at least one free block of sufficient size.*/
+ test_set_step(4);
+ {
+ size_t total_size, largest_size;
+
+ n = chHeapStatus(&test_heap, &total_size, &largest_size);
+ test_assert(n == 1, "missing free block");
+ test_assert(total_size >= ALLOC_SIZE, "unexpected heap state");
+ test_assert(total_size == largest_size, "unexpected heap state");
+ }
+
+ /* [7.1.5] Allocating then freeing in the same order.*/
+ test_set_step(5);
+ {
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ chHeapFree(p1); /* Does not merge.*/
+ chHeapFree(p2); /* Merges backward.*/
+ chHeapFree(p3); /* Merges both sides.*/
+ test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
+ }
+
+ /* [7.1.6] Allocating then freeing in reverse order.*/
+ test_set_step(6);
+ {
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ chHeapFree(p3); /* Merges forward.*/
+ chHeapFree(p2); /* Merges forward.*/
+ chHeapFree(p1); /* Merges forward.*/
+ test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
+ }
+
+ /* [7.1.7] Small fragments handling. Checking the behavior when
+ allocating blocks with size not multiple of alignment unit.*/
+ test_set_step(7);
+ {
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1);
+ p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ chHeapFree(p1);
+ test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ /* Note, the first situation happens when the alignment size is smaller
+ than the header size, the second in the other cases.*/
+ test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) ||
+ (chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
+ chHeapFree(p2);
+ chHeapFree(p1);
+ test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
+ }
+
+ /* [7.1.8] Skipping a fragment, the first fragment in the list is too
+ small so the allocator must pick the second one.*/
+ test_set_step(8);
+ {
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ chHeapFree(p1);
+ test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/
+ chHeapFree(p1);
+ chHeapFree(p2);
+ test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
+ }
+
+ /* [7.1.9] Allocating the whole available space.*/
+ test_set_step(9);
+ {
+ (void)chHeapStatus(&test_heap, &n, NULL);
+ p1 = chHeapAlloc(&test_heap, n);
+ test_assert(p1 != NULL, "allocation failed");
+ test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty");
+ chHeapFree(p1);
+ }
+
+ /* [7.1.10] Testing final conditions. The heap geometry must be the
+ same than the one registered at beginning.*/
+ test_set_step(10);
+ {
+ test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
+ test_assert(n == sz, "size changed");
+ }
+}
+
+static const testcase_t test_007_001 = {
+ "Allocation and fragmentation",
+ test_007_001_setup,
+ NULL,
+ test_007_001_execute
+};
+
+/**
+ * @page test_007_002 [7.2] Default Heap
+ *
+ * <h2>Description</h2>
+ * The default heap is pre-allocated in the system. We test base
+ * functionality.
+ *
+ * <h2>Test Steps</h2>
+ * - [7.2.1] Single block allocation using chHeapAlloc() then the block
+ * is freed using chHeapFree(), must not fail.
+ * - [7.2.2] Testing allocation failure.
+ * .
+ */
+
+static void test_007_002_execute(void) {
+ void *p1;
+ size_t total_size, largest_size;
+
+ /* [7.2.1] Single block allocation using chHeapAlloc() then the block
+ is freed using chHeapFree(), must not fail.*/
+ test_set_step(1);
+ {
+ (void)chHeapStatus(NULL, &total_size, &largest_size);
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ test_assert(p1 != NULL, "allocation failed");
+ chHeapFree(p1);
+ }
+
+ /* [7.2.2] Testing allocation failure.*/
+ test_set_step(2);
+ {
+ p1 = chHeapAlloc(NULL, (size_t)-256);
+ test_assert(p1 == NULL, "allocation not failed");
+ }
+}
+
+static const testcase_t test_007_002 = {
+ "Default Heap",
+ NULL,
+ NULL,
+ test_007_002_execute
+};
+
+/****************************************************************************
+ * Exported data.
+ ****************************************************************************/
+
+/**
+ * @brief Memory Heaps.
+ */
+const testcase_t * const test_sequence_007[] = {
+ &test_007_001,
+ &test_007_002,
+ NULL
+};
+
+#endif /* CH_CFG_USE_HEAP */
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
@@ -131,6 +131,210 @@ systime_t test_wait_tick(void) {
<value>Internal Tests</value>
</type>
<brief>
+ <value>Information.</value>
+ </brief>
+ <description>
+ <value>This sequence reports configuration and version information about the RT kernel.</value>
+ </description>
+ <condition>
+ <value />
+ </condition>
+ <shared_code>
+ <value><![CDATA[#include "ch.h"]]></value>
+ </shared_code>
+ <cases>
+ <case>
+ <brief>
+ <value>Kernel Info.</value>
+ </brief>
+ <description>
+ <value>The version numbers are reported.</value>
+ </description>
+ <condition>
+ <value />
+ </condition>
+ <various_code>
+ <setup_code>
+ <value />
+ </setup_code>
+ <teardown_code>
+ <value />
+ </teardown_code>
+ <local_variables>
+ <value />
+ </local_variables>
+ </various_code>
+ <steps>
+ <step>
+ <description>
+ <value>Prints the version string.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[test_println("*** Product: ChibiOS/RT");
+test_print("*** Stable Flag: ");
+test_printn(CH_KERNEL_STABLE);
+test_println("");
+test_print("*** Version String: ");
+test_println(CH_KERNEL_VERSION);
+test_print("*** Major Number: ");
+test_printn(CH_KERNEL_MAJOR);
+test_println("");
+test_print("*** Minor Number: ");
+test_printn(CH_KERNEL_MINOR);
+test_println("");
+test_print("*** Patch Number: ");
+test_printn(CH_KERNEL_PATCH);
+test_println("");]]></value>
+ </code>
+ </step>
+ </steps>
+ </case>
+ <case>
+ <brief>
+ <value>Kernel Settings.</value>
+ </brief>
+ <description>
+ <value>The static kernel settings are reported.</value>
+ </description>
+ <condition>
+ <value />
+ </condition>
+ <various_code>
+ <setup_code>
+ <value />
+ </setup_code>
+ <teardown_code>
+ <value />
+ </teardown_code>
+ <local_variables>
+ <value />
+ </local_variables>
+ </various_code>
+ <steps>
+ <step>
+ <description>
+ <value>Prints the configuration options settings.</value>
+ </description>
+ <tags>
+ <value />
+ </tags>
+ <code>
+ <value><![CDATA[test_print("*** CH_CFG_ST_RESOLUTION: ");
+test_printn(CH_CFG_ST_RESOLUTION);
+test_println("");
+test_print("*** CH_CFG_ST_FREQUENCY: ");
+test_printn(CH_CFG_ST_FREQUENCY);
+test_println("");
+test_print("*** CH_CFG_ST_TIMEDELTA: ");
+test_printn(CH_CFG_ST_TIMEDELTA);
+test_println("");
+test_print("*** CH_CFG_TIME_QUANTUM: ");
+test_printn(CH_CFG_TIME_QUANTUM);
+test_println("");
+test_print("*** CH_CFG_MEMCORE_SIZE: ");
+test_printn(CH_CFG_MEMCORE_SIZE);
+test_println("");
+test_print("*** CH_CFG_NO_IDLE_THREAD: ");
+test_printn(CH_CFG_NO_IDLE_THREAD);
+test_println("");
+test_print("*** CH_CFG_OPTIMIZE_SPEED: ");
+test_printn(CH_CFG_OPTIMIZE_SPEED);
+test_println("");
+test_print("*** CH_CFG_USE_TM: ");
+test_printn(CH_CFG_USE_TM);
+test_println("");
+test_print("*** CH_CFG_USE_REGISTRY: ");
+test_printn(CH_CFG_USE_REGISTRY);
+test_println("");
+test_print("*** CH_CFG_USE_WAITEXIT: ");
+test_printn(CH_CFG_USE_WAITEXIT);
+test_println("");
+test_print("*** CH_CFG_USE_SEMAPHORES: ");
+test_printn(CH_CFG_USE_SEMAPHORES);
+test_println("");
+test_print("*** CH_CFG_USE_SEMAPHORES_PRI: ");
+test_printn(CH_CFG_USE_SEMAPHORES_PRIORITY);
+test_println("");
+test_print("*** CH_CFG_USE_MUTEXES: ");
+test_printn(CH_CFG_USE_MUTEXES);
+test_println("");
+test_print("*** CH_CFG_USE_MUTEXES_RECURS: ");
+test_printn(CH_CFG_USE_MUTEXES_RECURSIVE);
+test_println("");
+test_print("*** CH_CFG_USE_CONDVARS: ");
+test_printn(CH_CFG_USE_CONDVARS);
+test_println("");
+test_print("*** CH_CFG_USE_CONDVARS_TIMEO: ");
+test_printn(CH_CFG_USE_CONDVARS_TIMEOUT);
+test_println("");
+test_print("*** CH_CFG_USE_EVENTS: ");
+test_printn(CH_CFG_USE_EVENTS);
+test_println("");
+test_print("*** CH_CFG_USE_EVENTS_TIMEOUT: ");
+test_printn(CH_CFG_USE_EVENTS_TIMEOUT);
+test_println("");
+test_print("*** CH_CFG_USE_MESSAGES: ");
+test_printn(CH_CFG_USE_MESSAGES);
+test_println("");
+test_print("*** CH_CFG_USE_MESSAGES_PRI: ");
+test_printn(CH_CFG_USE_MESSAGES_PRIORITY);
+test_println("");
+test_print("*** CH_CFG_USE_MAILBOXES: ");
+test_printn(CH_CFG_USE_MAILBOXES);
+test_println("");
+test_print("*** CH_CFG_USE_MEMCORE: ");
+test_printn(CH_CFG_USE_MEMCORE);
+test_println("");
+test_print("*** CH_CFG_USE_HEAP: ");
+test_printn(CH_CFG_USE_HEAP);
+test_println("");
+test_print("*** CH_CFG_USE_MEMPOOLS: ");
+test_printn(CH_CFG_USE_MEMPOOLS);
+test_println("");
+test_print("*** CH_CFG_USE_DYNAMIC: ");
+test_printn(CH_CFG_USE_DYNAMIC);
+test_println("");
+test_print("*** CH_DBG_STATISTICS: ");
+test_printn(CH_DBG_STATISTICS);
+test_println("");
+test_print("*** CH_DBG_SYSTEM_STATE_CHECK: ");
+test_printn(CH_DBG_SYSTEM_STATE_CHECK);
+test_println("");
+test_print("*** CH_DBG_ENABLE_CHECKS: ");
+test_printn(CH_DBG_ENABLE_CHECKS);
+test_println("");
+test_print("*** CH_DBG_ENABLE_ASSERTS: ");
+test_printn(CH_DBG_ENABLE_ASSERTS);
+test_println("");
+test_print("*** CH_DBG_TRACE_MASK: ");
+test_printn(CH_DBG_TRACE_MASK);
+test_println("");
+test_print("*** CH_DBG_TRACE_BUFFER_SIZE: ");
+test_printn(CH_DBG_TRACE_BUFFER_SIZE);
+test_println("");
+test_print("*** CH_DBG_ENABLE_STACK_CHECK: ");
+test_printn(CH_DBG_ENABLE_STACK_CHECK);
+test_println("");
+test_print("*** CH_DBG_FILL_THREADS: ");
+test_printn(CH_DBG_FILL_THREADS);
+test_println("");
+test_print("*** CH_DBG_THREADS_PROFILING: ");
+test_printn(CH_DBG_THREADS_PROFILING);
+test_println("");]]></value>
+ </code>
+ </step>
+ </steps>
+ </case>
+ </cases>
+ </sequence>
+ <sequence>
+ <type index="0">
+ <value>Internal Tests</value>
+ </type>
+ <brief>
<value>System layer and port interface.</value>
</brief>
<description>
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
*
* <h2>Description</h2>
- * The functionality of the system layer and port interface is tested.
- * Basic RT functionality is taken for granted or this test suite could
- * not even be executed. Errors in implementation are detected by
- * executing this sequence with the state checker enabled
- * (CH_DBG_STATE_CHECKER=TRUE).
+ * This sequence reports configuration and version information about
+ * the RT kernel.
*
* <h2>Test Cases</h2>
* - @subpage test_001_001
* - @subpage test_001_002
- * - @subpage test_001_003
- * - @subpage test_001_004
* .
*/
@@ -45,238 +40,190 @@
* Shared code.
****************************************************************************/
-/* Timer callback for testing system functions in ISR context.*/
-static void vtcb(void *p) {
- syssts_t sts;
-
- (void)p;
-
- /* Testing normal case.*/
- chSysLockFromISR();
- chSysUnlockFromISR();
-
- /* Reentrant case.*/
- chSysLockFromISR();
- sts = chSysGetStatusAndLockX();
- chSysRestoreStatusX(sts);
- chSysUnlockFromISR();
-}
+#include "ch.h"
/****************************************************************************
* Test cases.
****************************************************************************/
/**
- * @page test_001_001 [1.1] System integrity functionality
+ * @page test_001_001 [1.1] Kernel Info
*
* <h2>Description</h2>
- * The system self-test functionality is invoked in order to make an
- * initial system state assessment and for coverage.
+ * The version numbers are reported.
*
* <h2>Test Steps</h2>
- * - [1.1.1] Testing Ready List integrity.
- * - [1.1.2] Testing Virtual Timers List integrity.
- * - [1.1.3] Testing Registry List integrity.
- * - [1.1.4] Testing Port-defined integrity.
+ * - [1.1.1] Prints the version string.
* .
*/
static void test_001_001_execute(void) {
- bool result;
- /* [1.1.1] Testing Ready List integrity.*/
+ /* [1.1.1] Prints the version string.*/
test_set_step(1);
{
- chSysLock();
- result = chSysIntegrityCheckI(CH_INTEGRITY_RLIST);
- chSysUnlock();
- test_assert(result == false, "ready list check failed");
- }
-
- /* [1.1.2] Testing Virtual Timers List integrity.*/
- test_set_step(2);
- {
- chSysLock();
- result = chSysIntegrityCheckI(CH_INTEGRITY_VTLIST);
- chSysUnlock();
- test_assert(result == false, "virtual timers list check failed");
- }
-
- /* [1.1.3] Testing Registry List integrity.*/
- test_set_step(3);
- {
- chSysLock();
- result = chSysIntegrityCheckI(CH_INTEGRITY_REGISTRY);
- chSysUnlock();
- test_assert(result == false, "registry list check failed");
- }
-
- /* [1.1.4] Testing Port-defined integrity.*/
- test_set_step(4);
- {
- chSysLock();
- result = chSysIntegrityCheckI(CH_INTEGRITY_PORT);
- chSysUnlock();
- test_assert(result == false, "port layer check failed");
+ test_println("*** Product: ChibiOS/RT");
+ test_print("*** Stable Flag: ");
+ test_printn(CH_KERNEL_STABLE);
+ test_println("");
+ test_print("*** Version String: ");
+ test_println(CH_KERNEL_VERSION);
+ test_print("*** Major Number: ");
+ test_printn(CH_KERNEL_MAJOR);
+ test_println("");
+ test_print("*** Minor Number: ");
+ test_printn(CH_KERNEL_MINOR);
+ test_println("");
+ test_print("*** Patch Number: ");
+ test_printn(CH_KERNEL_PATCH);
+ test_println("");
}
}
static const testcase_t test_001_001 = {
- "System integrity functionality",
+ "Kernel Info",
NULL,
NULL,
test_001_001_execute
};
/**
- * @page test_001_002 [1.2] Critical zones functionality
+ * @page test_001_002 [1.2] Kernel Settings
*
* <h2>Description</h2>
- * The critical zones API is invoked for coverage.
+ * The static kernel settings are reported.
*
* <h2>Test Steps</h2>
- * - [1.2.1] Testing chSysGetStatusAndLockX() and
- * chSysRestoreStatusX(), non reentrant case.
- * - [1.2.2] Testing chSysGetStatusAndLockX() and
- * chSysRestoreStatusX(), reentrant case.
- * - [1.2.3] Testing chSysUnconditionalLock().
- * - [1.2.4] Testing chSysUnconditionalUnlock().
- * - [1.2.5] Testing from ISR context using a virtual timer.
+ * - [1.2.1] Prints the configuration options settings.
* .
*/
static void test_001_002_execute(void) {
- syssts_t sts;
- virtual_timer_t vt;
- /* [1.2.1] Testing chSysGetStatusAndLockX() and
- chSysRestoreStatusX(), non reentrant case.*/
+ /* [1.2.1] Prints the configuration options settings.*/
test_set_step(1);
{
- sts = chSysGetStatusAndLockX();
- chSysRestoreStatusX(sts);
- }
-
- /* [1.2.2] Testing chSysGetStatusAndLockX() and
- chSysRestoreStatusX(), reentrant case.*/
- test_set_step(2);
- {
- chSysLock();
- sts = chSysGetStatusAndLockX();
- chSysRestoreStatusX(sts);
- chSysUnlock();
- }
-
- /* [1.2.3] Testing chSysUnconditionalLock().*/
- test_set_step(3);
- {
- chSysUnconditionalLock();
- chSysUnconditionalLock();
- chSysUnlock();
- }
-
- /* [1.2.4] Testing chSysUnconditionalUnlock().*/
- test_set_step(4);
- {
- chSysLock();
- chSysUnconditionalUnlock();
- chSysUnconditionalUnlock();
- }
-
- /* [1.2.5] Testing from ISR context using a virtual timer.*/
- test_set_step(5);
- {
- chVTObjectInit(&vt);
- chVTSet(&vt, 1, vtcb, NULL);
- chThdSleep(10);
-
- test_assert(chVTIsArmed(&vt) == false, "timer still armed");
+ test_print("*** CH_CFG_ST_RESOLUTION: ");
+ test_printn(CH_CFG_ST_RESOLUTION);
+ test_println("");
+ test_print("*** CH_CFG_ST_FREQUENCY: ");
+ test_printn(CH_CFG_ST_FREQUENCY);
+ test_println("");
+ test_print("*** CH_CFG_ST_TIMEDELTA: ");
+ test_printn(CH_CFG_ST_TIMEDELTA);
+ test_println("");
+ test_print("*** CH_CFG_TIME_QUANTUM: ");
+ test_printn(CH_CFG_TIME_QUANTUM);
+ test_println("");
+ test_print("*** CH_CFG_MEMCORE_SIZE: ");
+ test_printn(CH_CFG_MEMCORE_SIZE);
+ test_println("");
+ test_print("*** CH_CFG_NO_IDLE_THREAD: ");
+ test_printn(CH_CFG_NO_IDLE_THREAD);
+ test_println("");
+ test_print("*** CH_CFG_OPTIMIZE_SPEED: ");
+ test_printn(CH_CFG_OPTIMIZE_SPEED);
+ test_println("");
+ test_print("*** CH_CFG_USE_TM: ");
+ test_printn(CH_CFG_USE_TM);
+ test_println("");
+ test_print("*** CH_CFG_USE_REGISTRY: ");
+ test_printn(CH_CFG_USE_REGISTRY);
+ test_println("");
+ test_print("*** CH_CFG_USE_WAITEXIT: ");
+ test_printn(CH_CFG_USE_WAITEXIT);
+ test_println("");
+ test_print("*** CH_CFG_USE_SEMAPHORES: ");
+ test_printn(CH_CFG_USE_SEMAPHORES);
+ test_println("");
+ test_print("*** CH_CFG_USE_SEMAPHORES_PRI: ");
+ test_printn(CH_CFG_USE_SEMAPHORES_PRIORITY);
+ test_println("");
+ test_print("*** CH_CFG_USE_MUTEXES: ");
+ test_printn(CH_CFG_USE_MUTEXES);
+ test_println("");
+ test_print("*** CH_CFG_USE_MUTEXES_RECURS: ");
+ test_printn(CH_CFG_USE_MUTEXES_RECURSIVE);
+ test_println("");
+ test_print("*** CH_CFG_USE_CONDVARS: ");
+ test_printn(CH_CFG_USE_CONDVARS);
+ test_println("");
+ test_print("*** CH_CFG_USE_CONDVARS_TIMEO: ");
+ test_printn(CH_CFG_USE_CONDVARS_TIMEOUT);
+ test_println("");
+ test_print("*** CH_CFG_USE_EVENTS: ");
+ test_printn(CH_CFG_USE_EVENTS);
+ test_println("");
+ test_print("*** CH_CFG_USE_EVENTS_TIMEOUT: ");
+ test_printn(CH_CFG_USE_EVENTS_TIMEOUT);
+ test_println("");
+ test_print("*** CH_CFG_USE_MESSAGES: ");
+ test_printn(CH_CFG_USE_MESSAGES);
+ test_println("");
+ test_print("*** CH_CFG_USE_MESSAGES_PRI: ");
+ test_printn(CH_CFG_USE_MESSAGES_PRIORITY);
+ test_println("");
+ test_print("*** CH_CFG_USE_MAILBOXES: ");
+ test_printn(CH_CFG_USE_MAILBOXES);
+ test_println("");
+ test_print("*** CH_CFG_USE_MEMCORE: ");
+ test_printn(CH_CFG_USE_MEMCORE);
+ test_println("");
+ test_print("*** CH_CFG_USE_HEAP: ");
+ test_printn(CH_CFG_USE_HEAP);
+ test_println("");
+ test_print("*** CH_CFG_USE_MEMPOOLS: ");
+ test_printn(CH_CFG_USE_MEMPOOLS);
+ test_println("");
+ test_print("*** CH_CFG_USE_DYNAMIC: ");
+ test_printn(CH_CFG_USE_DYNAMIC);
+ test_println("");
+ test_print("*** CH_DBG_STATISTICS: ");
+ test_printn(CH_DBG_STATISTICS);
+ test_println("");
+ test_print("*** CH_DBG_SYSTEM_STATE_CHECK: ");
+ test_printn(CH_DBG_SYSTEM_STATE_CHECK);
+ test_println("");
+ test_print("*** CH_DBG_ENABLE_CHECKS: ");
+ test_printn(CH_DBG_ENABLE_CHECKS);
+ test_println("");
+ test_print("*** CH_DBG_ENABLE_ASSERTS: ");
+ test_printn(CH_DBG_ENABLE_ASSERTS);
+ test_println("");
+ test_print("*** CH_DBG_TRACE_MASK: ");
+ test_printn(CH_DBG_TRACE_MASK);
+ test_println("");
+ test_print("*** CH_DBG_TRACE_BUFFER_SIZE: ");
+ test_printn(CH_DBG_TRACE_BUFFER_SIZE);
+ test_println("");
+ test_print("*** CH_DBG_ENABLE_STACK_CHECK: ");
+ test_printn(CH_DBG_ENABLE_STACK_CHECK);
+ test_println("");
+ test_print("*** CH_DBG_FILL_THREADS: ");
+ test_printn(CH_DBG_FILL_THREADS);
+ test_println("");
+ test_print("*** CH_DBG_THREADS_PROFILING: ");
+ test_printn(CH_DBG_THREADS_PROFILING);
+ test_println("");
}
}
static const testcase_t test_001_002 = {
- "Critical zones functionality",
+ "Kernel Settings",
NULL,
NULL,
test_001_002_execute
};
-/**
- * @page test_001_003 [1.3] Interrupts handling functionality
- *
- * <h2>Description</h2>
- * The interrupts handling API is invoked for coverage.
- *
- * <h2>Test Steps</h2>
- * - [1.3.1] Testing chSysSuspend(), chSysDisable() and chSysEnable().
- * .
- */
-
-static void test_001_003_execute(void) {
-
- /* [1.3.1] Testing chSysSuspend(), chSysDisable() and
- chSysEnable().*/
- test_set_step(1);
- {
- chSysSuspend();
- chSysDisable();
- chSysSuspend();
- chSysEnable();
- }
-}
-
-static const testcase_t test_001_003 = {
- "Interrupts handling functionality",
- NULL,
- NULL,
- test_001_003_execute
-};
-
-/**
- * @page test_001_004 [1.4] System Tick Counter functionality
- *
- * <h2>Description</h2>
- * The functionality of the API @p chVTGetSystemTimeX() is tested.
- *
- * <h2>Test Steps</h2>
- * - [1.4.1] A System Tick Counter increment is expected, the test
- * simply hangs if it does not happen.
- * .
- */
-
-static void test_001_004_execute(void) {
-
- /* [1.4.1] A System Tick Counter increment is expected, the test
- simply hangs if it does not happen.*/
- test_set_step(1);
- {
- systime_t time = chVTGetSystemTimeX();
- while (time == chVTGetSystemTimeX()) {
-#if defined(SIMULATOR)
- _sim_check_for_interrupts();
-#endif
- }
- }
-}
-
-static const testcase_t test_001_004 = {
- "System Tick Counter functionality",
- NULL,
- NULL,
- test_001_004_execute
-};
-
/****************************************************************************
* Exported data.
****************************************************************************/
/**
- * @brief System layer and port interface.
+ * @brief Information.
*/
const testcase_t * const test_sequence_001[] = {
&test_001_001,
&test_001_002,
- &test_001_003,
- &test_001_004,
NULL
};
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
*
* <h2>Description</h2>
- * This sequence tests the ChibiOS/RT functionalities related to
- * threading.
+ * The functionality of the system layer and port interface is tested.
+ * Basic RT functionality is taken for granted or this test suite could
+ * not even be executed. Errors in implementation are detected by
+ * executing this sequence with the state checker enabled
+ * (CH_DBG_STATE_CHECKER=TRUE).
*
* <h2>Test Cases</h2>
* - @subpage test_002_001
@@ -42,9 +45,21 @@
* Shared code.
****************************************************************************/
-static THD_FUNCTION(thread, p) {
+/* Timer callback for testing system functions in ISR context.*/
+static void vtcb(void *p) {
+ syssts_t sts;
- test_emit_token(*(char *)p);
+ (void)p;
+
+ /* Testing normal case.*/
+ chSysLockFromISR();
+ chSysUnlockFromISR();
+
+ /* Reentrant case.*/
+ chSysLockFromISR();
+ sts = chSysGetStatusAndLockX();
+ chSysRestoreStatusX(sts);
+ chSysUnlockFromISR();
}
/****************************************************************************
@@ -52,293 +67,216 @@ static THD_FUNCTION(thread, p) {
****************************************************************************/
/**
- * @page test_002_001 [2.1] Thread Sleep functionality
+ * @page test_002_001 [2.1] System integrity functionality
*
* <h2>Description</h2>
- * The functionality of @p chThdSleep() and derivatives is tested.
+ * The system self-test functionality is invoked in order to make an
+ * initial system state assessment and for coverage.
*
* <h2>Test Steps</h2>
- * - [2.1.1] The current system time is read then a sleep is performed
- * for 100 system ticks and on exit the system time is verified
- * again.
- * - [2.1.2] The current system time is read then a sleep is performed
- * for 100000 microseconds and on exit the system time is verified
- * again.
- * - [2.1.3] The current system time is read then a sleep is performed
- * for 100 milliseconds and on exit the system time is verified
- * again.
- * - [2.1.4] The current system time is read then a sleep is performed
- * for 1 second and on exit the system time is verified again.
- * - [2.1.5] Function chThdSleepUntil() is tested with a timeline of
- * "now" + 100 ticks.
+ * - [2.1.1] Testing Ready List integrity.
+ * - [2.1.2] Testing Virtual Timers List integrity.
+ * - [2.1.3] Testing Registry List integrity.
+ * - [2.1.4] Testing Port-defined integrity.
* .
*/
static void test_002_001_execute(void) {
- systime_t time;
+ bool result;
- /* [2.1.1] The current system time is read then a sleep is performed
- for 100 system ticks and on exit the system time is verified
- again.*/
+ /* [2.1.1] Testing Ready List integrity.*/
test_set_step(1);
{
- time = chVTGetSystemTimeX();
- chThdSleep(100);
- test_assert_time_window(time + 100,
- time + 100 + CH_CFG_ST_TIMEDELTA + 1,
- "out of time window");
+ chSysLock();
+ result = chSysIntegrityCheckI(CH_INTEGRITY_RLIST);
+ chSysUnlock();
+ test_assert(result == false, "ready list check failed");
}
- /* [2.1.2] The current system time is read then a sleep is performed
- for 100000 microseconds and on exit the system time is verified
- again.*/
+ /* [2.1.2] Testing Virtual Timers List integrity.*/
test_set_step(2);
{
- time = chVTGetSystemTimeX();
- chThdSleepMicroseconds(100000);
- test_assert_time_window(time + US2ST(100000),
- time + US2ST(100000) + CH_CFG_ST_TIMEDELTA + 1,
- "out of time window");
+ chSysLock();
+ result = chSysIntegrityCheckI(CH_INTEGRITY_VTLIST);
+ chSysUnlock();
+ test_assert(result == false, "virtual timers list check failed");
}
- /* [2.1.3] The current system time is read then a sleep is performed
- for 100 milliseconds and on exit the system time is verified
- again.*/
+ /* [2.1.3] Testing Registry List integrity.*/
test_set_step(3);
{
- time = chVTGetSystemTimeX();
- chThdSleepMilliseconds(100);
- test_assert_time_window(time + MS2ST(100),
- time + MS2ST(100) + CH_CFG_ST_TIMEDELTA + 1,
- "out of time window");
+ chSysLock();
+ result = chSysIntegrityCheckI(CH_INTEGRITY_REGISTRY);
+ chSysUnlock();
+ test_assert(result == false, "registry list check failed");
}
- /* [2.1.4] The current system time is read then a sleep is performed
- for 1 second and on exit the system time is verified again.*/
+ /* [2.1.4] Testing Port-defined integrity.*/
test_set_step(4);
{
- time = chVTGetSystemTimeX();
- chThdSleepSeconds(1);
- test_assert_time_window(time + S2ST(1),
- time + S2ST(1) + CH_CFG_ST_TIMEDELTA + 1,
- "out of time window");
- }
-
- /* [2.1.5] Function chThdSleepUntil() is tested with a timeline of
- "now" + 100 ticks.*/
- test_set_step(5);
- {
- time = chVTGetSystemTimeX();
- chThdSleepUntil(time + 100);
- test_assert_time_window(time + 100,
- time + 100 + CH_CFG_ST_TIMEDELTA + 1,
- "out of time window");
+ chSysLock();
+ result = chSysIntegrityCheckI(CH_INTEGRITY_PORT);
+ chSysUnlock();
+ test_assert(result == false, "port layer check failed");
}
}
static const testcase_t test_002_001 = {
- "Thread Sleep functionality",
+ "System integrity functionality",
NULL,
NULL,
test_002_001_execute
};
/**
- * @page test_002_002 [2.2] Ready List functionality, threads priority order
+ * @page test_002_002 [2.2] Critical zones functionality
*
* <h2>Description</h2>
- * Five threads, are enqueued in the ready list and atomically
- * executed. The test expects the threads to perform their operations
- * in correct priority order regardless of the initial order.
+ * The critical zones API is invoked for coverage.
*
* <h2>Test Steps</h2>
- * - [2.2.1] Creating 5 threads with increasing priority, execution
- * sequence is tested.
- * - [2.2.2] Creating 5 threads with decreasing priority, execution
- * sequence is tested.
- * - [2.2.3] Creating 5 threads with pseudo-random priority, execution
- * sequence is tested.
+ * - [2.2.1] Testing chSysGetStatusAndLockX() and
+ * chSysRestoreStatusX(), non reentrant case.
+ * - [2.2.2] Testing chSysGetStatusAndLockX() and
+ * chSysRestoreStatusX(), reentrant case.
+ * - [2.2.3] Testing chSysUnconditionalLock().
+ * - [2.2.4] Testing chSysUnconditionalUnlock().
+ * - [2.2.5] Testing from ISR context using a virtual timer.
* .
*/
static void test_002_002_execute(void) {
+ syssts_t sts;
+ virtual_timer_t vt;
- /* [2.2.1] Creating 5 threads with increasing priority, execution
- sequence is tested.*/
+ /* [2.2.1] Testing chSysGetStatusAndLockX() and
+ chSysRestoreStatusX(), non reentrant case.*/
test_set_step(1);
{
- threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
- threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
- threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
- threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
- threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
- test_wait_threads();
- test_assert_sequence("ABCDE", "invalid sequence");
+ sts = chSysGetStatusAndLockX();
+ chSysRestoreStatusX(sts);
}
- /* [2.2.2] Creating 5 threads with decreasing priority, execution
- sequence is tested.*/
+ /* [2.2.2] Testing chSysGetStatusAndLockX() and
+ chSysRestoreStatusX(), reentrant case.*/
test_set_step(2);
{
- threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
- threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
- threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
- threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
- threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
- test_wait_threads();
- test_assert_sequence("ABCDE", "invalid sequence");
+ chSysLock();
+ sts = chSysGetStatusAndLockX();
+ chSysRestoreStatusX(sts);
+ chSysUnlock();
}
- /* [2.2.3] Creating 5 threads with pseudo-random priority, execution
- sequence is tested.*/
+ /* [2.2.3] Testing chSysUnconditionalLock().*/
test_set_step(3);
{
- threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
- threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
- threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
- threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
- threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
- test_wait_threads();
- test_assert_sequence("ABCDE", "invalid sequence");
+ chSysUnconditionalLock();
+ chSysUnconditionalLock();
+ chSysUnlock();
+ }
+
+ /* [2.2.4] Testing chSysUnconditionalUnlock().*/
+ test_set_step(4);
+ {
+ chSysLock();
+ chSysUnconditionalUnlock();
+ chSysUnconditionalUnlock();
+ }
+
+ /* [2.2.5] Testing from ISR context using a virtual timer.*/
+ test_set_step(5);
+ {
+ chVTObjectInit(&vt);
+ chVTSet(&vt, 1, vtcb, NULL);
+ chThdSleep(10);
+
+ test_assert(chVTIsArmed(&vt) == false, "timer still armed");
}
}
static const testcase_t test_002_002 = {
- "Ready List functionality, threads priority order",
+ "Critical zones functionality",
NULL,
NULL,
test_002_002_execute
};
/**
- * @page test_002_003 [2.3] Priority change test
+ * @page test_002_003 [2.3] Interrupts handling functionality
*
* <h2>Description</h2>
- * A series of priority changes are performed on the current thread in
- * order to verify that the priority change happens as expected.
+ * The interrupts handling API is invoked for coverage.
*
* <h2>Test Steps</h2>
- * - [2.3.1] Thread priority is increased by one then a check is
- * performed.
- * - [2.3.2] Thread priority is returned to the previous value then a
- * check is performed.
+ * - [2.3.1] Testing chSysSuspend(), chSysDisable() and chSysEnable().
* .
*/
static void test_002_003_execute(void) {
- tprio_t prio, p1;
- /* [2.3.1] Thread priority is increased by one then a check is
- performed.*/
+ /* [2.3.1] Testing chSysSuspend(), chSysDisable() and
+ chSysEnable().*/
test_set_step(1);
{
- prio = chThdGetPriorityX();
- p1 = chThdSetPriority(prio + 1);
- test_assert(p1 == prio, "unexpected returned priority level");
- test_assert(chThdGetPriorityX() == prio + 1, "unexpected priority level");
- }
-
- /* [2.3.2] Thread priority is returned to the previous value then a
- check is performed.*/
- test_set_step(2);
- {
- p1 = chThdSetPriority(p1);
- test_assert(p1 == prio + 1, "unexpected returned priority level");
- test_assert(chThdGetPriorityX() == prio, "unexpected priority level");
+ chSysSuspend();
+ chSysDisable();
+ chSysSuspend();
+ chSysEnable();
}
}
static const testcase_t test_002_003 = {
- "Priority change test",
+ "Interrupts handling functionality",
NULL,
NULL,
test_002_003_execute
};
-#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
/**
- * @page test_002_004 [2.4] Priority change test with Priority Inheritance
+ * @page test_002_004 [2.4] System Tick Counter functionality
*
* <h2>Description</h2>
- * A series of priority changes are performed on the current thread in
- * order to verify that the priority change happens as expected.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_MUTEXES
- * .
+ * The functionality of the API @p chVTGetSystemTimeX() is tested.
*
* <h2>Test Steps</h2>
- * - [2.4.1] Simulating a priority boost situation (prio > realprio).
- * - [2.4.2] Raising thread priority above original priority but below
- * the boosted level.
- * - [2.4.3] Raising thread priority above the boosted level.
- * - [2.4.4] Restoring original conditions.
+ * - [2.4.1] A System Tick Counter increment is expected, the test
+ * simply hangs if it does not happen.
* .
*/
static void test_002_004_execute(void) {
- tprio_t prio, p1;
- /* [2.4.1] Simulating a priority boost situation (prio > realprio).*/
+ /* [2.4.1] A System Tick Counter increment is expected, the test
+ simply hangs if it does not happen.*/
test_set_step(1);
{
- prio = chThdGetPriorityX();
- chThdGetSelfX()->prio += 2;
- test_assert(chThdGetPriorityX() == prio + 2, "unexpected priority level");
- }
-
- /* [2.4.2] Raising thread priority above original priority but below
- the boosted level.*/
- test_set_step(2);
- {
- p1 = chThdSetPriority(prio + 1);
- test_assert(p1 == prio, "unexpected returned priority level");
- test_assert(chThdGetSelfX()->prio == prio + 2, "unexpected priority level");
- test_assert(chThdGetSelfX()->realprio == prio + 1, "unexpected returned real priority level");
- }
-
- /* [2.4.3] Raising thread priority above the boosted level.*/
- test_set_step(3);
- {
- p1 = chThdSetPriority(prio + 3);
- test_assert(p1 == prio + 1, "unexpected returned priority level");
- test_assert(chThdGetSelfX()->prio == prio + 3, "unexpected priority level");
- test_assert(chThdGetSelfX()->realprio == prio + 3, "unexpected real priority level");
- }
-
- /* [2.4.4] Restoring original conditions.*/
- test_set_step(4);
- {
- chSysLock();
- chThdGetSelfX()->prio = prio;
- chThdGetSelfX()->realprio = prio;
- chSysUnlock();
+ systime_t time = chVTGetSystemTimeX();
+ while (time == chVTGetSystemTimeX()) {
+#if defined(SIMULATOR)
+ _sim_check_for_interrupts();
+#endif
+ }
}
}
static const testcase_t test_002_004 = {
- "Priority change test with Priority Inheritance",
+ "System Tick Counter functionality",
NULL,
NULL,
test_002_004_execute
};
-#endif /* CH_CFG_USE_MUTEXES */
/****************************************************************************
* Exported data.
****************************************************************************/
/**
- * @brief Threads Functionality.
+ * @brief System layer and port interface.
*/
const testcase_t * const test_sequence_002[] = {
&test_002_001,
&test_002_002,
&test_002_003,
-#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
&test_002_004,
-#endif
NULL
};
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
*
* <h2>Description</h2>
* This sequence tests the ChibiOS/RT functionalities related to
- * threads suspend/resume.
+ * threading.
*
* <h2>Test Cases</h2>
* - @subpage test_003_001
+ * - @subpage test_003_002
+ * - @subpage test_003_003
+ * - @subpage test_003_004
* .
*/
@@ -39,14 +42,8 @@
* Shared code.
****************************************************************************/
-static thread_reference_t tr1;
+static THD_FUNCTION(thread, p) {
-static THD_FUNCTION(thread1, p) {
-
- chSysLock();
- chThdResumeI(&tr1, MSG_OK);
- chSchRescheduleS();
- chSysUnlock();
test_emit_token(*(char *)p);
}
@@ -55,76 +52,293 @@ static THD_FUNCTION(thread1, p) {
****************************************************************************/
/**
- * @page test_003_001 [3.1] Suspend and Resume functionality
+ * @page test_003_001 [3.1] Thread Sleep functionality
*
* <h2>Description</h2>
- * The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
- * tested.
+ * The functionality of @p chThdSleep() and derivatives is tested.
*
* <h2>Test Steps</h2>
- * - [3.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
- * is remotely resumed with message @p MSG_OK. On return the message
- * and the state of the reference are tested.
- * - [3.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
- * is not resumed so a timeout must occur. On return the message and
- * the state of the reference are tested.
+ * - [3.1.1] The current system time is read then a sleep is performed
+ * for 100 system ticks and on exit the system time is verified
+ * again.
+ * - [3.1.2] The current system time is read then a sleep is performed
+ * for 100000 microseconds and on exit the system time is verified
+ * again.
+ * - [3.1.3] The current system time is read then a sleep is performed
+ * for 100 milliseconds and on exit the system time is verified
+ * again.
+ * - [3.1.4] The current system time is read then a sleep is performed
+ * for 1 second and on exit the system time is verified again.
+ * - [3.1.5] Function chThdSleepUntil() is tested with a timeline of
+ * "now" + 100 ticks.
* .
*/
-static void test_003_001_setup(void) {
- tr1 = NULL;
-}
-
static void test_003_001_execute(void) {
systime_t time;
- msg_t msg;
- /* [3.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
- is remotely resumed with message @p MSG_OK. On return the message
- and the state of the reference are tested.*/
+ /* [3.1.1] The current system time is read then a sleep is performed
+ for 100 system ticks and on exit the system time is verified
+ again.*/
test_set_step(1);
{
- threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread1, "A");
- chSysLock();
- msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE);
- chSysUnlock();
- test_assert(NULL == tr1, "not NULL");
- test_assert(MSG_OK == msg,"wrong returned message");
- test_wait_threads();
+ time = chVTGetSystemTimeX();
+ chThdSleep(100);
+ test_assert_time_window(time + 100,
+ time + 100 + CH_CFG_ST_TIMEDELTA + 1,
+ "out of time window");
}
- /* [3.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
- is not resumed so a timeout must occur. On return the message and
- the state of the reference are tested.*/
+ /* [3.1.2] The current system time is read then a sleep is performed
+ for 100000 microseconds and on exit the system time is verified
+ again.*/
test_set_step(2);
{
- chSysLock();
time = chVTGetSystemTimeX();
- msg = chThdSuspendTimeoutS(&tr1, MS2ST(1000));
- chSysUnlock();
- test_assert_time_window(time + MS2ST(1000),
- time + MS2ST(1000) + CH_CFG_ST_TIMEDELTA + 1,
+ chThdSleepMicroseconds(100000);
+ test_assert_time_window(time + US2ST(100000),
+ time + US2ST(100000) + CH_CFG_ST_TIMEDELTA + 1,
+ "out of time window");
+ }
+
+ /* [3.1.3] The current system time is read then a sleep is performed
+ for 100 milliseconds and on exit the system time is verified
+ again.*/
+ test_set_step(3);
+ {
+ time = chVTGetSystemTimeX();
+ chThdSleepMilliseconds(100);
+ test_assert_time_window(time + MS2ST(100),
+ time + MS2ST(100) + CH_CFG_ST_TIMEDELTA + 1,
+ "out of time window");
+ }
+
+ /* [3.1.4] The current system time is read then a sleep is performed
+ for 1 second and on exit the system time is verified again.*/
+ test_set_step(4);
+ {
+ time = chVTGetSystemTimeX();
+ chThdSleepSeconds(1);
+ test_assert_time_window(time + S2ST(1),
+ time + S2ST(1) + CH_CFG_ST_TIMEDELTA + 1,
+ "out of time window");
+ }
+
+ /* [3.1.5] Function chThdSleepUntil() is tested with a timeline of
+ "now" + 100 ticks.*/
+ test_set_step(5);
+ {
+ time = chVTGetSystemTimeX();
+ chThdSleepUntil(time + 100);
+ test_assert_time_window(time + 100,
+ time + 100 + CH_CFG_ST_TIMEDELTA + 1,
"out of time window");
- test_assert(NULL == tr1, "not NULL");
- test_assert(MSG_TIMEOUT == msg, "wrong returned message");
}
}
static const testcase_t test_003_001 = {
- "Suspend and Resume functionality",
- test_003_001_setup,
+ "Thread Sleep functionality",
+ NULL,
NULL,
test_003_001_execute
};
+/**
+ * @page test_003_002 [3.2] Ready List functionality, threads priority order
+ *
+ * <h2>Description</h2>
+ * Five threads, are enqueued in the ready list and atomically
+ * executed. The test expects the threads to perform their operations
+ * in correct priority order regardless of the initial order.
+ *
+ * <h2>Test Steps</h2>
+ * - [3.2.1] Creating 5 threads with increasing priority, execution
+ * sequence is tested.
+ * - [3.2.2] Creating 5 threads with decreasing priority, execution
+ * sequence is tested.
+ * - [3.2.3] Creating 5 threads with pseudo-random priority, execution
+ * sequence is tested.
+ * .
+ */
+
+static void test_003_002_execute(void) {
+
+ /* [3.2.1] Creating 5 threads with increasing priority, execution
+ sequence is tested.*/
+ test_set_step(1);
+ {
+ threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
+ threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
+ threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
+ threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
+ threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
+ test_wait_threads();
+ test_assert_sequence("ABCDE", "invalid sequence");
+ }
+
+ /* [3.2.2] Creating 5 threads with decreasing priority, execution
+ sequence is tested.*/
+ test_set_step(2);
+ {
+ threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
+ threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
+ threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
+ threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
+ threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
+ test_wait_threads();
+ test_assert_sequence("ABCDE", "invalid sequence");
+ }
+
+ /* [3.2.3] Creating 5 threads with pseudo-random priority, execution
+ sequence is tested.*/
+ test_set_step(3);
+ {
+ threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
+ threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
+ threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
+ threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
+ threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
+ test_wait_threads();
+ test_assert_sequence("ABCDE", "invalid sequence");
+ }
+}
+
+static const testcase_t test_003_002 = {
+ "Ready List functionality, threads priority order",
+ NULL,
+ NULL,
+ test_003_002_execute
+};
+
+/**
+ * @page test_003_003 [3.3] Priority change test
+ *
+ * <h2>Description</h2>
+ * A series of priority changes are performed on the current thread in
+ * order to verify that the priority change happens as expected.
+ *
+ * <h2>Test Steps</h2>
+ * - [3.3.1] Thread priority is increased by one then a check is
+ * performed.
+ * - [3.3.2] Thread priority is returned to the previous value then a
+ * check is performed.
+ * .
+ */
+
+static void test_003_003_execute(void) {
+ tprio_t prio, p1;
+
+ /* [3.3.1] Thread priority is increased by one then a check is
+ performed.*/
+ test_set_step(1);
+ {
+ prio = chThdGetPriorityX();
+ p1 = chThdSetPriority(prio + 1);
+ test_assert(p1 == prio, "unexpected returned priority level");
+ test_assert(chThdGetPriorityX() == prio + 1, "unexpected priority level");
+ }
+
+ /* [3.3.2] Thread priority is returned to the previous value then a
+ check is performed.*/
+ test_set_step(2);
+ {
+ p1 = chThdSetPriority(p1);
+ test_assert(p1 == prio + 1, "unexpected returned priority level");
+ test_assert(chThdGetPriorityX() == prio, "unexpected priority level");
+ }
+}
+
+static const testcase_t test_003_003 = {
+ "Priority change test",
+ NULL,
+ NULL,
+ test_003_003_execute
+};
+
+#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
+/**
+ * @page test_003_004 [3.4] Priority change test with Priority Inheritance
+ *
+ * <h2>Description</h2>
+ * A series of priority changes are performed on the current thread in
+ * order to verify that the priority change happens as expected.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_MUTEXES
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [3.4.1] Simulating a priority boost situation (prio > realprio).
+ * - [3.4.2] Raising thread priority above original priority but below
+ * the boosted level.
+ * - [3.4.3] Raising thread priority above the boosted level.
+ * - [3.4.4] Restoring original conditions.
+ * .
+ */
+
+static void test_003_004_execute(void) {
+ tprio_t prio, p1;
+
+ /* [3.4.1] Simulating a priority boost situation (prio > realprio).*/
+ test_set_step(1);
+ {
+ prio = chThdGetPriorityX();
+ chThdGetSelfX()->prio += 2;
+ test_assert(chThdGetPriorityX() == prio + 2, "unexpected priority level");
+ }
+
+ /* [3.4.2] Raising thread priority above original priority but below
+ the boosted level.*/
+ test_set_step(2);
+ {
+ p1 = chThdSetPriority(prio + 1);
+ test_assert(p1 == prio, "unexpected returned priority level");
+ test_assert(chThdGetSelfX()->prio == prio + 2, "unexpected priority level");
+ test_assert(chThdGetSelfX()->realprio == prio + 1, "unexpected returned real priority level");
+ }
+
+ /* [3.4.3] Raising thread priority above the boosted level.*/
+ test_set_step(3);
+ {
+ p1 = chThdSetPriority(prio + 3);
+ test_assert(p1 == prio + 1, "unexpected returned priority level");
+ test_assert(chThdGetSelfX()->prio == prio + 3, "unexpected priority level");
+ test_assert(chThdGetSelfX()->realprio == prio + 3, "unexpected real priority level");
+ }
+
+ /* [3.4.4] Restoring original conditions.*/
+ test_set_step(4);
+ {
+ chSysLock();
+ chThdGetSelfX()->prio = prio;
+ chThdGetSelfX()->realprio = prio;
+ chSysUnlock();
+ }
+}
+
+static const testcase_t test_003_004 = {
+ "Priority change test with Priority Inheritance",
+ NULL,
+ NULL,
+ test_003_004_execute
+};
+#endif /* CH_CFG_USE_MUTEXES */
+
/****************************************************************************
* Exported data.
****************************************************************************/
/**
- * @brief Suspend/Resume.
+ * @brief Threads Functionality.
*/
const testcase_t * const test_sequence_003[] = {
&test_003_001,
+ &test_003_002,
+ &test_003_003,
+#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
+ &test_003_004,
+#endif
NULL
};
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
*
* <h2>Description</h2>
* This sequence tests the ChibiOS/RT functionalities related to
- * counter semaphores.
- *
- * <h2>Conditions</h2>
- * This sequence is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_SEMAPHORES
- * .
+ * threads suspend/resume.
*
* <h2>Test Cases</h2>
* - @subpage test_004_001
- * - @subpage test_004_002
- * - @subpage test_004_003
- * - @subpage test_004_004
- * - @subpage test_004_005
- * - @subpage test_004_006
* .
*/
-#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
-
/****************************************************************************
* Shared code.
****************************************************************************/
-#include "ch.h"
-
-static semaphore_t sem1;
+static thread_reference_t tr1;
static THD_FUNCTION(thread1, p) {
- chSemWait(&sem1);
- test_emit_token(*(char *)p);
-}
-
-static THD_FUNCTION(thread2, p) {
-
- (void)p;
- chThdSleepMilliseconds(50);
chSysLock();
- chSemSignalI(&sem1); /* For coverage reasons */
+ chThdResumeI(&tr1, MSG_OK);
chSchRescheduleS();
chSysUnlock();
-}
-
-static THD_FUNCTION(thread3, p) {
-
- (void)p;
- chSemWait(&sem1);
- chSemSignal(&sem1);
-}
-
-static THD_FUNCTION(thread4, p) {
-
- chBSemSignal((binary_semaphore_t *)p);
+ test_emit_token(*(char *)p);
}
/****************************************************************************
@@ -89,403 +55,66 @@ static THD_FUNCTION(thread4, p) {
****************************************************************************/
/**
- * @page test_004_001 [4.1] Semaphore primitives, no state change
+ * @page test_004_001 [4.1] Suspend and Resume functionality
*
* <h2>Description</h2>
- * Wait, Signal and Reset primitives are tested. The testing thread
- * does not trigger a state change.
+ * The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
+ * tested.
*
* <h2>Test Steps</h2>
- * - [4.1.1] The function chSemWait() is invoked, after return the
- * counter and the returned message are tested.
- * - [4.1.2] The function chSemSignal() is invoked, after return the
- * counter is tested.
- * - [4.1.3] The function chSemReset() is invoked, after return the
- * counter is tested.
+ * - [4.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
+ * is remotely resumed with message @p MSG_OK. On return the message
+ * and the state of the reference are tested.
+ * - [4.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
+ * is not resumed so a timeout must occur. On return the message and
+ * the state of the reference are tested.
* .
*/
static void test_004_001_setup(void) {
- chSemObjectInit(&sem1, 1);
-}
-
-static void test_004_001_teardown(void) {
- chSemReset(&sem1, 0);
+ tr1 = NULL;
}
static void test_004_001_execute(void) {
-
- /* [4.1.1] The function chSemWait() is invoked, after return the
- counter and the returned message 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");
- }
-
- /* [4.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");
- }
-
- /* [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");
- }
-}
-
-static const testcase_t test_004_001 = {
- "Semaphore primitives, no state change",
- test_004_001_setup,
- test_004_001_teardown,
- test_004_001_execute
-};
-
-/**
- * @page test_004_002 [4.2] Semaphore enqueuing test
- *
- * <h2>Description</h2>
- * Five threads with randomized priorities are enqueued to a semaphore
- * then awakened one at time. The test expects that the threads reach
- * their goal in FIFO order or priority order depending on the @p
- * CH_CFG_USE_SEMAPHORES_PRIORITY configuration setting.
- *
- * <h2>Test Steps</h2>
- * - [4.2.1] Five threads are created with mixed priority levels (not
- * increasing nor decreasing). Threads enqueue on a semaphore
- * initialized to zero.
- * - [4.2.2] The semaphore is signaled 5 times. The thread activation
- * sequence is tested.
- * .
- */
-
-static void test_004_002_setup(void) {
- chSemObjectInit(&sem1, 0);
-}
-
-static void test_004_002_execute(void) {
-
- /* [4.2.1] Five threads are created with mixed priority levels (not
- increasing nor decreasing). Threads enqueue on a semaphore
- initialized to zero.*/
- test_set_step(1);
- {
- threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, thread1, "A");
- threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+1, thread1, "B");
- threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, thread1, "C");
- threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+4, thread1, "D");
- threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+2, thread1, "E");
- }
-
- /* [4.2.2] The semaphore is signaled 5 times. The thread activation
- sequence is tested.*/
- test_set_step(2);
- {
- chSemSignal(&sem1);
- chSemSignal(&sem1);
- chSemSignal(&sem1);
- chSemSignal(&sem1);
- chSemSignal(&sem1);
- test_wait_threads();
-#if CH_CFG_USE_SEMAPHORES_PRIORITY
- test_assert_sequence("ADCEB", "invalid sequence");
-#else
- test_assert_sequence("ABCDE", "invalid sequence");
-#endif
- }
-}
-
-static const testcase_t test_004_002 = {
- "Semaphore enqueuing test",
- test_004_002_setup,
- NULL,
- test_004_002_execute
-};
-
-/**
- * @page test_004_003 [4.3] Semaphore timeout test
- *
- * <h2>Description</h2>
- * The three possible semaphore waiting modes (do not wait, wait with
- * timeout, wait without timeout) are explored. The test expects that
- * the semaphore wait function returns the correct value in each of the
- * above scenario and that the semaphore structure status is correct
- * after each operation.
- *
- * <h2>Test Steps</h2>
- * - [4.3.1] Testing special case TIME_IMMEDIATE.
- * - [4.3.2] Testing non-timeout condition.
- * - [4.3.3] Testing timeout condition.
- * .
- */
-
-static void test_004_003_setup(void) {
- chSemObjectInit(&sem1, 0);
-}
-
-static void test_004_003_execute(void) {
- unsigned i;
- systime_t target_time;
+ systime_t time;
msg_t msg;
- /* [4.3.1] Testing special case TIME_IMMEDIATE.*/
- test_set_step(1);
- {
- msg = chSemWaitTimeout(&sem1, TIME_IMMEDIATE);
- test_assert(msg == MSG_TIMEOUT, "wrong wake-up message");
- test_assert(queue_isempty(&sem1.queue), "queue not empty");
- test_assert(sem1.cnt == 0, "counter not zero");
- }
-
- /* [4.3.2] Testing non-timeout condition.*/
- test_set_step(2);
- {
- threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
- thread2, 0);
- msg = chSemWaitTimeout(&sem1, MS2ST(500));
- test_wait_threads();
- test_assert(msg == MSG_OK, "wrong wake-up message");
- test_assert(queue_isempty(&sem1.queue), "queue not empty");
- test_assert(sem1.cnt == 0, "counter not zero");
- }
-
- /* [4.3.3] Testing timeout condition.*/
- test_set_step(3);
- {
- target_time = test_wait_tick() + MS2ST(5 * 50);
- for (i = 0; i < 5; i++) {
- test_emit_token('A' + i);
- msg = chSemWaitTimeout(&sem1, MS2ST(50));
- test_assert(msg == MSG_TIMEOUT, "wrong wake-up message");
- test_assert(queue_isempty(&sem1.queue), "queue not empty");
- test_assert(sem1.cnt == 0, "counter not zero");
- }
- test_assert_sequence("ABCDE", "invalid sequence");
- test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
- "out of time window");
- }
-}
-
-static const testcase_t test_004_003 = {
- "Semaphore timeout test",
- test_004_003_setup,
- NULL,
- test_004_003_execute
-};
-
-/**
- * @page test_004_004 [4.4] Testing chSemAddCounterI() functionality
- *
- * <h2>Description</h2>
- * The functon is tested by waking up a thread then the semaphore
- * counter value is tested.
- *
- * <h2>Test Steps</h2>
- * - [4.4.1] A thread is created, it goes to wait on the semaphore.
- * - [4.4.2] The semaphore counter is increased by two, it is then
- * tested to be one, the thread must have completed.
- * .
- */
-
-static void test_004_004_setup(void) {
- chSemObjectInit(&sem1, 0);
-}
-
-static void test_004_004_execute(void) {
-
- /* [4.4.1] A thread is created, it goes to wait on the semaphore.*/
+ /* [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);
{
- 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);
- {
+ threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread1, "A");
chSysLock();
- chSemAddCounterI(&sem1, 2);
- chSchRescheduleS();
+ msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE);
chSysUnlock();
+ test_assert(NULL == tr1, "not NULL");
+ test_assert(MSG_OK == msg,"wrong returned message");
test_wait_threads();
- test_assert_lock(chSemGetCounterI(&sem1) == 1, "invalid counter");
- test_assert_sequence("A", "invalid sequence");
- }
-}
-
-static const testcase_t test_004_004 = {
- "Testing chSemAddCounterI() functionality",
- test_004_004_setup,
- NULL,
- test_004_004_execute
-};
-
-/**
- * @page test_004_005 [4.5] Testing chSemWaitSignal() functionality
- *
- * <h2>Description</h2>
- * This test case explicitly addresses the @p chSemWaitSignal()
- * function. A thread is created that performs a wait and a signal
- * operations. The tester thread is awakened from an atomic wait/signal
- * operation. The test expects that the semaphore wait function returns
- * the correct value in each of the above scenario and that the
- * semaphore structure status is correct after each operation.
- *
- * <h2>Test Steps</h2>
- * - [4.5.1] An higher priority thread is created that performs
- * non-atomical wait and signal operations on a semaphore.
- * - [4.5.2] The function chSemSignalWait() is invoked by specifying
- * the same semaphore for the wait and signal phases. The counter
- * value must be one on exit.
- * - [4.5.3] The function chSemSignalWait() is invoked again by
- * specifying the same semaphore for the wait and signal phases. The
- * counter value must be one on exit.
- * .
- */
-
-static void test_004_005_setup(void) {
- chSemObjectInit(&sem1, 0);
-}
-
-static void test_004_005_teardown(void) {
- test_wait_threads();
-}
-
-static void test_004_005_execute(void) {
-
- /* [4.5.1] An higher priority thread is created that performs
- non-atomical wait and signal operations on a semaphore.*/
- test_set_step(1);
- {
- threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread3, 0);
- }
-
- /* [4.5.2] The function chSemSignalWait() is invoked by specifying
- the same semaphore for the wait and signal phases. The counter
- value must be one on exit.*/
- test_set_step(2);
- {
- chSemSignalWait(&sem1, &sem1);
- test_assert(queue_isempty(&sem1.queue), "queue not empty");
- test_assert(sem1.cnt == 0, "counter not zero");
- }
-
- /* [4.5.3] The function chSemSignalWait() is invoked again by
- specifying the same semaphore for the wait and signal phases. The
- counter value must be one on exit.*/
- test_set_step(3);
- {
- chSemSignalWait(&sem1, &sem1);
- test_assert(queue_isempty(&sem1.queue), "queue not empty");
- test_assert(sem1.cnt == 0, "counter not zero");
- }
-}
-
-static const testcase_t test_004_005 = {
- "Testing chSemWaitSignal() functionality",
- test_004_005_setup,
- test_004_005_teardown,
- test_004_005_execute
-};
-
-/**
- * @page test_004_006 [4.6] Testing Binary Semaphores special case
- *
- * <h2>Description</h2>
- * This test case tests the binary semaphores functionality. The test
- * both checks the binary semaphore status and the expected status of
- * the underlying counting semaphore.
- *
- * <h2>Test Steps</h2>
- * - [4.6.1] Creating a binary semaphore in "taken" state, the state is
- * checked.
- * - [4.6.2] Resetting the binary semaphore in "taken" state, the state
- * must not change.
- * - [4.6.3] Starting a signaler thread at a lower priority.
- * - [4.6.4] Waiting for the binary semaphore to be signaled, the
- * semaphore is expected to be taken.
- * - [4.6.5] Signaling the binary semaphore, checking the binary
- * semaphore state to be "not taken" and the underlying counter
- * semaphore counter to be one.
- * - [4.6.6] Signaling the binary semaphore again, the internal state
- * must not change from "not taken".
- * .
- */
-
-static void test_004_006_teardown(void) {
- test_wait_threads();
-}
-
-static void test_004_006_execute(void) {
- binary_semaphore_t bsem;
- msg_t msg;
-
- /* [4.6.1] Creating a binary semaphore in "taken" state, the state is
- checked.*/
- test_set_step(1);
- {
- chBSemObjectInit(&bsem, true);
- test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken");
}
- /* [4.6.2] Resetting the binary semaphore in "taken" state, the state
- must not change.*/
+ /* [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);
{
- 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");
+ 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_006 = {
- "Testing Binary Semaphores special case",
+static const testcase_t test_004_001 = {
+ "Suspend and Resume functionality",
+ test_004_001_setup,
NULL,
- test_004_006_teardown,
- test_004_006_execute
+ test_004_001_execute
};
/****************************************************************************
@@ -493,16 +122,9 @@ static const testcase_t test_004_006 = {
****************************************************************************/
/**
- * @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
*
* <h2>Description</h2>
* This sequence tests the ChibiOS/RT functionalities related to
- * mutexes, condition variables and priority inheritance algorithm.
+ * counter semaphores.
*
* <h2>Conditions</h2>
* This sequence is only executed if the following preprocessor condition
* evaluates to true:
- * - CH_CFG_USE_MUTEXES
+ * - CH_CFG_USE_SEMAPHORES
* .
*
* <h2>Test Cases</h2>
@@ -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) {
-
- chMtxLock(&m1);
- chCondWait(&c1);
- test_emit_token(*(char *)p);
- chMtxUnlock(&m1);
-}
-
-static THD_FUNCTION(thread8, p) {
+static THD_FUNCTION(thread3, 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);
+ (void)p;
+ chSemWait(&sem1);
+ chSemSignal(&sem1);
}
-static THD_FUNCTION(thread9, p) {
+static THD_FUNCTION(thread4, p) {
- chMtxLock(&m2);
- test_emit_token(*(char *)p);
- chMtxUnlock(&m2);
+ chBSemSignal((binary_semaphore_t *)p);
}
-#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
*
* <h2>Description</h2>
- * 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.
*
* <h2>Test Steps</h2>
- * - [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
*
* <h2>Description</h2>
- * 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.
- *
- * <h2>Conditions</h2>
- * 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.
*
* <h2>Test Steps</h2>
- * - [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
*
* <h2>Description</h2>
- * 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.
- *
- * <h2>Conditions</h2>
- * 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.
*
* <h2>Test Steps</h2>
- * - [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
*
* <h2>Description</h2>
- * 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.<br> 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.
*
* <h2>Test Steps</h2>
- * - [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
*
* <h2>Description</h2>
- * The behavior of multiple mutex locks from the same thread is tested
- * when recursion is disabled.
- *
- * <h2>Conditions</h2>
- * 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.
*
* <h2>Test Steps</h2>
- * - [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
*
* <h2>Description</h2>
- * The behavior of multiple mutex locks from the same thread is tested
- * when recursion is enabled.
- *
- * <h2>Conditions</h2>
- * 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.
*
* <h2>Test Steps</h2>
- * - [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
- *
- * <h2>Description</h2>
- * 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.<br> The test expects the threads to
- * reach their goal in increasing priority order regardless of the
- * initial order.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_CONDVARS
- * .
- *
- * <h2>Test Steps</h2>
- * - [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
- *
- * <h2>Description</h2>
- * Five threads take a mutex and then enter a conditional variable
- * queue, the tester thread then proceeds to broadcast the conditional
- * variable.<br> The test expects the threads to reach their goal in
- * increasing priority order regardless of the initial order.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_CONDVARS
- * .
- *
- * <h2>Test Steps</h2>
- * - [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
- *
- * <h2>Description</h2>
- * 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)}.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_CONDVARS
- * .
- *
- * <h2>Test Steps</h2>
- * - [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
*
* <h2>Description</h2>
- * 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.
*
* <h2>Conditions</h2>
* This sequence is only executed if the following preprocessor condition
* evaluates to true:
- * - CH_CFG_USE_MESSAGES
+ * - CH_CFG_USE_MUTEXES
* .
*
* <h2>Test Cases</h2>
* - @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
*
* <h2>Description</h2>
- * A messenger thread is spawned that sends four messages back to the
- * tester thread.<br> The test expect to receive the messages in the
- * correct sequence and to not find a fifth message waiting.
+ * 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.
*
* <h2>Test Steps</h2>
- * - [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_setup(void) {
+ chMtxObjectInit(&m1);
+}
+
static void test_006_001_execute(void) {
- thread_t *tp;
- msg_t msg;
+ tprio_t prio;
- /* [6.1.1] Starting the messenger thread.*/
+ /* [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
+ *
+ * <h2>Description</h2>
+ * 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.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_DBG_THREADS_PROFILING
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * 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.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_DBG_THREADS_PROFILING
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * 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.<br> Thread A performs
+ * wait(50), lock(m1), unlock(m1), exit. Thread B performs wait(150),
+ * lock(m2), unlock(m2), exit.
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * The behavior of multiple mutex locks from the same thread is tested
+ * when recursion is disabled.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - !CH_CFG_USE_MUTEXES_RECURSIVE
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * The behavior of multiple mutex locks from the same thread is tested
+ * when recursion is enabled.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_MUTEXES_RECURSIVE
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * 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.<br> The test expects the threads to
+ * reach their goal in increasing priority order regardless of the
+ * initial order.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_CONDVARS
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * Five threads take a mutex and then enter a conditional variable
+ * queue, the tester thread then proceeds to broadcast the conditional
+ * variable.<br> The test expects the threads to reach their goal in
+ * increasing priority order regardless of the initial order.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_CONDVARS
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * 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)}.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_CONDVARS
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [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
*
* <h2>Description</h2>
- * This module implements the test sequence for the Events subsystem.
+ * This module implements the test sequence for the Synchronous
+ * Messages subsystem.
*
* <h2>Conditions</h2>
* This sequence is only executed if the following preprocessor condition
* evaluates to true:
- * - CH_CFG_USE_EVENTS
+ * - CH_CFG_USE_MESSAGES
* .
*
* <h2>Test Cases</h2>
* - @subpage test_007_001
- * - @subpage test_007_002
- * - @subpage test_007_003
- * - @subpage test_007_004
- * - @subpage test_007_005
- * - @subpage test_007_006
- * - @subpage test_007_007
* .
*/
-#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
+#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
/****************************************************************************
* Shared code.
****************************************************************************/
-static EVENTSOURCE_DECL(es1);
-static EVENTSOURCE_DECL(es2);
+static THD_FUNCTION(msg_thread1, p) {
-static void h1(eventid_t id) {(void)id;test_emit_token('A');}
-static void h2(eventid_t id) {(void)id;test_emit_token('B');}
-static void h3(eventid_t id) {(void)id;test_emit_token('C');}
-static ROMCONST evhandler_t evhndl[] = {h1, h2, h3};
-
-static THD_FUNCTION(evt_thread3, p) {
-
- chThdSleepMilliseconds(50);
- chEvtSignal((thread_t *)p, 1);
-}
-
-static THD_FUNCTION(evt_thread7, p) {
-
- (void)p;
- chEvtBroadcast(&es1);
- chThdSleepMilliseconds(50);
- chEvtBroadcast(&es2);
+ chMsgSend(p, 'A');
+ chMsgSend(p, 'B');
+ chMsgSend(p, 'C');
+ chMsgSend(p, 'D');
}
/****************************************************************************
@@ -79,491 +60,64 @@ static THD_FUNCTION(evt_thread7, p) {
****************************************************************************/
/**
- * @page test_007_001 [7.1] Events registration
+ * @page test_007_001 [7.1] Messages Server loop
*
* <h2>Description</h2>
- * Two event listeners are registered on an event source and then
- * unregistered in the same order.<br> The test expects that the even
- * source has listeners after the registrations and after the first
- * unregistration, then, after the second unegistration, the test
- * expects no more listeners.
+ * A messenger thread is spawned that sends four messages back to the
+ * tester thread.<br> The test expect to receive the messages in the
+ * correct sequence and to not find a fifth message waiting.
*
* <h2>Test Steps</h2>
- * - [7.1.1] An Event Source is initialized.
- * - [7.1.2] Two Event Listeners are registered on the Event Source,
- * the Event Source is tested to have listeners.
- * - [7.1.3] An Event Listener is unregistered, the Event Source must
- * still have listeners.
- * - [7.1.4] An Event Listener is unregistered, the Event Source must
- * not have listeners.
+ * - [7.1.1] Starting the messenger thread.
+ * - [7.1.2] Waiting for four messages then testing the receive order.
* .
*/
static void test_007_001_execute(void) {
- event_listener_t el1, el2;
+ thread_t *tp;
+ msg_t msg;
- /* [7.1.1] An Event Source is initialized.*/
+ /* [7.1.1] Starting the messenger thread.*/
test_set_step(1);
{
- chEvtObjectInit(&es1);
+ threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() + 1,
+ msg_thread1, chThdGetSelfX());
}
- /* [7.1.2] Two Event Listeners are registered on the Event Source,
- the Event Source is tested to have listeners.*/
+ /* [7.1.2] Waiting for four messages then testing the receive
+ order.*/
test_set_step(2);
{
- chEvtRegisterMask(&es1, &el1, 1);
- chEvtRegisterMask(&es1, &el2, 2);
- test_assert_lock(chEvtIsListeningI(&es1), "no listener");
- }
-
- /* [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");
- }
+ unsigned i;
- /* [7.1.4] An Event Listener is unregistered, the Event Source must
- not have listeners.*/
- test_set_step(4);
- {
- chEvtUnregister(&es1, &el2);
- test_assert_lock(!chEvtIsListeningI(&es1), "stuck listener");
+ for (i = 0; i < 4; i++) {
+ tp = chMsgWait();
+ msg = chMsgGet(tp);
+ chMsgRelease(tp, msg);
+ test_emit_token(msg);
+ }
+ test_wait_threads();
+ test_assert_sequence("ABCD", "invalid sequence");
}
}
static const testcase_t test_007_001 = {
- "Events registration",
+ "Messages Server loop",
NULL,
NULL,
test_007_001_execute
};
-/**
- * @page test_007_002 [7.2] Event Flags dispatching
- *
- * <h2>Description</h2>
- * The test dispatches three event flags and verifies that the
- * associated event handlers are invoked in LSb-first order.
- *
- * <h2>Test Steps</h2>
- * - [7.2.1] Three evenf flag bits are raised then chEvtDispatch() is
- * invoked, the sequence of handlers calls is tested.
- * .
- */
-
-static void test_007_002_setup(void) {
- chEvtGetAndClearEvents(ALL_EVENTS);
-}
-
-static void test_007_002_execute(void) {
-
- /* [7.2.1] Three evenf flag bits are raised then chEvtDispatch() is
- invoked, the sequence of handlers calls is tested.*/
- test_set_step(1);
- {
- chEvtDispatch(evhndl, 7);
- test_assert_sequence("ABC", "invalid sequence");
- }
-}
-
-static const testcase_t test_007_002 = {
- "Event Flags dispatching",
- test_007_002_setup,
- NULL,
- test_007_002_execute
-};
-
-/**
- * @page test_007_003 [7.3] Events Flags wait using chEvtWaitOne()
- *
- * <h2>Description</h2>
- * Functionality of chEvtWaitOne() is tested under various scenarios.
- *
- * <h2>Test Steps</h2>
- * - [7.3.1] Setting three event flags.
- * - [7.3.2] Calling chEvtWaitOne() three times, each time a single
- * flag must be returned in order of priority.
- * - [7.3.3] Getting current time and starting a signaler thread, the
- * thread will set an event flag after 50mS.
- * - [7.3.4] Calling chEvtWaitOne() then verifying that the event has
- * been received after 50mS and that the event flags mask has been
- * emptied.
- * .
- */
-
-static void test_007_003_setup(void) {
- chEvtGetAndClearEvents(ALL_EVENTS);
-}
-
-static void test_007_003_execute(void) {
- eventmask_t m;
- systime_t target_time;
-
- /* [7.3.1] Setting three event flags.*/
- test_set_step(1);
- {
- chEvtAddEvents(7);
- }
-
- /* [7.3.2] Calling chEvtWaitOne() three times, each time a single
- flag must be returned in order of priority.*/
- test_set_step(2);
- {
- m = chEvtWaitOne(ALL_EVENTS);
- test_assert(m == 1, "single event error");
- m = chEvtWaitOne(ALL_EVENTS);
- test_assert(m == 2, "single event error");
- m = chEvtWaitOne(ALL_EVENTS);
- test_assert(m == 4, "single event error");
- m = chEvtGetAndClearEvents(ALL_EVENTS);
- test_assert(m == 0, "stuck event");
- }
-
- /* [7.3.3] Getting current time and starting a signaler thread, the
- thread will set an event flag after 50mS.*/
- test_set_step(3);
- {
- target_time = test_wait_tick() + MS2ST(50);
- threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
- evt_thread3, chThdGetSelfX());
- }
-
- /* [7.3.4] Calling chEvtWaitOne() then verifying that the event has
- been received after 50mS and that the event flags mask has been
- emptied.*/
- test_set_step(4);
- {
- m = chEvtWaitOne(ALL_EVENTS);
- test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
- "out of time window");
- test_assert(m == 1, "event flag error");
- m = chEvtGetAndClearEvents(ALL_EVENTS);
- test_assert(m == 0, "stuck event");
- test_wait_threads();
- }
-}
-
-static const testcase_t test_007_003 = {
- "Events Flags wait using chEvtWaitOne()",
- test_007_003_setup,
- NULL,
- test_007_003_execute
-};
-
-/**
- * @page test_007_004 [7.4] Events Flags wait using chEvtWaitAny()
- *
- * <h2>Description</h2>
- * Functionality of chEvtWaitAny() is tested under various scenarios.
- *
- * <h2>Test Steps</h2>
- * - [7.4.1] Setting two, non contiguous, event flags.
- * - [7.4.2] Calling chEvtWaitAny() one time, the two flags must be
- * returned.
- * - [7.4.3] Getting current time and starting a signaler thread, the
- * thread will set an event flag after 50mS.
- * - [7.4.4] Calling chEvtWaitAny() then verifying that the event has
- * been received after 50mS and that the event flags mask has been
- * emptied.
- * .
- */
-
-static void test_007_004_setup(void) {
- chEvtGetAndClearEvents(ALL_EVENTS);
-}
-
-static void test_007_004_execute(void) {
- eventmask_t m;
- systime_t target_time;
-
- /* [7.4.1] Setting two, non contiguous, event flags.*/
- test_set_step(1);
- {
- chEvtAddEvents(5);
- }
-
- /* [7.4.2] Calling chEvtWaitAny() one time, the two flags must be
- returned.*/
- test_set_step(2);
- {
- m = chEvtWaitAny(ALL_EVENTS);
- test_assert(m == 5, "unexpected pending bit");
- m = chEvtGetAndClearEvents(ALL_EVENTS);
- test_assert(m == 0, "stuck event");
- }
-
- /* [7.4.3] Getting current time and starting a signaler thread, the
- thread will set an event flag after 50mS.*/
- test_set_step(3);
- {
- target_time = test_wait_tick() + MS2ST(50);
- threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
- evt_thread3, chThdGetSelfX());
- }
-
- /* [7.4.4] Calling chEvtWaitAny() then verifying that the event has
- been received after 50mS and that the event flags mask has been
- emptied.*/
- test_set_step(4);
- {
- m = chEvtWaitAny(ALL_EVENTS);
- test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
- "out of time window");
- test_assert(m == 1, "event flag error");
- m = chEvtGetAndClearEvents(ALL_EVENTS);
- test_assert(m == 0, "stuck event");
- test_wait_threads();
- }
-}
-
-static const testcase_t test_007_004 = {
- "Events Flags wait using chEvtWaitAny()",
- test_007_004_setup,
- NULL,
- test_007_004_execute
-};
-
-/**
- * @page test_007_005 [7.5] Events Flags wait using chEvtWaitAll()
- *
- * <h2>Description</h2>
- * Functionality of chEvtWaitAll() is tested under various scenarios.
- *
- * <h2>Test Steps</h2>
- * - [7.5.1] Setting two, non contiguous, event flags.
- * - [7.5.2] Calling chEvtWaitAll() one time, the two flags must be
- * returned.
- * - [7.5.3] Setting one event flag.
- * - [7.5.4] Getting current time and starting a signaler thread, the
- * thread will set another event flag after 50mS.
- * - [7.5.5] Calling chEvtWaitAll() then verifying that both event
- * flags have been received after 50mS and that the event flags mask
- * has been emptied.
- * .
- */
-
-static void test_007_005_setup(void) {
- chEvtGetAndClearEvents(ALL_EVENTS);
-}
-
-static void test_007_005_execute(void) {
- eventmask_t m;
- systime_t target_time;
-
- /* [7.5.1] Setting two, non contiguous, event flags.*/
- test_set_step(1);
- {
- chEvtAddEvents(5);
- }
-
- /* [7.5.2] Calling chEvtWaitAll() one time, the two flags must be
- returned.*/
- test_set_step(2);
- {
- m = chEvtWaitAll(5);
- test_assert(m == 5, "unexpected pending bit");
- m = chEvtGetAndClearEvents(ALL_EVENTS);
- test_assert(m == 0, "stuck event");
- }
-
- /* [7.5.3] Setting one event flag.*/
- test_set_step(3);
- {
- chEvtAddEvents(4);
- }
-
- /* [7.5.4] Getting current time and starting a signaler thread, the
- thread will set another event flag after 50mS.*/
- test_set_step(4);
- {
- target_time = test_wait_tick() + MS2ST(50);
- threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
- evt_thread3, chThdGetSelfX());
- }
-
- /* [7.5.5] Calling chEvtWaitAll() then verifying that both event
- flags have been received after 50mS and that the event flags mask
- has been emptied.*/
- test_set_step(5);
- {
- m = chEvtWaitAll(5);
- test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
- "out of time window");
- test_assert(m == 5, "event flags error");
- m = chEvtGetAndClearEvents(ALL_EVENTS);
- test_assert(m == 0, "stuck event");
- test_wait_threads();
- }
-}
-
-static const testcase_t test_007_005 = {
- "Events Flags wait using chEvtWaitAll()",
- test_007_005_setup,
- NULL,
- test_007_005_execute
-};
-
-#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
-/**
- * @page test_007_006 [7.6] Events Flags wait timeouts
- *
- * <h2>Description</h2>
- * Timeout functionality is tested for chEvtWaitOneTimeout(),
- * chEvtWaitAnyTimeout() and chEvtWaitAllTimeout().
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_EVENTS_TIMEOUT
- * .
- *
- * <h2>Test Steps</h2>
- * - [7.6.1] The functions are invoked first with TIME_IMMEDIATE
- * timeout, the timeout condition is tested.
- * - [7.6.2] The functions are invoked first with a 50mS timeout, the
- * timeout condition is tested.
- * .
- */
-
-static void test_007_006_setup(void) {
- chEvtGetAndClearEvents(ALL_EVENTS);
-}
-
-static void test_007_006_execute(void) {
- eventmask_t m;
-
- /* [7.6.1] The functions are invoked first with TIME_IMMEDIATE
- timeout, the timeout condition is tested.*/
- test_set_step(1);
- {
- m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_IMMEDIATE);
- test_assert(m == 0, "spurious event");
- m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_IMMEDIATE);
- test_assert(m == 0, "spurious event");
- m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_IMMEDIATE);
- test_assert(m == 0, "spurious event");
- }
-
- /* [7.6.2] The functions are invoked first with a 50mS timeout, the
- timeout condition is tested.*/
- test_set_step(2);
- {
- m = chEvtWaitOneTimeout(ALL_EVENTS, MS2ST(50));
- test_assert(m == 0, "spurious event");
- m = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(50));
- test_assert(m == 0, "spurious event");
- m = chEvtWaitAllTimeout(ALL_EVENTS, MS2ST(50));
- test_assert(m == 0, "spurious event");
- }
-}
-
-static const testcase_t test_007_006 = {
- "Events Flags wait timeouts",
- test_007_006_setup,
- NULL,
- test_007_006_execute
-};
-#endif /* CH_CFG_USE_EVENTS_TIMEOUT */
-
-/**
- * @page test_007_007 [7.7] Broadcasting using chEvtBroadcast()
- *
- * <h2>Description</h2>
- * Functionality of chEvtBroadcast() is tested.
- *
- * <h2>Test Steps</h2>
- * - [7.7.1] Registering on two event sources associating them with
- * flags 1 and 4.
- * - [7.7.2] Getting current time and starting a broadcaster thread,
- * the thread broadcast the first Event Source immediately and the
- * other after 50mS.
- * - [7.7.3] Calling chEvtWaitAll() then verifying that both event
- * flags have been received after 50mS and that the event flags mask
- * has been emptied.
- * - [7.7.4] Unregistering from the Event Sources.
- * .
- */
-
-static void test_007_007_setup(void) {
- chEvtGetAndClearEvents(ALL_EVENTS);
- chEvtObjectInit(&es1);
- chEvtObjectInit(&es2);
-}
-
-static void test_007_007_execute(void) {
- eventmask_t m;
- event_listener_t el1, el2;
- systime_t target_time;
-
- /* [7.7.1] Registering on two event sources associating them with
- flags 1 and 4.*/
- test_set_step(1);
- {
- chEvtRegisterMask(&es1, &el1, 1);
- chEvtRegisterMask(&es2, &el2, 4);
- }
-
- /* [7.7.2] Getting current time and starting a broadcaster thread,
- the thread broadcast the first Event Source immediately and the
- other after 50mS.*/
- test_set_step(2);
- {
- target_time = test_wait_tick() + MS2ST(50);
- threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
- evt_thread7, "A");
- }
-
- /* [7.7.3] Calling chEvtWaitAll() then verifying that both event
- flags have been received after 50mS and that the event flags mask
- has been emptied.*/
- test_set_step(3);
- {
- m = chEvtWaitAll(5);
- test_assert_time_window(target_time, target_time + ALLOWED_DELAY,
- "out of time window");
- m = chEvtGetAndClearEvents(ALL_EVENTS);
- test_assert(m == 0, "stuck event");
- test_wait_threads();
- }
-
- /* [7.7.4] Unregistering from the Event Sources.*/
- test_set_step(4);
- {
- chEvtUnregister(&es1, &el1);
- chEvtUnregister(&es2, &el2);
- test_assert(!chEvtIsListeningI(&es1), "stuck listener");
- test_assert(!chEvtIsListeningI(&es2), "stuck listener");
- }
-}
-
-static const testcase_t test_007_007 = {
- "Broadcasting using chEvtBroadcast()",
- test_007_007_setup,
- NULL,
- test_007_007_execute
-};
-
/****************************************************************************
* Exported data.
****************************************************************************/
/**
- * @brief Event Sources and Event Flags.
+ * @brief Synchronous Messages.
*/
const testcase_t * const test_sequence_007[] = {
&test_007_001,
- &test_007_002,
- &test_007_003,
- &test_007_004,
- &test_007_005,
-#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
- &test_007_006,
-#endif
- &test_007_007,
NULL
};
-#endif /* CH_CFG_USE_EVENTS */
+#endif /* CH_CFG_USE_MESSAGES */
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,374 +22,528 @@
* @file test_sequence_008.c
* @brief Test Sequence 008 code.
*
- * @page test_sequence_008 [8] Mailboxes
+ * @page test_sequence_008 [8] Event Sources and Event Flags
*
* File: @ref test_sequence_008.c
*
* <h2>Description</h2>
- * This sequence tests the ChibiOS/RT functionalities related to
- * mailboxes.
+ * This module implements the test sequence for the Events subsystem.
*
* <h2>Conditions</h2>
* This sequence is only executed if the following preprocessor condition
* evaluates to true:
- * - CH_CFG_USE_MAILBOXES
+ * - CH_CFG_USE_EVENTS
* .
*
* <h2>Test Cases</h2>
* - @subpage test_008_001
* - @subpage test_008_002
* - @subpage test_008_003
+ * - @subpage test_008_004
+ * - @subpage test_008_005
+ * - @subpage test_008_006
+ * - @subpage test_008_007
* .
*/
-#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
+#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
/****************************************************************************
* Shared code.
****************************************************************************/
-#define MB_SIZE 4
+static EVENTSOURCE_DECL(es1);
+static EVENTSOURCE_DECL(es2);
-static msg_t mb_buffer[MB_SIZE];
-static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE);
+static void h1(eventid_t id) {(void)id;test_emit_token('A');}
+static void h2(eventid_t id) {(void)id;test_emit_token('B');}
+static void h3(eventid_t id) {(void)id;test_emit_token('C');}
+static ROMCONST evhandler_t evhndl[] = {h1, h2, h3};
+
+static THD_FUNCTION(evt_thread3, p) {
+
+ chThdSleepMilliseconds(50);
+ chEvtSignal((thread_t *)p, 1);
+}
+
+static THD_FUNCTION(evt_thread7, p) {
+
+ (void)p;
+ chEvtBroadcast(&es1);
+ chThdSleepMilliseconds(50);
+ chEvtBroadcast(&es2);
+}
/****************************************************************************
* Test cases.
****************************************************************************/
/**
- * @page test_008_001 [8.1] Mailbox normal API, non-blocking tests
+ * @page test_008_001 [8.1] Events registration
*
* <h2>Description</h2>
- * The mailbox normal API is tested without triggering blocking
- * conditions.
+ * Two event listeners are registered on an event source and then
+ * unregistered in the same order.<br> The test expects that the even
+ * source has listeners after the registrations and after the first
+ * unregistration, then, after the second unegistration, the test
+ * expects no more listeners.
*
* <h2>Test Steps</h2>
- * - [8.1.1] Testing the mailbox size.
- * - [8.1.2] Resetting the mailbox, conditions are checked, no errors
- * expected.
- * - [8.1.3] Testing the behavior of API when the mailbox is in reset
- * state then return in active state.
- * - [8.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
- * once, no errors expected.
- * - [8.1.5] Testing intermediate conditions. Data pointers must be
- * aligned, semaphore counters are checked.
- * - [8.1.6] Emptying the mailbox using chMBFetch(), no errors
- * expected.
- * - [8.1.7] Posting and then fetching one more message, no errors
- * expected.
- * - [8.1.8] Testing final conditions. Data pointers must be aligned to
- * buffer start, semaphore counters are checked.
+ * - [8.1.1] An Event Source is initialized.
+ * - [8.1.2] Two Event Listeners are registered on the Event Source,
+ * the Event Source is tested to have listeners.
+ * - [8.1.3] An Event Listener is unregistered, the Event Source must
+ * still have listeners.
+ * - [8.1.4] An Event Listener is unregistered, the Event Source must
+ * not have listeners.
* .
*/
-static void test_008_001_setup(void) {
- chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
+static void test_008_001_execute(void) {
+ event_listener_t el1, el2;
+
+ /* [8.1.1] An Event Source is initialized.*/
+ test_set_step(1);
+ {
+ chEvtObjectInit(&es1);
+ }
+
+ /* [8.1.2] Two Event Listeners are registered on the Event Source,
+ the Event Source is tested to have listeners.*/
+ test_set_step(2);
+ {
+ chEvtRegisterMask(&es1, &el1, 1);
+ chEvtRegisterMask(&es1, &el2, 2);
+ test_assert_lock(chEvtIsListeningI(&es1), "no listener");
+ }
+
+ /* [8.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");
+ }
+
+ /* [8.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");
+ }
}
-static void test_008_001_teardown(void) {
- chMBReset(&mb1);
+static const testcase_t test_008_001 = {
+ "Events registration",
+ NULL,
+ NULL,
+ test_008_001_execute
+};
+
+/**
+ * @page test_008_002 [8.2] Event Flags dispatching
+ *
+ * <h2>Description</h2>
+ * The test dispatches three event flags and verifies that the
+ * associated event handlers are invoked in LSb-first order.
+ *
+ * <h2>Test Steps</h2>
+ * - [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) {
+ chEvtGetAndClearEvents(ALL_EVENTS);
}
-static void test_008_001_execute(void) {
- msg_t msg1, msg2;
- unsigned i;
+static void test_008_002_execute(void) {
- /* [8.1.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");
+ chEvtDispatch(evhndl, 7);
+ test_assert_sequence("ABC", "invalid sequence");
}
+}
+
+static const testcase_t test_008_002 = {
+ "Event Flags dispatching",
+ test_008_002_setup,
+ NULL,
+ test_008_002_execute
+};
+
+/**
+ * @page test_008_003 [8.3] Events Flags wait using chEvtWaitOne()
+ *
+ * <h2>Description</h2>
+ * Functionality of chEvtWaitOne() is tested under various scenarios.
+ *
+ * <h2>Test Steps</h2>
+ * - [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.
+ * .
+ */
- /* [8.1.2] Resetting the mailbox, conditions are checked, no errors
- expected.*/
+static void test_008_003_setup(void) {
+ chEvtGetAndClearEvents(ALL_EVENTS);
+}
+
+static void test_008_003_execute(void) {
+ eventmask_t m;
+ systime_t target_time;
+
+ /* [8.3.1] Setting three event flags.*/
+ test_set_step(1);
+ {
+ chEvtAddEvents(7);
+ }
+
+ /* [8.3.2] Calling chEvtWaitOne() three times, each time a single
+ flag must be returned in order of priority.*/
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");
+ 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.1.3] Testing the behavior of API when the mailbox is in reset
- state then return 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);
{
- 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);
+ target_time = test_wait_tick() + MS2ST(50);
+ threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
+ evt_thread3, chThdGetSelfX());
}
- /* [8.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
- once, no errors expected.*/
+ /* [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);
{
- 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");
+ 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();
}
+}
- /* [8.1.5] Testing intermediate conditions. Data pointers must be
- aligned, semaphore counters are checked.*/
- test_set_step(5);
+static const testcase_t test_008_003 = {
+ "Events Flags wait using chEvtWaitOne()",
+ test_008_003_setup,
+ NULL,
+ test_008_003_execute
+};
+
+/**
+ * @page test_008_004 [8.4] Events Flags wait using chEvtWaitAny()
+ *
+ * <h2>Description</h2>
+ * Functionality of chEvtWaitAny() is tested under various scenarios.
+ *
+ * <h2>Test Steps</h2>
+ * - [8.4.1] Setting two, non contiguous, event flags.
+ * - [8.4.2] Calling chEvtWaitAny() one time, the two flags must be
+ * returned.
+ * - [8.4.3] Getting current time and starting a signaler thread, the
+ * thread will set an event flag after 50mS.
+ * - [8.4.4] Calling chEvtWaitAny() then verifying that the event has
+ * been received after 50mS and that the event flags mask has been
+ * emptied.
+ * .
+ */
+
+static void test_008_004_setup(void) {
+ chEvtGetAndClearEvents(ALL_EVENTS);
+}
+
+static void test_008_004_execute(void) {
+ eventmask_t m;
+ systime_t target_time;
+
+ /* [8.4.1] Setting two, non contiguous, event flags.*/
+ test_set_step(1);
{
- 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");
+ chEvtAddEvents(5);
}
- /* [8.1.6] Emptying the mailbox using chMBFetch(), no errors
- expected.*/
- test_set_step(6);
+ /* [8.4.2] Calling chEvtWaitAny() one time, the two flags must be
+ returned.*/
+ test_set_step(2);
{
- 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");
+ m = chEvtWaitAny(ALL_EVENTS);
+ test_assert(m == 5, "unexpected pending bit");
+ m = chEvtGetAndClearEvents(ALL_EVENTS);
+ test_assert(m == 0, "stuck event");
}
- /* [8.1.7] Posting and then fetching one more message, no errors
- expected.*/
- test_set_step(7);
+ /* [8.4.3] Getting current time and starting a signaler thread, the
+ thread will set an event flag after 50mS.*/
+ test_set_step(3);
{
- 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");
+ target_time = test_wait_tick() + MS2ST(50);
+ threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
+ evt_thread3, chThdGetSelfX());
}
- /* [8.1.8] Testing final conditions. Data pointers must be aligned to
- buffer start, semaphore counters are checked.*/
- test_set_step(8);
+ /* [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);
{
- 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");
+ 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_001 = {
- "Mailbox normal API, non-blocking tests",
- test_008_001_setup,
- test_008_001_teardown,
- test_008_001_execute
+static const testcase_t test_008_004 = {
+ "Events Flags wait using chEvtWaitAny()",
+ test_008_004_setup,
+ NULL,
+ test_008_004_execute
};
/**
- * @page test_008_002 [8.2] Mailbox I-Class API, non-blocking tests
+ * @page test_008_005 [8.5] Events Flags wait using chEvtWaitAll()
*
* <h2>Description</h2>
- * The mailbox I-Class API is tested without triggering blocking
- * conditions.
+ * Functionality of chEvtWaitAll() is tested under various scenarios.
*
* <h2>Test Steps</h2>
- * - [8.2.1] Testing the mailbox size.
- * - [8.2.2] Resetting the mailbox, conditions are checked, no errors
- * expected. The mailbox is then returned in active state.
- * - [8.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
- * once, no errors expected.
- * - [8.2.4] Testing intermediate conditions. Data pointers must be
- * aligned, semaphore counters are checked.
- * - [8.2.5] Emptying the mailbox using chMBFetchI(), no errors
- * expected.
- * - [8.2.6] Posting and then fetching one more message, no errors
- * expected.
- * - [8.2.7] Testing final conditions. Data pointers must be aligned to
- * buffer start, semaphore counters are checked.
+ * - [8.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_002_setup(void) {
- chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
+static void test_008_005_setup(void) {
+ chEvtGetAndClearEvents(ALL_EVENTS);
}
-static void test_008_002_teardown(void) {
- chMBReset(&mb1);
-}
+static void test_008_005_execute(void) {
+ eventmask_t m;
+ systime_t target_time;
-static void test_008_002_execute(void) {
- msg_t msg1, msg2;
- unsigned i;
-
- /* [8.2.1] Testing the mailbox size.*/
+ /* [8.5.1] Setting two, non contiguous, event flags.*/
test_set_step(1);
{
- test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
+ chEvtAddEvents(5);
}
- /* [8.2.2] Resetting the mailbox, conditions are checked, no errors
- expected. The mailbox is then returned in active state.*/
+ /* [8.5.2] Calling chEvtWaitAll() one time, the two flags must be
+ returned.*/
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);
+ m = chEvtWaitAll(5);
+ test_assert(m == 5, "unexpected pending bit");
+ m = chEvtGetAndClearEvents(ALL_EVENTS);
+ test_assert(m == 0, "stuck event");
}
- /* [8.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
- once, no errors expected.*/
+ /* [8.5.3] Setting one event flag.*/
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");
+ chEvtAddEvents(4);
}
- /* [8.2.4] Testing intermediate conditions. Data pointers must be
- aligned, semaphore counters are checked.*/
+ /* [8.5.4] Getting current time and starting a signaler thread, the
+ thread will set another event flag after 50mS.*/
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");
+ target_time = test_wait_tick() + MS2ST(50);
+ threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
+ evt_thread3, chThdGetSelfX());
}
- /* [8.2.5] Emptying the mailbox using chMBFetchI(), no errors
- expected.*/
+ /* [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);
{
- 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");
+ 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();
}
+}
- /* [8.2.6] Posting and then fetching one more message, no errors
- expected.*/
- test_set_step(6);
+static const testcase_t test_008_005 = {
+ "Events Flags wait using chEvtWaitAll()",
+ test_008_005_setup,
+ NULL,
+ test_008_005_execute
+};
+
+#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
+/**
+ * @page test_008_006 [8.6] Events Flags wait timeouts
+ *
+ * <h2>Description</h2>
+ * Timeout functionality is tested for chEvtWaitOneTimeout(),
+ * chEvtWaitAnyTimeout() and chEvtWaitAllTimeout().
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_EVENTS_TIMEOUT
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [8.6.1] The functions are invoked first with TIME_IMMEDIATE
+ * timeout, the timeout condition is tested.
+ * - [8.6.2] The functions are invoked first with a 50mS timeout, the
+ * timeout condition is tested.
+ * .
+ */
+
+static void test_008_006_setup(void) {
+ chEvtGetAndClearEvents(ALL_EVENTS);
+}
+
+static void test_008_006_execute(void) {
+ eventmask_t m;
+
+ /* [8.6.1] The functions are invoked first with TIME_IMMEDIATE
+ timeout, the timeout condition is tested.*/
+ test_set_step(1);
{
- 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");
+ 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.2.7] Testing final conditions. Data pointers must be aligned to
- buffer start, semaphore counters are checked.*/
- test_set_step(7);
+ /* [8.6.2] The functions are invoked first with a 50mS timeout, the
+ timeout condition is tested.*/
+ test_set_step(2);
{
- 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");
+ 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_002 = {
- "Mailbox I-Class API, non-blocking tests",
- test_008_002_setup,
- test_008_002_teardown,
- test_008_002_execute
+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_003 [8.3] Mailbox timeouts
+ * @page test_008_007 [8.7] Broadcasting using chEvtBroadcast()
*
* <h2>Description</h2>
- * The mailbox API is tested for timeouts.
+ * Functionality of chEvtBroadcast() is tested.
*
* <h2>Test Steps</h2>
- * - [8.3.1] Filling the mailbox.
- * - [8.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
- * chMBPostAheadI() timeout.
- * - [8.3.3] Resetting the mailbox. The mailbox is then returned in
- * active state.
- * - [8.3.4] Testing chMBFetch() and chMBFetchI() timeout.
+ * - [8.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_003_setup(void) {
- chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
-}
-
-static void test_008_003_teardown(void) {
- chMBReset(&mb1);
+static void test_008_007_setup(void) {
+ chEvtGetAndClearEvents(ALL_EVENTS);
+ chEvtObjectInit(&es1);
+ chEvtObjectInit(&es2);
}
-static void test_008_003_execute(void) {
- msg_t msg1, msg2;
- unsigned i;
+static void test_008_007_execute(void) {
+ eventmask_t m;
+ event_listener_t el1, el2;
+ systime_t target_time;
- /* [8.3.1] Filling the mailbox.*/
+ /* [8.7.1] Registering on two event sources associating them with
+ flags 1 and 4.*/
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");
- }
+ chEvtRegisterMask(&es1, &el1, 1);
+ chEvtRegisterMask(&es2, &el2, 4);
}
- /* [8.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
- chMBPostAheadI() timeout.*/
+ /* [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);
{
- 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");
+ target_time = test_wait_tick() + MS2ST(50);
+ threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
+ evt_thread7, "A");
}
- /* [8.3.3] Resetting the mailbox. The mailbox is then returned in
- active state.*/
+ /* [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);
{
- chMBReset(&mb1);
- chMBResumeX(&mb1);
+ 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.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/
+ /* [8.7.4] Unregistering from the Event Sources.*/
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");
+ chEvtUnregister(&es1, &el1);
+ chEvtUnregister(&es2, &el2);
+ test_assert(!chEvtIsListeningI(&es1), "stuck listener");
+ test_assert(!chEvtIsListeningI(&es2), "stuck listener");
}
}
-static const testcase_t test_008_003 = {
- "Mailbox timeouts",
- test_008_003_setup,
- test_008_003_teardown,
- test_008_003_execute
+static const testcase_t test_008_007 = {
+ "Broadcasting using chEvtBroadcast()",
+ test_008_007_setup,
+ NULL,
+ test_008_007_execute
};
/****************************************************************************
@@ -397,13 +551,19 @@ static const testcase_t test_008_003 = {
****************************************************************************/
/**
- * @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
*
* <h2>Description</h2>
- * This sequence tests the ChibiOS/RT functionalities related to memory
- * pools.
+ * This sequence tests the ChibiOS/RT functionalities related to
+ * mailboxes.
*
* <h2>Conditions</h2>
* This sequence is only executed if the following preprocessor condition
* evaluates to true:
- * - CH_CFG_USE_MEMPOOLS
+ * - CH_CFG_USE_MAILBOXES
* .
*
* <h2>Test Cases</h2>
@@ -43,254 +43,367 @@
* .
*/
-#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
+#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
/****************************************************************************
* Shared code.
****************************************************************************/
-#define MEMORY_POOL_SIZE 4
+#define MB_SIZE 4
-static uint32_t objects[MEMORY_POOL_SIZE];
-static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL);
-
-#if CH_CFG_USE_SEMAPHORES
-static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t));
-#endif
-
-static void *null_provider(size_t size, unsigned align) {
-
- (void)size;
- (void)align;
-
- return NULL;
-}
+static msg_t mb_buffer[MB_SIZE];
+static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE);
/****************************************************************************
* Test cases.
****************************************************************************/
/**
- * @page test_009_001 [9.1] Loading and emptying a memory pool
+ * @page test_009_001 [9.1] Mailbox normal API, non-blocking tests
*
* <h2>Description</h2>
- * The memory pool functionality is tested by loading and emptying it,
- * all conditions are tested.
+ * The mailbox normal API is tested without triggering blocking
+ * conditions.
*
* <h2>Test Steps</h2>
- * - [9.1.1] Adding the objects to the pool using chPoolLoadArray().
- * - [9.1.2] Emptying the pool using chPoolAlloc().
- * - [9.1.3] Now must be empty.
- * - [9.1.4] Adding the objects to the pool using chPoolFree().
- * - [9.1.5] Emptying the pool using chPoolAlloc() again.
- * - [9.1.6] Now must be empty again.
- * - [9.1.7] Covering the case where a provider is unable to return
- * more memory.
+ * - [9.1.1] Testing the mailbox size.
+ * - [9.1.2] Resetting the mailbox, conditions are checked, no errors
+ * expected.
+ * - [9.1.3] Testing the behavior of API when the mailbox is in reset
+ * state then return in active state.
+ * - [9.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
+ * once, no errors expected.
+ * - [9.1.5] Testing intermediate conditions. Data pointers must be
+ * aligned, semaphore counters are checked.
+ * - [9.1.6] Emptying the mailbox using chMBFetch(), no errors
+ * expected.
+ * - [9.1.7] Posting and then fetching one more message, no errors
+ * expected.
+ * - [9.1.8] Testing final conditions. Data pointers must be aligned to
+ * buffer start, semaphore counters are checked.
* .
*/
static void test_009_001_setup(void) {
- chPoolObjectInit(&mp1, sizeof (uint32_t), NULL);
+ chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
+}
+
+static void test_009_001_teardown(void) {
+ chMBReset(&mb1);
}
static void test_009_001_execute(void) {
+ msg_t msg1, msg2;
unsigned i;
- /* [9.1.1] Adding the objects to the pool using chPoolLoadArray().*/
+ /* [9.1.1] Testing the mailbox size.*/
test_set_step(1);
{
- chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE);
+ test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
}
- /* [9.1.2] Emptying the pool using chPoolAlloc().*/
+ /* [9.1.2] Resetting the mailbox, conditions are checked, no errors
+ expected.*/
test_set_step(2);
{
- for (i = 0; i < MEMORY_POOL_SIZE; i++)
- test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
+ chMBReset(&mb1);
+ test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
+ test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
+ test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
+ test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
}
- /* [9.1.3] Now must be empty.*/
+ /* [9.1.3] Testing the behavior of API when the mailbox is in reset
+ state then return in active state.*/
test_set_step(3);
{
- test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
+ msg1 = chMBPost(&mb1, (msg_t)0, TIME_INFINITE);
+ test_assert(msg1 == MSG_RESET, "not in reset state");
+ msg1 = chMBPostAhead(&mb1, (msg_t)0, TIME_INFINITE);
+ test_assert(msg1 == MSG_RESET, "not in reset state");
+ msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
+ test_assert(msg1 == MSG_RESET, "not in reset state");
+ chMBResumeX(&mb1);
}
- /* [9.1.4] Adding the objects to the pool using chPoolFree().*/
+ /* [9.1.4] Filling the mailbox using chMBPost() and chMBPostAhead()
+ once, no errors expected.*/
test_set_step(4);
{
- for (i = 0; i < MEMORY_POOL_SIZE; i++)
- chPoolFree(&mp1, &objects[i]);
+ for (i = 0; i < MB_SIZE - 1; i++) {
+ msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ }
+ msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
}
- /* [9.1.5] Emptying the pool using chPoolAlloc() again.*/
+ /* [9.1.5] Testing intermediate conditions. Data pointers must be
+ aligned, semaphore counters are checked.*/
test_set_step(5);
{
- for (i = 0; i < MEMORY_POOL_SIZE; i++)
- test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
+ test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
+ test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
+ test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
}
- /* [9.1.6] Now must be empty again.*/
+ /* [9.1.6] Emptying the mailbox using chMBFetch(), no errors
+ expected.*/
test_set_step(6);
{
- test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
+ for (i = 0; i < MB_SIZE; i++) {
+ msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ test_emit_token(msg2);
+ }
+ test_assert_sequence("ABCD", "wrong get sequence");
}
- /* [9.1.7] Covering the case where a provider is unable to return
- more memory.*/
+ /* [9.1.7] Posting and then fetching one more message, no errors
+ expected.*/
test_set_step(7);
{
- chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider);
- test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory");
+ msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ }
+
+ /* [9.1.8] Testing final conditions. Data pointers must be aligned to
+ buffer start, semaphore counters are checked.*/
+ test_set_step(8);
+ {
+ test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
+ test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
+ test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
+ test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
}
}
static const testcase_t test_009_001 = {
- "Loading and emptying a memory pool",
+ "Mailbox normal API, non-blocking tests",
test_009_001_setup,
- NULL,
+ test_009_001_teardown,
test_009_001_execute
};
-#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
/**
- * @page test_009_002 [9.2] Loading and emptying a guarded memory pool without waiting
+ * @page test_009_002 [9.2] Mailbox I-Class API, non-blocking tests
*
* <h2>Description</h2>
- * The memory pool functionality is tested by loading and emptying it,
- * all conditions are tested.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_SEMAPHORES
- * .
+ * The mailbox I-Class API is tested without triggering blocking
+ * conditions.
*
* <h2>Test Steps</h2>
- * - [9.2.1] Adding the objects to the pool using
- * chGuardedPoolLoadArray().
- * - [9.2.2] Emptying the pool using chGuardedPoolAllocTimeout().
- * - [9.2.3] Now must be empty.
- * - [9.2.4] Adding the objects to the pool using chGuardedPoolFree().
- * - [9.2.5] Emptying the pool using chGuardedPoolAllocTimeout() again.
- * - [9.2.6] Now must be empty again.
+ * - [9.2.1] Testing the mailbox size.
+ * - [9.2.2] Resetting the mailbox, conditions are checked, no errors
+ * expected. The mailbox is then returned in active state.
+ * - [9.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
+ * once, no errors expected.
+ * - [9.2.4] Testing intermediate conditions. Data pointers must be
+ * aligned, semaphore counters are checked.
+ * - [9.2.5] Emptying the mailbox using chMBFetchI(), no errors
+ * expected.
+ * - [9.2.6] Posting and then fetching one more message, no errors
+ * expected.
+ * - [9.2.7] Testing final conditions. Data pointers must be aligned to
+ * buffer start, semaphore counters are checked.
* .
*/
static void test_009_002_setup(void) {
- chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
+ chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
+}
+
+static void test_009_002_teardown(void) {
+ chMBReset(&mb1);
}
static void test_009_002_execute(void) {
+ msg_t msg1, msg2;
unsigned i;
- /* [9.2.1] Adding the objects to the pool using
- chGuardedPoolLoadArray().*/
+ /* [9.2.1] Testing the mailbox size.*/
test_set_step(1);
{
- chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE);
+ test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
}
- /* [9.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/
+ /* [9.2.2] Resetting the mailbox, conditions are checked, no errors
+ expected. The mailbox is then returned in active state.*/
test_set_step(2);
{
- for (i = 0; i < MEMORY_POOL_SIZE; i++)
- test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
+ chSysLock();
+ chMBResetI(&mb1);
+ chSysUnlock();
+ test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
+ test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
+ test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
+ test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
+ chMBResumeX(&mb1);
}
- /* [9.2.3] Now must be empty.*/
+ /* [9.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI()
+ once, no errors expected.*/
test_set_step(3);
{
- test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
+ for (i = 0; i < MB_SIZE - 1; i++) {
+ chSysLock();
+ msg1 = chMBPostI(&mb1, 'B' + i);
+ chSysUnlock();
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ }
+ chSysLock();
+ msg1 = chMBPostAheadI(&mb1, 'A');
+ chSysUnlock();
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
}
- /* [9.2.4] Adding the objects to the pool using
- chGuardedPoolFree().*/
+ /* [9.2.4] Testing intermediate conditions. Data pointers must be
+ aligned, semaphore counters are checked.*/
test_set_step(4);
{
- for (i = 0; i < MEMORY_POOL_SIZE; i++)
- chGuardedPoolFree(&gmp1, &objects[i]);
+ test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty");
+ test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
+ test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned");
}
- /* [9.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
- again.*/
+ /* [9.2.5] Emptying the mailbox using chMBFetchI(), no errors
+ expected.*/
test_set_step(5);
{
- for (i = 0; i < MEMORY_POOL_SIZE; i++)
- test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
+ for (i = 0; i < MB_SIZE; i++) {
+ chSysLock();
+ msg1 = chMBFetchI(&mb1, &msg2);
+ chSysUnlock();
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ test_emit_token(msg2);
+ }
+ test_assert_sequence("ABCD", "wrong get sequence");
}
- /* [9.2.6] Now must be empty again.*/
+ /* [9.2.6] Posting and then fetching one more message, no errors
+ expected.*/
test_set_step(6);
{
- test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
+ msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ }
+
+ /* [9.2.7] Testing final conditions. Data pointers must be aligned to
+ buffer start, semaphore counters are checked.*/
+ test_set_step(7);
+ {
+ test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
+ test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full");
+ test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
+ test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
}
}
static const testcase_t test_009_002 = {
- "Loading and emptying a guarded memory pool without waiting",
+ "Mailbox I-Class API, non-blocking tests",
test_009_002_setup,
- NULL,
+ test_009_002_teardown,
test_009_002_execute
};
-#endif /* CH_CFG_USE_SEMAPHORES */
-#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
/**
- * @page test_009_003 [9.3] Guarded Memory Pools timeout
+ * @page test_009_003 [9.3] Mailbox timeouts
*
* <h2>Description</h2>
- * The timeout features for the Guarded Memory Pools is tested.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_SEMAPHORES
- * .
+ * The mailbox API is tested for timeouts.
*
* <h2>Test Steps</h2>
- * - [9.3.1] Trying to allocate with 100mS timeout, must fail because
- * the pool is empty.
+ * - [9.3.1] Filling the mailbox.
+ * - [9.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
+ * chMBPostAheadI() timeout.
+ * - [9.3.3] Resetting the mailbox. The mailbox is then returned in
+ * active state.
+ * - [9.3.4] Testing chMBFetch() and chMBFetchI() timeout.
* .
*/
static void test_009_003_setup(void) {
- chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
+ chMBObjectInit(&mb1, mb_buffer, MB_SIZE);
+}
+
+static void test_009_003_teardown(void) {
+ chMBReset(&mb1);
}
static void test_009_003_execute(void) {
+ msg_t msg1, msg2;
+ unsigned i;
- /* [9.3.1] Trying to allocate with 100mS timeout, must fail because
- the pool is empty.*/
+ /* [9.3.1] Filling the mailbox.*/
test_set_step(1);
{
- test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty");
+ for (i = 0; i < MB_SIZE; i++) {
+ msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
+ test_assert(msg1 == MSG_OK, "wrong wake-up message");
+ }
+ }
+
+ /* [9.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and
+ chMBPostAheadI() timeout.*/
+ test_set_step(2);
+ {
+ msg1 = chMBPost(&mb1, 'X', 1);
+ test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
+ chSysLock();
+ msg1 = chMBPostI(&mb1, 'X');
+ chSysUnlock();
+ test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
+ msg1 = chMBPostAhead(&mb1, 'X', 1);
+ test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
+ chSysLock();
+ msg1 = chMBPostAheadI(&mb1, 'X');
+ chSysUnlock();
+ test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
+ }
+
+ /* [9.3.3] Resetting the mailbox. The mailbox is then returned in
+ active state.*/
+ test_set_step(3);
+ {
+ chMBReset(&mb1);
+ chMBResumeX(&mb1);
+ }
+
+ /* [9.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/
+ test_set_step(4);
+ {
+ msg1 = chMBFetch(&mb1, &msg2, 1);
+ test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
+ chSysLock();
+ msg1 = chMBFetchI(&mb1, &msg2);
+ chSysUnlock();
+ test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message");
}
}
static const testcase_t test_009_003 = {
- "Guarded Memory Pools timeout",
+ "Mailbox timeouts",
test_009_003_setup,
- NULL,
+ test_009_003_teardown,
test_009_003_execute
};
-#endif /* CH_CFG_USE_SEMAPHORES */
/****************************************************************************
* Exported data.
****************************************************************************/
/**
- * @brief Memory Pools.
+ * @brief Mailboxes.
*/
const testcase_t * const test_sequence_009[] = {
&test_009_001,
-#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
&test_009_002,
-#endif
-#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
&test_009_003,
-#endif
NULL
};
-#endif /* CH_CFG_USE_MEMPOOLS */
+#endif /* CH_CFG_USE_MAILBOXES */
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
*
* <h2>Description</h2>
* This sequence tests the ChibiOS/RT functionalities related to memory
- * heaps.
+ * pools.
*
* <h2>Conditions</h2>
* This sequence is only executed if the following preprocessor condition
* evaluates to true:
- * - CH_CFG_USE_HEAP
+ * - CH_CFG_USE_MEMPOOLS
* .
*
* <h2>Test Cases</h2>
* - @subpage test_010_001
* - @subpage test_010_002
+ * - @subpage test_010_003
* .
*/
-#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
+#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
/****************************************************************************
* Shared code.
****************************************************************************/
-#define ALLOC_SIZE 16
-#define HEAP_SIZE (ALLOC_SIZE * 8)
+#define MEMORY_POOL_SIZE 4
-memory_heap_t test_heap;
+static uint32_t objects[MEMORY_POOL_SIZE];
+static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL);
+
+#if CH_CFG_USE_SEMAPHORES
+static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t));
+#endif
+
+static void *null_provider(size_t size, unsigned align) {
+
+ (void)size;
+ (void)align;
+
+ return NULL;
+}
/****************************************************************************
* Test cases.
****************************************************************************/
/**
- * @page test_010_001 [10.1] Allocation and fragmentation
+ * @page test_010_001 [10.1] Loading and emptying a memory pool
*
* <h2>Description</h2>
- * Series of allocations/deallocations are performed in carefully
- * designed sequences in order to stimulate all the possible code paths
- * inside the allocator. The test expects to find the heap back to the
- * initial status after each sequence.
+ * The memory pool functionality is tested by loading and emptying it,
+ * all conditions are tested.
*
* <h2>Test Steps</h2>
- * - [10.1.1] Testing initial conditions, the heap must not be
- * fragmented and one free block present.
- * - [10.1.2] Trying to allocate an block bigger than available space,
- * an error is expected.
- * - [10.1.3] Single block allocation using chHeapAlloc() then the
- * block is freed using chHeapFree(), must not fail.
- * - [10.1.4] Using chHeapStatus() to assess the heap state. There must
- * be at least one free block of sufficient size.
- * - [10.1.5] Allocating then freeing in the same order.
- * - [10.1.6] Allocating then freeing in reverse order.
- * - [10.1.7] Small fragments handling. Checking the behavior when
- * allocating blocks with size not multiple of alignment unit.
- * - [10.1.8] Skipping a fragment, the first fragment in the list is
- * too small so the allocator must pick the second one.
- * - [10.1.9] Allocating the whole available space.
- * - [10.1.10] Testing final conditions. The heap geometry must be the
- * same than the one registered at beginning.
+ * - [10.1.1] Adding the objects to the pool using chPoolLoadArray().
+ * - [10.1.2] Emptying the pool using chPoolAlloc().
+ * - [10.1.3] Now must be empty.
+ * - [10.1.4] Adding the objects to the pool using chPoolFree().
+ * - [10.1.5] Emptying the pool using chPoolAlloc() again.
+ * - [10.1.6] Now must be empty again.
+ * - [10.1.7] Covering the case where a provider is unable to return
+ * more memory.
* .
*/
static void test_010_001_setup(void) {
- chHeapObjectInit(&test_heap, test_buffer, sizeof(test_buffer));
+ chPoolObjectInit(&mp1, sizeof (uint32_t), NULL);
}
static void test_010_001_execute(void) {
- void *p1, *p2, *p3;
- size_t n, sz;
+ unsigned i;
- /* [10.1.1] Testing initial conditions, the heap must not be
- fragmented and one free block present.*/
+ /* [10.1.1] Adding the objects to the pool using chPoolLoadArray().*/
test_set_step(1);
{
- test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented");
+ chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE);
}
- /* [10.1.2] Trying to allocate an block bigger than available space,
- an error is expected.*/
+ /* [10.1.2] Emptying the pool using chPoolAlloc().*/
test_set_step(2);
{
- p1 = chHeapAlloc(&test_heap, sizeof test_buffer * 2);
- test_assert(p1 == NULL, "allocation not failed");
+ for (i = 0; i < MEMORY_POOL_SIZE; i++)
+ test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
}
- /* [10.1.3] Single block allocation using chHeapAlloc() then the
- block is freed using chHeapFree(), must not fail.*/
+ /* [10.1.3] Now must be empty.*/
test_set_step(3);
{
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- test_assert(p1 != NULL, "allocation failed");
- chHeapFree(p1);
+ test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
}
- /* [10.1.4] Using chHeapStatus() to assess the heap state. There must
- be at least one free block of sufficient size.*/
+ /* [10.1.4] Adding the objects to the pool using chPoolFree().*/
test_set_step(4);
{
- size_t total_size, largest_size;
-
- n = chHeapStatus(&test_heap, &total_size, &largest_size);
- test_assert(n == 1, "missing free block");
- test_assert(total_size >= ALLOC_SIZE, "unexpected heap state");
- test_assert(total_size == largest_size, "unexpected heap state");
+ for (i = 0; i < MEMORY_POOL_SIZE; i++)
+ chPoolFree(&mp1, &objects[i]);
}
- /* [10.1.5] Allocating then freeing in the same order.*/
+ /* [10.1.5] Emptying the pool using chPoolAlloc() again.*/
test_set_step(5);
{
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- chHeapFree(p1); /* Does not merge.*/
- chHeapFree(p2); /* Merges backward.*/
- chHeapFree(p3); /* Merges both sides.*/
- test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
+ for (i = 0; i < MEMORY_POOL_SIZE; i++)
+ test_assert(chPoolAlloc(&mp1) != NULL, "list empty");
}
- /* [10.1.6] Allocating then freeing in reverse order.*/
+ /* [10.1.6] Now must be empty again.*/
test_set_step(6);
{
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- chHeapFree(p3); /* Merges forward.*/
- chHeapFree(p2); /* Merges forward.*/
- chHeapFree(p1); /* Merges forward.*/
- test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
+ test_assert(chPoolAlloc(&mp1) == NULL, "list not empty");
}
- /* [10.1.7] Small fragments handling. Checking the behavior when
- allocating blocks with size not multiple of alignment unit.*/
+ /* [10.1.7] Covering the case where a provider is unable to return
+ more memory.*/
test_set_step(7);
{
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1);
- p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- chHeapFree(p1);
- test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- /* Note, the first situation happens when the alignment size is smaller
- than the header size, the second in the other cases.*/
- test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) ||
- (chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
- chHeapFree(p2);
- chHeapFree(p1);
- test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
- }
-
- /* [10.1.8] Skipping a fragment, the first fragment in the list is
- too small so the allocator must pick the second one.*/
- test_set_step(8);
- {
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- chHeapFree(p1);
- test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/
- chHeapFree(p1);
- chHeapFree(p2);
- test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
- }
-
- /* [10.1.9] Allocating the whole available space.*/
- test_set_step(9);
- {
- (void)chHeapStatus(&test_heap, &n, NULL);
- p1 = chHeapAlloc(&test_heap, n);
- test_assert(p1 != NULL, "allocation failed");
- test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty");
- chHeapFree(p1);
- }
-
- /* [10.1.10] Testing final conditions. The heap geometry must be the
- same than the one registered at beginning.*/
- test_set_step(10);
- {
- test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
- test_assert(n == sz, "size changed");
+ chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider);
+ test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory");
}
}
static const testcase_t test_010_001 = {
- "Allocation and fragmentation",
+ "Loading and emptying a memory pool",
test_010_001_setup,
NULL,
test_010_001_execute
};
+#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
/**
- * @page test_010_002 [10.2] Default Heap
+ * @page test_010_002 [10.2] Loading and emptying a guarded memory pool without waiting
*
* <h2>Description</h2>
- * The default heap is pre-allocated in the system. We test base
- * functionality.
+ * The memory pool functionality is tested by loading and emptying it,
+ * all conditions are tested.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_SEMAPHORES
+ * .
*
* <h2>Test Steps</h2>
- * - [10.2.1] Single block allocation using chHeapAlloc() then the
- * block is freed using chHeapFree(), must not fail.
- * - [10.2.2] Testing allocation failure.
+ * - [10.2.1] Adding the objects to the pool using
+ * chGuardedPoolLoadArray().
+ * - [10.2.2] Emptying the pool using chGuardedPoolAllocTimeout().
+ * - [10.2.3] Now must be empty.
+ * - [10.2.4] Adding the objects to the pool using chGuardedPoolFree().
+ * - [10.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
+ * again.
+ * - [10.2.6] Now must be empty again.
* .
*/
+static void test_010_002_setup(void) {
+ chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
+}
+
static void test_010_002_execute(void) {
- void *p1;
- size_t total_size, largest_size;
+ unsigned i;
- /* [10.2.1] Single block allocation using chHeapAlloc() then the
- block is freed using chHeapFree(), must not fail.*/
+ /* [10.2.1] Adding the objects to the pool using
+ chGuardedPoolLoadArray().*/
test_set_step(1);
{
- (void)chHeapStatus(NULL, &total_size, &largest_size);
- p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
- test_assert(p1 != NULL, "allocation failed");
- chHeapFree(p1);
+ chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE);
}
- /* [10.2.2] Testing allocation failure.*/
+ /* [10.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/
test_set_step(2);
{
- p1 = chHeapAlloc(NULL, (size_t)-256);
- test_assert(p1 == NULL, "allocation not failed");
+ for (i = 0; i < MEMORY_POOL_SIZE; i++)
+ test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
+ }
+
+ /* [10.2.3] Now must be empty.*/
+ test_set_step(3);
+ {
+ test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
+ }
+
+ /* [10.2.4] Adding the objects to the pool using
+ chGuardedPoolFree().*/
+ test_set_step(4);
+ {
+ for (i = 0; i < MEMORY_POOL_SIZE; i++)
+ chGuardedPoolFree(&gmp1, &objects[i]);
+ }
+
+ /* [10.2.5] Emptying the pool using chGuardedPoolAllocTimeout()
+ again.*/
+ test_set_step(5);
+ {
+ for (i = 0; i < MEMORY_POOL_SIZE; i++)
+ test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty");
+ }
+
+ /* [10.2.6] Now must be empty again.*/
+ test_set_step(6);
+ {
+ test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty");
}
}
static const testcase_t test_010_002 = {
- "Default Heap",
- NULL,
+ "Loading and emptying a guarded memory pool without waiting",
+ test_010_002_setup,
NULL,
test_010_002_execute
};
+#endif /* CH_CFG_USE_SEMAPHORES */
+
+#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
+/**
+ * @page test_010_003 [10.3] Guarded Memory Pools timeout
+ *
+ * <h2>Description</h2>
+ * The timeout features for the Guarded Memory Pools is tested.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_SEMAPHORES
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [10.3.1] Trying to allocate with 100mS timeout, must fail because
+ * the pool is empty.
+ * .
+ */
+
+static void test_010_003_setup(void) {
+ chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t));
+}
+
+static void test_010_003_execute(void) {
+
+ /* [10.3.1] Trying to allocate with 100mS timeout, must fail because
+ the pool is empty.*/
+ test_set_step(1);
+ {
+ test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty");
+ }
+}
+
+static const testcase_t test_010_003 = {
+ "Guarded Memory Pools timeout",
+ test_010_003_setup,
+ NULL,
+ test_010_003_execute
+};
+#endif /* CH_CFG_USE_SEMAPHORES */
/****************************************************************************
* Exported data.
****************************************************************************/
/**
- * @brief Memory Heaps.
+ * @brief Memory Pools.
*/
const testcase_t * const test_sequence_010[] = {
&test_010_001,
+#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
&test_010_002,
+#endif
+#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
+ &test_010_003,
+#endif
NULL
};
-#endif /* CH_CFG_USE_HEAP */
+#endif /* CH_CFG_USE_MEMPOOLS */
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
*
* <h2>Description</h2>
- * This module implements the test sequence for the dynamic thread
- * creation APIs.
+ * This sequence tests the ChibiOS/RT functionalities related to memory
+ * heaps.
*
* <h2>Conditions</h2>
* This sequence is only executed if the following preprocessor condition
* evaluates to true:
- * - CH_CFG_USE_DYNAMIC
+ * - CH_CFG_USE_HEAP
* .
*
* <h2>Test Cases</h2>
@@ -42,243 +42,231 @@
* .
*/
-#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
+#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
/****************************************************************************
* Shared code.
****************************************************************************/
-#if CH_CFG_USE_HEAP
-static memory_heap_t heap1;
-#endif
-#if CH_CFG_USE_MEMPOOLS
-static memory_pool_t mp1;
-#endif
-
-static THD_FUNCTION(dyn_thread1, p) {
+#define ALLOC_SIZE 16
+#define HEAP_SIZE (ALLOC_SIZE * 8)
- test_emit_token(*(char *)p);
-}
+memory_heap_t test_heap;
/****************************************************************************
* Test cases.
****************************************************************************/
-#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
/**
- * @page test_011_001 [11.1] Threads creation from Memory Heap
+ * @page test_011_001 [11.1] Allocation and fragmentation
*
* <h2>Description</h2>
- * Two threads are started by allocating the memory from the Memory
- * Heap then a third thread is started with a huge stack
- * requirement.<br> The test expects the first two threads to
- * successfully start and the third one to fail.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_HEAP
- * .
+ * Series of allocations/deallocations are performed in carefully
+ * designed sequences in order to stimulate all the possible code paths
+ * inside the allocator. The test expects to find the heap back to the
+ * initial status after each sequence.
*
* <h2>Test Steps</h2>
- * - [11.1.1] Getting base priority for threads.
- * - [11.1.2] Getting heap info before the test.
- * - [11.1.3] Creating thread 1, it is expected to succeed.
- * - [11.1.4] Creating thread 2, it is expected to succeed.
- * - [11.1.5] Creating thread 3, it is expected to fail.
- * - [11.1.6] Letting threads execute then checking the start order and
- * freeing memory.
- * - [11.1.7] Getting heap info again for verification.
+ * - [11.1.1] Testing initial conditions, the heap must not be
+ * fragmented and one free block present.
+ * - [11.1.2] Trying to allocate an block bigger than available space,
+ * an error is expected.
+ * - [11.1.3] Single block allocation using chHeapAlloc() then the
+ * block is freed using chHeapFree(), must not fail.
+ * - [11.1.4] Using chHeapStatus() to assess the heap state. There must
+ * be at least one free block of sufficient size.
+ * - [11.1.5] Allocating then freeing in the same order.
+ * - [11.1.6] Allocating then freeing in reverse order.
+ * - [11.1.7] Small fragments handling. Checking the behavior when
+ * allocating blocks with size not multiple of alignment unit.
+ * - [11.1.8] Skipping a fragment, the first fragment in the list is
+ * too small so the allocator must pick the second one.
+ * - [11.1.9] Allocating the whole available space.
+ * - [11.1.10] Testing final conditions. The heap geometry must be the
+ * same than the one registered at beginning.
* .
*/
static void test_011_001_setup(void) {
- chHeapObjectInit(&heap1, test_buffer, sizeof test_buffer);
+ chHeapObjectInit(&test_heap, test_buffer, sizeof(test_buffer));
}
static void test_011_001_execute(void) {
- size_t n1, total1, largest1;
- size_t n2, total2, largest2;
- tprio_t prio;
+ void *p1, *p2, *p3;
+ size_t n, sz;
- /* [11.1.1] Getting base priority for threads.*/
+ /* [11.1.1] Testing initial conditions, the heap must not be
+ fragmented and one free block present.*/
test_set_step(1);
{
- prio = chThdGetPriorityX();
+ test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented");
}
- /* [11.1.2] Getting heap info before the test.*/
+ /* [11.1.2] Trying to allocate an block bigger than available space,
+ an error is expected.*/
test_set_step(2);
{
- n1 = chHeapStatus(&heap1, &total1, &largest1);
- test_assert(n1 == 1, "heap fragmented");
+ p1 = chHeapAlloc(&test_heap, sizeof test_buffer * 2);
+ test_assert(p1 == NULL, "allocation not failed");
}
- /* [11.1.3] Creating thread 1, it is expected to succeed.*/
+ /* [11.1.3] Single block allocation using chHeapAlloc() then the
+ block is freed using chHeapFree(), must not fail.*/
test_set_step(3);
{
- threads[0] = chThdCreateFromHeap(&heap1,
- THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
- "dyn1",
- prio-1, dyn_thread1, "A");
- test_assert(threads[0] != NULL, "thread creation failed");
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ test_assert(p1 != NULL, "allocation failed");
+ chHeapFree(p1);
}
- /* [11.1.4] Creating thread 2, it is expected to succeed.*/
+ /* [11.1.4] Using chHeapStatus() to assess the heap state. There must
+ be at least one free block of sufficient size.*/
test_set_step(4);
{
- threads[1] = chThdCreateFromHeap(&heap1,
- THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
- "dyn2",
- prio-2, dyn_thread1, "B");
- test_assert(threads[1] != NULL, "thread creation failed");
+ size_t total_size, largest_size;
+
+ n = chHeapStatus(&test_heap, &total_size, &largest_size);
+ test_assert(n == 1, "missing free block");
+ test_assert(total_size >= ALLOC_SIZE, "unexpected heap state");
+ test_assert(total_size == largest_size, "unexpected heap state");
}
- /* [11.1.5] Creating thread 3, it is expected to fail.*/
+ /* [11.1.5] Allocating then freeing in the same order.*/
test_set_step(5);
{
- threads[2] = chThdCreateFromHeap(&heap1,
- THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE * 1024),
- "dyn3",
- prio-3, dyn_thread1, "C");
- test_assert(threads[2] == NULL, "thread creation not failed");
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ chHeapFree(p1); /* Does not merge.*/
+ chHeapFree(p2); /* Merges backward.*/
+ chHeapFree(p3); /* Merges both sides.*/
+ test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
}
- /* [11.1.6] Letting threads execute then checking the start order and
- freeing memory.*/
+ /* [11.1.6] Allocating then freeing in reverse order.*/
test_set_step(6);
{
- test_wait_threads();
- test_assert_sequence("AB", "invalid sequence");
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ p3 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ chHeapFree(p3); /* Merges forward.*/
+ chHeapFree(p2); /* Merges forward.*/
+ chHeapFree(p1); /* Merges forward.*/
+ test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
}
- /* [11.1.7] Getting heap info again for verification.*/
+ /* [11.1.7] Small fragments handling. Checking the behavior when
+ allocating blocks with size not multiple of alignment unit.*/
test_set_step(7);
{
- n2 = chHeapStatus(&heap1, &total2, &largest2);
- test_assert(n1 == n2, "fragmentation changed");
- test_assert(total1 == total2, "total free space changed");
- test_assert(largest1 == largest2, "largest fragment size changed");
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1);
+ p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ chHeapFree(p1);
+ test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ /* Note, the first situation happens when the alignment size is smaller
+ than the header size, the second in the other cases.*/
+ test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) ||
+ (chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
+ chHeapFree(p2);
+ chHeapFree(p1);
+ test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
+ }
+
+ /* [11.1.8] Skipping a fragment, the first fragment in the list is
+ too small so the allocator must pick the second one.*/
+ test_set_step(8);
+ {
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ p2 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ chHeapFree(p1);
+ test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/
+ chHeapFree(p1);
+ chHeapFree(p2);
+ test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
+ }
+
+ /* [11.1.9] Allocating the whole available space.*/
+ test_set_step(9);
+ {
+ (void)chHeapStatus(&test_heap, &n, NULL);
+ p1 = chHeapAlloc(&test_heap, n);
+ test_assert(p1 != NULL, "allocation failed");
+ test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty");
+ chHeapFree(p1);
+ }
+
+ /* [11.1.10] Testing final conditions. The heap geometry must be the
+ same than the one registered at beginning.*/
+ test_set_step(10);
+ {
+ test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
+ test_assert(n == sz, "size changed");
}
}
static const testcase_t test_011_001 = {
- "Threads creation from Memory Heap",
+ "Allocation and fragmentation",
test_011_001_setup,
NULL,
test_011_001_execute
};
-#endif /* CH_CFG_USE_HEAP */
-#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
/**
- * @page test_011_002 [11.2] Threads creation from Memory Pool
+ * @page test_011_002 [11.2] Default Heap
*
* <h2>Description</h2>
- * Five thread creation are attempted from a pool containing only four
- * elements.<br> The test expects the first four threads to
- * successfully start and the last one to fail.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_MEMPOOLS
- * .
+ * The default heap is pre-allocated in the system. We test base
+ * functionality.
*
* <h2>Test Steps</h2>
- * - [11.2.1] Adding four working areas to the pool.
- * - [11.2.2] Getting base priority for threads.
- * - [11.2.3] Creating the five threads.
- * - [11.2.4] Testing that only the fifth thread creation failed.
- * - [11.2.5] Letting them run, free the memory then checking the
- * execution sequence.
- * - [11.2.6] Testing that the pool contains four elements again.
+ * - [11.2.1] Single block allocation using chHeapAlloc() then the
+ * block is freed using chHeapFree(), must not fail.
+ * - [11.2.2] Testing allocation failure.
* .
*/
-static void test_011_002_setup(void) {
- chPoolObjectInit(&mp1, THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), NULL);
-}
-
static void test_011_002_execute(void) {
- unsigned i;
- tprio_t prio;
+ void *p1;
+ size_t total_size, largest_size;
- /* [11.2.1] Adding four working areas to the pool.*/
+ /* [11.2.1] Single block allocation using chHeapAlloc() then the
+ block is freed using chHeapFree(), must not fail.*/
test_set_step(1);
{
- for (i = 0; i < 4; i++)
- chPoolFree(&mp1, wa[i]);
+ (void)chHeapStatus(NULL, &total_size, &largest_size);
+ p1 = chHeapAlloc(&test_heap, ALLOC_SIZE);
+ test_assert(p1 != NULL, "allocation failed");
+ chHeapFree(p1);
}
- /* [11.2.2] Getting base priority for threads.*/
+ /* [11.2.2] Testing allocation failure.*/
test_set_step(2);
{
- prio = chThdGetPriorityX();
- }
-
- /* [11.2.3] Creating the five threads.*/
- test_set_step(3);
- {
- threads[0] = chThdCreateFromMemoryPool(&mp1, "dyn1", prio-1, dyn_thread1, "A");
- threads[1] = chThdCreateFromMemoryPool(&mp1, "dyn2", prio-2, dyn_thread1, "B");
- threads[2] = chThdCreateFromMemoryPool(&mp1, "dyn3", prio-3, dyn_thread1, "C");
- threads[3] = chThdCreateFromMemoryPool(&mp1, "dyn4", prio-4, dyn_thread1, "D");
- threads[4] = chThdCreateFromMemoryPool(&mp1, "dyn5", prio-5, dyn_thread1, "E");
- }
-
- /* [11.2.4] Testing that only the fifth thread creation failed.*/
- test_set_step(4);
- {
- test_assert((threads[0] != NULL) &&
- (threads[1] != NULL) &&
- (threads[2] != NULL) &&
- (threads[3] != NULL),
- "thread creation failed");
- test_assert(threads[4] == NULL,
- "thread creation not failed");
- }
-
- /* [11.2.5] Letting them run, free the memory then checking the
- execution sequence.*/
- test_set_step(5);
- {
- test_wait_threads();
- test_assert_sequence("ABCD", "invalid sequence");
- }
-
- /* [11.2.6] Testing that the pool contains four elements again.*/
- test_set_step(6);
- {
- for (i = 0; i < 4; i++)
- test_assert(chPoolAlloc(&mp1) != NULL, "pool list empty");
- test_assert(chPoolAlloc(&mp1) == NULL, "pool list not empty");
+ p1 = chHeapAlloc(NULL, (size_t)-256);
+ test_assert(p1 == NULL, "allocation not failed");
}
}
static const testcase_t test_011_002 = {
- "Threads creation from Memory Pool",
- test_011_002_setup,
+ "Default Heap",
+ NULL,
NULL,
test_011_002_execute
};
-#endif /* CH_CFG_USE_MEMPOOLS */
/****************************************************************************
* Exported data.
****************************************************************************/
/**
- * @brief Dynamic threads.
+ * @brief Memory Heaps.
*/
const testcase_t * const test_sequence_011[] = {
-#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
&test_011_001,
-#endif
-#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
&test_011_002,
-#endif
NULL
};
-#endif /* CH_CFG_USE_DYNAMIC */
+#endif /* CH_CFG_USE_HEAP */
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
*
* <h2>Description</h2>
- * 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.<br> 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.
+ *
+ * <h2>Conditions</h2>
+ * This sequence is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_DYNAMIC
+ * .
*
* <h2>Test Cases</h2>
* - @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;
-#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();
+#if CH_CFG_USE_HEAP
+static memory_heap_t heap1;
#endif
- } while (chVTIsSystemTimeWithinX(start, end));
- (void)chMsgSend(tp, 0);
- return n;
-}
+#if CH_CFG_USE_MEMPOOLS
+static memory_pool_t mp1;
#endif
-static THD_FUNCTION(bmk_thread3, p) {
-
- chThdExit((msg_t)p);
-}
-
-static THD_FUNCTION(bmk_thread4, p) {
- msg_t msg;
- thread_t *self = chThdGetSelfX();
+static THD_FUNCTION(dyn_thread1, p) {
- (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__)
-/**
- * @page test_012_001 [12.1] Messages performance #1
- *
- * <h2>Description</h2>
- * 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.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_MESSAGES
- * .
- *
- * <h2>Test Steps</h2>
- * - [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.
- * .
- */
-
-static void test_012_001_execute(void) {
- uint32_t n;
-
- /* [12.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);
- }
-
- /* [12.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();
- }
-
- /* [12.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_012_001 = {
- "Messages performance #1",
- NULL,
- NULL,
- test_012_001_execute
-};
-#endif /* CH_CFG_USE_MESSAGES */
-
-#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
+#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
/**
- * @page test_012_002 [12.2] Messages performance #2
+ * @page test_012_001 [12.1] Threads creation from Memory Heap
*
* <h2>Description</h2>
- * 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.
+ * Two threads are started by allocating the memory from the Memory
+ * Heap then a third thread is started with a huge stack
+ * requirement.<br> The test expects the first two threads to
+ * successfully start and the third one to fail.
*
* <h2>Conditions</h2>
* This test is only executed if the following preprocessor condition
* evaluates to true:
- * - CH_CFG_USE_MESSAGES
+ * - CH_CFG_USE_HEAP
* .
*
* <h2>Test Steps</h2>
- * - [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.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_002_execute(void) {
- uint32_t n;
-
- /* [12.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);
- }
-
- /* [12.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();
- }
-
- /* [12.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 void test_012_001_setup(void) {
+ chHeapObjectInit(&heap1, test_buffer, sizeof test_buffer);
}
-static const testcase_t test_012_002 = {
- "Messages performance #2",
- NULL,
- 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
- *
- * <h2>Description</h2>
- * 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.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_MESSAGES
- * .
- *
- * <h2>Test Steps</h2>
- * - [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
- *
- * <h2>Description</h2>
- * 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.<br> The Context Switch performance is calculated by
- * measuring the number of iterations after a second of continuous
- * operations.
- *
- * <h2>Test Steps</h2>
- * - [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
- *
- * <h2>Description</h2>
- * Threads are continuously created and terminated into a loop. A full
- * chThdCreateStatic() / @p chThdExit() / @p chThdWait() cycle is
- * performed in each iteration.<br> The performance is calculated by
- * measuring the number of iterations after a second of continuous
- * operations.
- *
- * <h2>Test Steps</h2>
- * - [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
- *
- * <h2>Description</h2>
- * 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.<br> The performance is calculated by measuring
- * the number of iterations after a second of continuous operations.
- *
- * <h2>Test Steps</h2>
- * - [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
- *
- * <h2>Description</h2>
- * Five threads are created and atomically rescheduled by resetting the
- * semaphore where they are waiting on. The operation is performed into
- * a continuous loop.<br> The performance is calculated by measuring
- * the number of iterations after a second of continuous operations.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_SEMAPHORES
- * .
- *
- * <h2>Test Steps</h2>
- * - [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;
+static void test_012_001_execute(void) {
+ size_t n1, total1, largest1;
+ size_t n2, total2, largest2;
+ tprio_t prio;
- /* [12.7.1] Five threads are created at higher priority that
- immediately enqueue on a semaphore.*/
+ /* [12.1.1] Getting base priority for threads.*/
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);
+ prio = chThdGetPriorityX();
}
- /* [12.7.2] The semaphore is reset waking up the five threads. The
- operation is repeated continuously in a one-second time window.*/
+ /* [12.1.2] Getting heap info before the test.*/
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));
+ n1 = chHeapStatus(&heap1, &total1, &largest1);
+ test_assert(n1 == 1, "heap fragmented");
}
- /* [12.7.3] The five threads are terminated.*/
+ /* [12.1.3] Creating thread 1, it is expected to succeed.*/
test_set_step(3);
{
- test_terminate_threads();
- chSemReset(&sem1, 0);
- test_wait_threads();
+ 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.7.4] The score is printed.*/
+ /* [12.1.4] Creating thread 2, it is expected to succeed.*/
test_set_step(4);
{
- test_print("--- Score : ");
- test_printn(n);
- test_print(" reschedules/S, ");
- test_printn(n * 6);
- test_println(" ctxswc/S");
+ 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");
}
-}
-
-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
- *
- * <h2>Description</h2>
- * Five threads are created at equal priority, each thread just
- * increases a variable and yields.<br> The performance is calculated
- * by measuring the number of iterations after a second of continuous
- * operations.
- *
- * <h2>Test Steps</h2>
- * - [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);
+ /* [12.1.5] Creating thread 3, it is expected to fail.*/
+ test_set_step(5);
{
- 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);
+ 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.8.2] Waiting one second then terminating the 5 threads.*/
- test_set_step(2);
+ /* [12.1.6] Letting threads execute then checking the start order and
+ freeing memory.*/
+ test_set_step(6);
{
- chThdSleepSeconds(1);
- test_terminate_threads();
test_wait_threads();
+ test_assert_sequence("AB", "invalid sequence");
}
- /* [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
- *
- * <h2>Description</h2>
- * A virtual timer is set and immediately reset into a continuous
- * loop.<br> The performance is calculated by measuring the number of
- * iterations after a second of continuous operations.
- *
- * <h2>Test Steps</h2>
- * - [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
- *
- * <h2>Description</h2>
- * A counting semaphore is taken/released into a continuous loop, no
- * Context Switch happens because the counter is always non
- * negative.<br> The performance is calculated by measuring the number
- * of iterations after a second of continuous operations.
- *
- * <h2>Conditions</h2>
- * This test is only executed if the following preprocessor condition
- * evaluates to true:
- * - CH_CFG_USE_SEMAPHORES
- * .
- *
- * <h2>Test Steps</h2>
- * - [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);
+ /* [12.1.7] Getting heap info again for verification.*/
+ test_set_step(7);
{
- test_print("--- Score : ");
- test_printn(n * 4);
- test_println(" wait+signal/S");
+ 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_010 = {
- "Semaphores wait/signal performance",
- test_012_010_setup,
+static const testcase_t test_012_001 = {
+ "Threads creation from Memory Heap",
+ test_012_001_setup,
NULL,
- test_012_010_execute
+ test_012_001_execute
};
-#endif /* CH_CFG_USE_SEMAPHORES */
+#endif /* CH_CFG_USE_HEAP */
-#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
+#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
/**
- * @page test_012_011 [12.11] Mutexes lock/unlock performance
+ * @page test_012_002 [12.2] Threads creation from Memory Pool
*
* <h2>Description</h2>
- * A mutex is locked/unlocked into a continuous loop, no Context Switch
- * happens because there are no other threads asking for the mutex.<br>
- * The performance is calculated by measuring the number of iterations
- * after a second of continuous operations.
+ * Five thread creation are attempted from a pool containing only four
+ * elements.<br> The test expects the first four threads to
+ * successfully start and the last one to fail.
*
* <h2>Conditions</h2>
* This test is only executed if the following preprocessor condition
* evaluates to true:
- * - CH_CFG_USE_MUTEXES
+ * - CH_CFG_USE_MEMPOOLS
* .
*
* <h2>Test Steps</h2>
- * - [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.
+ * - [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_011_setup(void) {
- chMtxObjectInit(&mtx1);
+static void test_012_002_setup(void) {
+ chPoolObjectInit(&mp1, THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), NULL);
}
-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
- *
- * <h2>Description</h2>
- * The memory size of the various kernel objects is printed.
- *
- * <h2>Test Steps</h2>
- * - [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) {
+static void test_012_002_execute(void) {
+ unsigned i;
+ tprio_t prio;
- /* [12.12.1] The size of the system area is printed.*/
+ /* [12.2.1] Adding four working areas to the pool.*/
test_set_step(1);
{
- test_print("--- System: ");
- test_printn(sizeof(ch_system_t));
- test_println(" bytes");
+ for (i = 0; i < 4; i++)
+ chPoolFree(&mp1, wa[i]);
}
- /* [12.12.2] The size of a thread structure is printed.*/
+ /* [12.2.2] Getting base priority for threads.*/
test_set_step(2);
{
- test_print("--- Thread: ");
- test_printn(sizeof(thread_t));
- test_println(" bytes");
+ prio = chThdGetPriorityX();
}
- /* [12.12.3] The size of a virtual timer structure is printed.*/
+ /* [12.2.3] Creating the five threads.*/
test_set_step(3);
{
- test_print("--- Timer : ");
- test_printn(sizeof(virtual_timer_t));
- test_println(" bytes");
+ 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.12.4] The size of a semaphore structure is printed.*/
+ /* [12.2.4] Testing that only the fifth thread creation failed.*/
test_set_step(4);
{
-#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
- test_print("--- Semaph: ");
- test_printn(sizeof(semaphore_t));
- test_println(" bytes");
-#endif
+ 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.12.5] The size of a mutex is printed.*/
+ /* [12.2.5] Letting them run, free the memory then checking the
+ execution sequence.*/
test_set_step(5);
{
-#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
- test_print("--- Mutex : ");
- test_printn(sizeof(mutex_t));
- test_println(" bytes");
-#endif
+ test_wait_threads();
+ test_assert_sequence("ABCD", "invalid sequence");
}
- /* [12.12.6] The size of a condition variable is printed.*/
+ /* [12.2.6] Testing that the pool contains four elements again.*/
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
+ 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_012 = {
- "RAM Footprint",
- NULL,
+static const testcase_t test_012_002 = {
+ "Threads creation from Memory Pool",
+ test_012_002_setup,
NULL,
- test_012_012_execute
+ test_012_002_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
+ *
+ * <h2>Description</h2>
+ * 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.<br> 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.
+ *
+ * <h2>Test Cases</h2>
+ * - @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
+ *
+ * <h2>Description</h2>
+ * 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.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_MESSAGES
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * 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.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_MESSAGES
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * 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.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_MESSAGES
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * 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.<br> The Context Switch performance is calculated by
+ * measuring the number of iterations after a second of continuous
+ * operations.
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * Threads are continuously created and terminated into a loop. A full
+ * chThdCreateStatic() / @p chThdExit() / @p chThdWait() cycle is
+ * performed in each iteration.<br> The performance is calculated by
+ * measuring the number of iterations after a second of continuous
+ * operations.
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * 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.<br> The performance is calculated by measuring
+ * the number of iterations after a second of continuous operations.
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * Five threads are created and atomically rescheduled by resetting the
+ * semaphore where they are waiting on. The operation is performed into
+ * a continuous loop.<br> The performance is calculated by measuring
+ * the number of iterations after a second of continuous operations.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_SEMAPHORES
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * Five threads are created at equal priority, each thread just
+ * increases a variable and yields.<br> The performance is calculated
+ * by measuring the number of iterations after a second of continuous
+ * operations.
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * A virtual timer is set and immediately reset into a continuous
+ * loop.<br> The performance is calculated by measuring the number of
+ * iterations after a second of continuous operations.
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * A counting semaphore is taken/released into a continuous loop, no
+ * Context Switch happens because the counter is always non
+ * negative.<br> The performance is calculated by measuring the number
+ * of iterations after a second of continuous operations.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_SEMAPHORES
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * A mutex is locked/unlocked into a continuous loop, no Context Switch
+ * happens because there are no other threads asking for the mutex.<br>
+ * The performance is calculated by measuring the number of iterations
+ * after a second of continuous operations.
+ *
+ * <h2>Conditions</h2>
+ * This test is only executed if the following preprocessor condition
+ * evaluates to true:
+ * - CH_CFG_USE_MUTEXES
+ * .
+ *
+ * <h2>Test Steps</h2>
+ * - [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
+ *
+ * <h2>Description</h2>
+ * The memory size of the various kernel objects is printed.
+ *
+ * <h2>Test Steps</h2>
+ * - [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 \