git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@13192 27425a3e-05d8-49a3-a47f-9c15f0e5edd8
This commit is contained in:
parent
58cd6d0497
commit
00a5875467
|
@ -94,7 +94,7 @@ static inline msg_t i2c_check_arbitration(I2CDriver *i2cp) {
|
|||
|
||||
static inline msg_t i2c_check_timeout(I2CDriver *i2cp) {
|
||||
|
||||
if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), i2cp->start, i2cp->end)) {
|
||||
if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), i2cp->start, i2cp->end)) {
|
||||
i2c_write_stop(i2cp);
|
||||
return MSG_TIMEOUT;
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ static inline msg_t i2c_check_timeout(I2CDriver *i2cp) {
|
|||
static msg_t i2c_wait_clock(I2CDriver *i2cp) {
|
||||
|
||||
while (palReadLine(i2cp->config->scl) == PAL_LOW) {
|
||||
if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), i2cp->start, i2cp->end)) {
|
||||
if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), i2cp->start, i2cp->end)) {
|
||||
return MSG_TIMEOUT;
|
||||
}
|
||||
i2c_delay(i2cp);
|
||||
|
@ -347,18 +347,18 @@ void i2c_lld_stop(I2CDriver *i2cp) {
|
|||
*/
|
||||
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
|
||||
uint8_t *rxbuf, size_t rxbytes,
|
||||
systime_t timeout) {
|
||||
sysinterval_t timeout) {
|
||||
|
||||
/* Setting timeout fields.*/
|
||||
i2cp->start = osalOsGetSystemTimeX();
|
||||
i2cp->end = i2cp->start;
|
||||
if (timeout != TIME_INFINITE) {
|
||||
i2cp->end += timeout;
|
||||
i2cp->end = osalTimeAddX(i2cp->start, timeout);
|
||||
}
|
||||
|
||||
CHECK_ERROR(i2c_write_start(i2cp));
|
||||
|
||||
/* Sending anddress and mode.*/
|
||||
/* Sending address and mode.*/
|
||||
CHECK_ERROR(i2c_write_header(i2cp, addr, true));
|
||||
|
||||
do {
|
||||
|
@ -399,19 +399,19 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
|
|||
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
|
||||
const uint8_t *txbuf, size_t txbytes,
|
||||
uint8_t *rxbuf, size_t rxbytes,
|
||||
systime_t timeout) {
|
||||
sysinterval_t timeout) {
|
||||
|
||||
/* Setting timeout fields.*/
|
||||
i2cp->start = osalOsGetSystemTimeX();
|
||||
i2cp->end = i2cp->start;
|
||||
if (timeout != TIME_INFINITE) {
|
||||
i2cp->end += timeout;
|
||||
i2cp->end = osalTimeAddX(i2cp->start, timeout);
|
||||
}
|
||||
|
||||
/* send start condition */
|
||||
CHECK_ERROR(i2c_write_start(i2cp));
|
||||
|
||||
/* Sending anddress and mode.*/
|
||||
/* Sending address and mode.*/
|
||||
CHECK_ERROR(i2c_write_header(i2cp, addr, false));
|
||||
|
||||
do {
|
||||
|
|
|
@ -217,10 +217,10 @@ extern "C" {
|
|||
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
|
||||
const uint8_t *txbuf, size_t txbytes,
|
||||
uint8_t *rxbuf, size_t rxbytes,
|
||||
systime_t timeout);
|
||||
sysinterval_t timeout);
|
||||
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
|
||||
uint8_t *rxbuf, size_t rxbytes,
|
||||
systime_t timeout);
|
||||
sysinterval_t timeout);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -703,7 +703,8 @@ static inline bool osalTimeIsInRangeX(systime_t time,
|
|||
systime_t start,
|
||||
systime_t end) {
|
||||
|
||||
return (bool)((time - start) < (end - start));
|
||||
return (bool)((systime_t)((systime_t)time - (systime_t)start) <=
|
||||
(systime_t)((systime_t)end - (systime_t)start - (systime_t)1));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -639,7 +639,8 @@ static inline bool osalTimeIsInRangeX(systime_t time,
|
|||
systime_t start,
|
||||
systime_t end) {
|
||||
|
||||
return (bool)((time - start) < (end - start));
|
||||
return (bool)((systime_t)((systime_t)time - (systime_t)start) <=
|
||||
(systime_t)((systime_t)end - (systime_t)start - (systime_t)1));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1278,23 +1278,6 @@ struct nil_system {
|
|||
#define chTimeDiffX(start, end) \
|
||||
((sysinterval_t)((systime_t)((systime_t)(end) - (systime_t)(start))))
|
||||
|
||||
/**
|
||||
* @brief Checks if the specified time is within the specified time range.
|
||||
* @note When start==end then the function returns always true because the
|
||||
* whole time range is specified.
|
||||
*
|
||||
* @param[in] time the time to be verified
|
||||
* @param[in] start the start of the time window (inclusive)
|
||||
* @param[in] end the end of the time window (non inclusive)
|
||||
* @retval true current time within the specified time window.
|
||||
* @retval false current time not within the specified time window.
|
||||
*
|
||||
* @xclass
|
||||
*/
|
||||
#define chTimeIsInRangeX(time, start, end) \
|
||||
((bool)((systime_t)((systime_t)(time) - (systime_t)(start)) < \
|
||||
(systime_t)((systime_t)(end) - (systime_t)(start))))
|
||||
|
||||
/**
|
||||
* @brief Function parameters check.
|
||||
* @details If the condition check fails then the kernel panics and halts.
|
||||
|
@ -1392,6 +1375,7 @@ extern "C" {
|
|||
void chSchDoReschedule(void);
|
||||
void chSchRescheduleS(void);
|
||||
msg_t chSchGoSleepTimeoutS(tstate_t newstate, sysinterval_t timeout);
|
||||
bool chTimeIsInRangeX(systime_t time, systime_t start, systime_t end);
|
||||
thread_t *chThdCreateI(const thread_descriptor_t *tdp);
|
||||
thread_t *chThdCreate(const thread_descriptor_t *tdp);
|
||||
void chThdExit(msg_t msg);
|
||||
|
|
|
@ -722,6 +722,25 @@ msg_t chSchGoSleepTimeoutS(tstate_t newstate, sysinterval_t timeout) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the specified time is within the specified time range.
|
||||
* @note When start==end then the function returns always true because the
|
||||
* whole time range is specified.
|
||||
*
|
||||
* @param[in] time the time to be verified
|
||||
* @param[in] start the start of the time window (inclusive)
|
||||
* @param[in] end the end of the time window (non inclusive)
|
||||
* @retval true current time within the specified time window.
|
||||
* @retval false current time not within the specified time window.
|
||||
*
|
||||
* @xclass
|
||||
*/
|
||||
bool chTimeIsInRangeX(systime_t time, systime_t start, systime_t end) {
|
||||
|
||||
return (bool)((systime_t)((systime_t)(time) - (systime_t)(start)) <=
|
||||
(systime_t)((systime_t)(end) - (systime_t)(start) - (systime_t)1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a new thread into a static memory area.
|
||||
* @details The new thread is initialized and make ready to execute.
|
||||
|
|
|
@ -481,8 +481,8 @@ static inline bool chTimeIsInRangeX(systime_t time,
|
|||
systime_t start,
|
||||
systime_t end) {
|
||||
|
||||
return (bool)((systime_t)((systime_t)time - (systime_t)start) <
|
||||
(systime_t)((systime_t)end - (systime_t)start));
|
||||
return (bool)((systime_t)((systime_t)time - (systime_t)start) <=
|
||||
(systime_t)((systime_t)end - (systime_t)start - (systime_t)1));
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -140,6 +140,10 @@
|
|||
- HAL: Added a new interface for range-finder devices (used by EX).
|
||||
- HAL: Added mcuconf.h updater tool for STM32F407 (backported to 19.1.1).
|
||||
- NIL: Integrated NIL 4.0.
|
||||
- FIX: Fixed I2C fallback driver broken (bug #1061)
|
||||
(not yet)(backported to 19.1.4)(backported to 18.2.3).
|
||||
- FIX: Fixed bug in chVTGetSystemTimeX() (bug #1060)
|
||||
(not yet)(backported to 19.1.4)(backported to 18.2.3).
|
||||
- FIX: Fixed STM32 ADC1 sample time macros (bug #1059)
|
||||
(backported to 19.1.4)(backported to 18.2.3).
|
||||
- FIX: Fixed STM32 ADCv1 error callback disabled on some devices (bug #1058)
|
||||
|
|
|
@ -279,10 +279,10 @@ test_println("");]]></value>
|
|||
<value>Internal Tests</value>
|
||||
</type>
|
||||
<brief>
|
||||
<value>Threads Functionality.</value>
|
||||
<value>Time and Intervals Functionality.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>This sequence tests the ChibiOS/NIL functionalities related to threading.</value>
|
||||
<value>This sequence tests the ChibiOS/NIL functionalities related to time and intervals management.</value>
|
||||
</description>
|
||||
<condition>
|
||||
<value />
|
||||
|
@ -328,6 +328,115 @@ while (time == chVTGetSystemTimeX()) {
|
|||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
<case>
|
||||
<brief>
|
||||
<value>Time ranges functionality.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>The functionality of the API @p chTimeIsInRangeX() is tested.</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>Checking case where start == end, it must always evaluate as in range.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[
|
||||
bool b;
|
||||
|
||||
b = chTimeIsInRangeX((systime_t)0, (systime_t)0, (systime_t)0);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)-1, (systime_t)0, (systime_t)0);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)0, (systime_t)-1, (systime_t)-1);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)-1, (systime_t)-1, (systime_t)-1);
|
||||
test_assert(b == true, "not in range");
|
||||
]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>Checking boundaries for start < end.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[
|
||||
bool b;
|
||||
|
||||
b = chTimeIsInRangeX((systime_t)10, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)9, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == false, "in range");
|
||||
b = chTimeIsInRangeX((systime_t)99, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)100, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == false, "in range");
|
||||
]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>Checking boundaries for start > end.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[
|
||||
bool b;
|
||||
|
||||
b = chTimeIsInRangeX((systime_t)100, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)99, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == false, "in range");
|
||||
b = chTimeIsInRangeX((systime_t)9, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)10, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == false, "in range");
|
||||
]]></value>
|
||||
</code>
|
||||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
</cases>
|
||||
</sequence>
|
||||
<sequence>
|
||||
<type index="0">
|
||||
<value>Internal Tests</value>
|
||||
</type>
|
||||
<brief>
|
||||
<value>Threads Functionality.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>This sequence tests the ChibiOS/NIL functionalities related to threading.</value>
|
||||
</description>
|
||||
<condition>
|
||||
<value />
|
||||
</condition>
|
||||
<shared_code>
|
||||
<value><![CDATA[#include "ch.h"]]></value>
|
||||
</shared_code>
|
||||
<cases>
|
||||
<case>
|
||||
<brief>
|
||||
<value>Thread Sleep functionality.</value>
|
||||
|
|
|
@ -6,7 +6,8 @@ TESTSRC += ${CHIBIOS}/test/nil/source/test/nil_test_root.c \
|
|||
${CHIBIOS}/test/nil/source/test/nil_test_sequence_004.c \
|
||||
${CHIBIOS}/test/nil/source/test/nil_test_sequence_005.c \
|
||||
${CHIBIOS}/test/nil/source/test/nil_test_sequence_006.c \
|
||||
${CHIBIOS}/test/nil/source/test/nil_test_sequence_007.c
|
||||
${CHIBIOS}/test/nil/source/test/nil_test_sequence_007.c \
|
||||
${CHIBIOS}/test/nil/source/test/nil_test_sequence_008.c
|
||||
|
||||
# Required include directories
|
||||
TESTINC += ${CHIBIOS}/test/nil/source/test
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
* - @subpage nil_test_sequence_005
|
||||
* - @subpage nil_test_sequence_006
|
||||
* - @subpage nil_test_sequence_007
|
||||
* - @subpage nil_test_sequence_008
|
||||
* .
|
||||
*/
|
||||
|
||||
|
@ -51,17 +52,18 @@
|
|||
const testsequence_t * const nil_test_suite_array[] = {
|
||||
&nil_test_sequence_001,
|
||||
&nil_test_sequence_002,
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&nil_test_sequence_003,
|
||||
#endif
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&nil_test_sequence_004,
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
&nil_test_sequence_005,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
&nil_test_sequence_005,
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
&nil_test_sequence_006,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
&nil_test_sequence_007,
|
||||
#endif
|
||||
&nil_test_sequence_008,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "nil_test_sequence_005.h"
|
||||
#include "nil_test_sequence_006.h"
|
||||
#include "nil_test_sequence_007.h"
|
||||
#include "nil_test_sequence_008.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
|
|
|
@ -21,13 +21,13 @@
|
|||
* @file nil_test_sequence_002.c
|
||||
* @brief Test Sequence 002 code.
|
||||
*
|
||||
* @page nil_test_sequence_002 [2] Threads Functionality
|
||||
* @page nil_test_sequence_002 [2] Time and Intervals Functionality
|
||||
*
|
||||
* File: @ref nil_test_sequence_002.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/NIL functionalities related to
|
||||
* threading.
|
||||
* This sequence tests the ChibiOS/NIL functionalities related to time
|
||||
* and intervals management.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage nil_test_002_001
|
||||
|
@ -78,97 +78,73 @@ static const testcase_t nil_test_002_001 = {
|
|||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_002_002 [2.2] Thread Sleep functionality
|
||||
* @page nil_test_002_002 [2.2] Time ranges functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The functionality of @p chThdSleep() and derivatives is tested.
|
||||
* The functionality of the API @p chTimeIsInRangeX() is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [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.
|
||||
* - [2.2.1] Checking case where start == end, it must always evaluate
|
||||
* as in range.
|
||||
* - [2.2.2] Checking boundaries for start < end.
|
||||
* - [2.2.3] Checking boundaries for start > end.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_002_002_execute(void) {
|
||||
systime_t time;
|
||||
|
||||
/* [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.1] Checking case where start == end, it must always evaluate
|
||||
as in range.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleep(100);
|
||||
test_assert_time_window(chTimeAddX(time, 100),
|
||||
chTimeAddX(time, 100 + 1),
|
||||
"out of time window");
|
||||
bool b;
|
||||
|
||||
b = chTimeIsInRangeX((systime_t)0, (systime_t)0, (systime_t)0);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)-1, (systime_t)0, (systime_t)0);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)0, (systime_t)-1, (systime_t)-1);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)-1, (systime_t)-1, (systime_t)-1);
|
||||
test_assert(b == true, "not in range");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [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.2] Checking boundaries for start < end.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepMicroseconds(100000);
|
||||
test_assert_time_window(chTimeAddX(time, TIME_US2I(100000)),
|
||||
chTimeAddX(time, TIME_US2I(100000) + 1),
|
||||
"out of time window");
|
||||
bool b;
|
||||
|
||||
b = chTimeIsInRangeX((systime_t)10, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)9, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == false, "in range");
|
||||
b = chTimeIsInRangeX((systime_t)99, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)100, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == false, "in range");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [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.3] Checking boundaries for start > end.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepMilliseconds(100);
|
||||
test_assert_time_window(chTimeAddX(time, TIME_MS2I(100)),
|
||||
chTimeAddX(time, TIME_MS2I(100) + 1),
|
||||
"out of time window");
|
||||
bool b;
|
||||
|
||||
b = chTimeIsInRangeX((systime_t)100, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)99, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == false, "in range");
|
||||
b = chTimeIsInRangeX((systime_t)9, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)10, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == false, "in range");
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [2.2.4] The current system time is read then a sleep is performed
|
||||
for 1 second and on exit the system time is verified again.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepSeconds(1);
|
||||
test_assert_time_window(chTimeAddX(time, TIME_S2I(1)),
|
||||
chTimeAddX(time, TIME_S2I(1) + 1),
|
||||
"out of time window");
|
||||
}
|
||||
test_end_step(4);
|
||||
|
||||
/* [2.2.5] Function chThdSleepUntil() is tested with a timeline of
|
||||
"now" + 100 ticks.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepUntil(chTimeAddX(time, 100));
|
||||
test_assert_time_window(chTimeAddX(time, 100),
|
||||
chTimeAddX(time, 100 + 1),
|
||||
"out of time window");
|
||||
}
|
||||
test_end_step(5);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_002_002 = {
|
||||
"Thread Sleep functionality",
|
||||
"Time ranges functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_002_002_execute
|
||||
|
@ -188,9 +164,9 @@ const testcase_t * const nil_test_sequence_002_array[] = {
|
|||
};
|
||||
|
||||
/**
|
||||
* @brief Threads Functionality.
|
||||
* @brief Time and Intervals Functionality.
|
||||
*/
|
||||
const testsequence_t nil_test_sequence_002 = {
|
||||
"Threads Functionality",
|
||||
"Time and Intervals Functionality",
|
||||
nil_test_sequence_002_array
|
||||
};
|
||||
|
|
|
@ -21,268 +21,126 @@
|
|||
* @file nil_test_sequence_003.c
|
||||
* @brief Test Sequence 003 code.
|
||||
*
|
||||
* @page nil_test_sequence_003 [3] Semaphores
|
||||
* @page nil_test_sequence_003 [3] Threads Functionality
|
||||
*
|
||||
* File: @ref nil_test_sequence_003.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 nil_test_003_001
|
||||
* - @subpage nil_test_003_002
|
||||
* - @subpage nil_test_003_003
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
static thread_t *tp1;
|
||||
static bool terminate;
|
||||
static semaphore_t sem1, sem2;
|
||||
|
||||
/*
|
||||
* Signaler thread.
|
||||
*/
|
||||
static THD_FUNCTION(signaler, arg) {
|
||||
|
||||
(void)arg;
|
||||
|
||||
/* Initializing global resources.*/
|
||||
terminate = false;
|
||||
chSemObjectInit(&sem1, 0);
|
||||
chSemObjectInit(&sem2, 0);
|
||||
|
||||
while (!terminate) {
|
||||
chSysLock();
|
||||
if (chSemGetCounterI(&sem1) < 0)
|
||||
chSemSignalI(&sem1);
|
||||
chSemResetI(&sem2, 0);
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
|
||||
chThdSleepMilliseconds(250);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page nil_test_003_001 [3.1] Semaphore primitives, no state change
|
||||
* @page nil_test_003_001 [3.1] Thread Sleep functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Wait, Signal and Reset primitives are tested. The testing thread
|
||||
* does not trigger a state change.
|
||||
* The functionality of @p chThdSleep() and derivatives is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [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.
|
||||
* - [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 nil_test_003_001_setup(void) {
|
||||
chSemObjectInit(&sem1, 1);
|
||||
}
|
||||
|
||||
static void nil_test_003_001_teardown(void) {
|
||||
chSemReset(&sem1, 0);
|
||||
}
|
||||
|
||||
static void nil_test_003_001_execute(void) {
|
||||
systime_t time;
|
||||
|
||||
/* [3.1.1] The function chSemWait() is invoked, after return the
|
||||
counter and the returned message 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);
|
||||
{
|
||||
msg_t msg;
|
||||
|
||||
msg = chSemWait(&sem1);
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_OK == msg, "wrong returned message");
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleep(100);
|
||||
test_assert_time_window(chTimeAddX(time, 100),
|
||||
chTimeAddX(time, 100 + 1),
|
||||
"out of time window");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [3.1.2] The function chSemSignal() is invoked, after return the
|
||||
counter is 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);
|
||||
{
|
||||
chSemSignal(&sem1);
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 1, "wrong counter value");
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepMicroseconds(100000);
|
||||
test_assert_time_window(chTimeAddX(time, TIME_US2I(100000)),
|
||||
chTimeAddX(time, TIME_US2I(100000) + 1),
|
||||
"out of time window");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [3.1.3] The function chSemReset() is invoked, after return the
|
||||
counter is tested.*/
|
||||
/* [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);
|
||||
{
|
||||
chSemReset(&sem1, 2);
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value");
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepMilliseconds(100);
|
||||
test_assert_time_window(chTimeAddX(time, TIME_MS2I(100)),
|
||||
chTimeAddX(time, TIME_MS2I(100) + 1),
|
||||
"out of time window");
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [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(chTimeAddX(time, TIME_S2I(1)),
|
||||
chTimeAddX(time, TIME_S2I(1) + 1),
|
||||
"out of time window");
|
||||
}
|
||||
test_end_step(4);
|
||||
|
||||
/* [3.1.5] Function chThdSleepUntil() is tested with a timeline of
|
||||
"now" + 100 ticks.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepUntil(chTimeAddX(time, 100));
|
||||
test_assert_time_window(chTimeAddX(time, 100),
|
||||
chTimeAddX(time, 100 + 1),
|
||||
"out of time window");
|
||||
}
|
||||
test_end_step(5);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_003_001 = {
|
||||
"Semaphore primitives, no state change",
|
||||
nil_test_003_001_setup,
|
||||
nil_test_003_001_teardown,
|
||||
"Thread Sleep functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_003_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_003_002 [3.2] Semaphore primitives, with state change
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Wait, Signal and Reset primitives are tested. The testing thread
|
||||
* triggers a state change.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [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 nil_test_003_002_setup(void) {
|
||||
thread_descriptor_t td = {
|
||||
.name = "signaler",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() - 1,
|
||||
.funcp = signaler,
|
||||
.arg = NULL
|
||||
};
|
||||
tp1 = chThdCreate(&td);
|
||||
}
|
||||
|
||||
static void nil_test_003_002_teardown(void) {
|
||||
terminate = true;
|
||||
chThdWait(tp1);
|
||||
}
|
||||
|
||||
static void nil_test_003_002_execute(void) {
|
||||
|
||||
/* [3.2.1] The function chSemWait() is invoked, after return the
|
||||
counter and the returned message are tested. The semaphore is
|
||||
signaled by another thread.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
msg_t msg;
|
||||
|
||||
msg = chSemWait(&sem1);
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_OK == msg, "wrong returned message");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [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(&sem2);
|
||||
test_assert_lock(chSemGetCounterI(&sem2) == 0,"wrong counter value");
|
||||
test_assert(MSG_RESET == msg, "wrong returned message");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_003_002 = {
|
||||
"Semaphore primitives, with state change",
|
||||
nil_test_003_002_setup,
|
||||
nil_test_003_002_teardown,
|
||||
nil_test_003_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_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 nil_test_003_003_setup(void) {
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static void nil_test_003_003_teardown(void) {
|
||||
chSemReset(&sem1, 0);
|
||||
}
|
||||
|
||||
static void nil_test_003_003_execute(void) {
|
||||
systime_t time;
|
||||
msg_t msg;
|
||||
|
||||
/* [3.3.1] The function chSemWaitTimeout() is invoked a first time,
|
||||
after return the system time, the counter and the returned message
|
||||
are tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chSemWaitTimeout(&sem1, TIME_MS2I(1000));
|
||||
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
|
||||
chTimeAddX(time, TIME_MS2I(1000) + 1),
|
||||
"out of time window");
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong timeout message");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [3.3.2] The function chSemWaitTimeout() is invoked again, after
|
||||
return the system time, the counter and the returned message are
|
||||
tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chSemWaitTimeout(&sem1, TIME_MS2I(1000));
|
||||
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
|
||||
chTimeAddX(time, TIME_MS2I(1000) + 1),
|
||||
"out of time window");
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong timeout message");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_003_003 = {
|
||||
"Semaphores timeout",
|
||||
nil_test_003_003_setup,
|
||||
nil_test_003_003_teardown,
|
||||
nil_test_003_003_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
@ -292,17 +150,13 @@ static const testcase_t nil_test_003_003 = {
|
|||
*/
|
||||
const testcase_t * const nil_test_sequence_003_array[] = {
|
||||
&nil_test_003_001,
|
||||
&nil_test_003_002,
|
||||
&nil_test_003_003,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Semaphores.
|
||||
* @brief Threads Functionality.
|
||||
*/
|
||||
const testsequence_t nil_test_sequence_003 = {
|
||||
"Semaphores",
|
||||
"Threads Functionality",
|
||||
nil_test_sequence_003_array
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
|
|
@ -21,40 +21,59 @@
|
|||
* @file nil_test_sequence_004.c
|
||||
* @brief Test Sequence 004 code.
|
||||
*
|
||||
* @page nil_test_sequence_004 [4] Suspend/Resume
|
||||
* @page nil_test_sequence_004 [4] Semaphores
|
||||
*
|
||||
* File: @ref nil_test_sequence_004.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/NIL functionalities related to
|
||||
* threads suspend/resume.
|
||||
* 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 nil_test_004_001
|
||||
* - @subpage nil_test_004_002
|
||||
* - @subpage nil_test_004_003
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
static thread_t *tp1;
|
||||
static bool terminate;
|
||||
static thread_reference_t tr1;
|
||||
static semaphore_t sem1, sem2;
|
||||
|
||||
/*
|
||||
* Resumer thread.
|
||||
* Signaler thread.
|
||||
*/
|
||||
static THD_FUNCTION(resumer, arg) {
|
||||
static THD_FUNCTION(signaler, arg) {
|
||||
|
||||
(void)arg;
|
||||
|
||||
/* Initializing global resources.*/
|
||||
terminate = false;
|
||||
tr1 = NULL;
|
||||
chSemObjectInit(&sem1, 0);
|
||||
chSemObjectInit(&sem2, 0);
|
||||
|
||||
while (!terminate) {
|
||||
chThdResume(&tr1, MSG_OK);
|
||||
chSysLock();
|
||||
if (chSemGetCounterI(&sem1) < 0)
|
||||
chSemSignalI(&sem1);
|
||||
chSemResetI(&sem2, 0);
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
|
||||
chThdSleepMilliseconds(250);
|
||||
}
|
||||
}
|
||||
|
@ -64,81 +83,204 @@ static THD_FUNCTION(resumer, arg) {
|
|||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page nil_test_004_001 [4.1] Suspend and Resume functionality
|
||||
* @page nil_test_004_001 [4.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>
|
||||
* - [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.
|
||||
* - [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.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_004_001_setup(void) {
|
||||
chSemObjectInit(&sem1, 1);
|
||||
}
|
||||
|
||||
static void nil_test_004_001_teardown(void) {
|
||||
chSemReset(&sem1, 0);
|
||||
}
|
||||
|
||||
static void nil_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");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [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");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [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");
|
||||
}
|
||||
test_end_step(3);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_004_001 = {
|
||||
"Semaphore primitives, no state change",
|
||||
nil_test_004_001_setup,
|
||||
nil_test_004_001_teardown,
|
||||
nil_test_004_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_004_002 [4.2] Semaphore primitives, with state change
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Wait, Signal and Reset primitives are tested. The testing thread
|
||||
* triggers a state change.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.2.1] The function chSemWait() is invoked, after return the
|
||||
* counter and the returned message are tested. The semaphore is
|
||||
* signaled by another thread.
|
||||
* - [4.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 nil_test_004_002_setup(void) {
|
||||
thread_descriptor_t td = {
|
||||
.name = "resumer",
|
||||
.name = "signaler",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() - 1,
|
||||
.funcp = resumer,
|
||||
.funcp = signaler,
|
||||
.arg = NULL
|
||||
};
|
||||
tp1 = chThdCreate(&td);
|
||||
}
|
||||
|
||||
static void nil_test_004_001_teardown(void) {
|
||||
static void nil_test_004_002_teardown(void) {
|
||||
terminate = true;
|
||||
chThdWait(tp1);
|
||||
}
|
||||
|
||||
static void nil_test_004_001_execute(void) {
|
||||
systime_t time;
|
||||
msg_t msg;
|
||||
static void nil_test_004_002_execute(void) {
|
||||
|
||||
/* [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.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);
|
||||
{
|
||||
chSysLock();
|
||||
msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE);
|
||||
chSysUnlock();
|
||||
test_assert(NULL == tr1, "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");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [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.*/
|
||||
/* [4.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);
|
||||
{
|
||||
thread_reference_t tr = NULL;
|
||||
msg_t msg;
|
||||
|
||||
chSysLock();
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chThdSuspendTimeoutS(&tr, TIME_MS2I(1000));
|
||||
chSysUnlock();
|
||||
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
|
||||
chTimeAddX(time, TIME_MS2I(1000) + 1),
|
||||
"out of time window");
|
||||
test_assert(NULL == tr, "not NULL");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong returned message");
|
||||
msg = chSemWait(&sem2);
|
||||
test_assert_lock(chSemGetCounterI(&sem2) == 0,"wrong counter value");
|
||||
test_assert(MSG_RESET == msg, "wrong returned message");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_004_001 = {
|
||||
"Suspend and Resume functionality",
|
||||
nil_test_004_001_setup,
|
||||
nil_test_004_001_teardown,
|
||||
nil_test_004_001_execute
|
||||
static const testcase_t nil_test_004_002 = {
|
||||
"Semaphore primitives, with state change",
|
||||
nil_test_004_002_setup,
|
||||
nil_test_004_002_teardown,
|
||||
nil_test_004_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_004_003 [4.3] Semaphores timeout
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Timeout on semaphores is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.3.1] The function chSemWaitTimeout() is invoked a first time,
|
||||
* after return the system time, the counter and the returned message
|
||||
* are tested.
|
||||
* - [4.3.2] The function chSemWaitTimeout() is invoked again, after
|
||||
* return the system time, the counter and the returned message are
|
||||
* tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_004_003_setup(void) {
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static void nil_test_004_003_teardown(void) {
|
||||
chSemReset(&sem1, 0);
|
||||
}
|
||||
|
||||
static void nil_test_004_003_execute(void) {
|
||||
systime_t time;
|
||||
msg_t msg;
|
||||
|
||||
/* [4.3.1] The function chSemWaitTimeout() is invoked a first time,
|
||||
after return the system time, the counter and the returned message
|
||||
are tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chSemWaitTimeout(&sem1, TIME_MS2I(1000));
|
||||
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
|
||||
chTimeAddX(time, TIME_MS2I(1000) + 1),
|
||||
"out of time window");
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong timeout message");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [4.3.2] The function chSemWaitTimeout() is invoked again, after
|
||||
return the system time, the counter and the returned message are
|
||||
tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chSemWaitTimeout(&sem1, TIME_MS2I(1000));
|
||||
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
|
||||
chTimeAddX(time, TIME_MS2I(1000) + 1),
|
||||
"out of time window");
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong timeout message");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_004_003 = {
|
||||
"Semaphores timeout",
|
||||
nil_test_004_003_setup,
|
||||
nil_test_004_003_teardown,
|
||||
nil_test_004_003_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -150,13 +292,17 @@ static const testcase_t nil_test_004_001 = {
|
|||
*/
|
||||
const testcase_t * const nil_test_sequence_004_array[] = {
|
||||
&nil_test_004_001,
|
||||
&nil_test_004_002,
|
||||
&nil_test_004_003,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Suspend/Resume.
|
||||
* @brief Semaphores.
|
||||
*/
|
||||
const testsequence_t nil_test_sequence_004 = {
|
||||
"Suspend/Resume",
|
||||
"Semaphores",
|
||||
nil_test_sequence_004_array
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
|
|
@ -21,62 +21,42 @@
|
|||
* @file nil_test_sequence_005.c
|
||||
* @brief Test Sequence 005 code.
|
||||
*
|
||||
* @page nil_test_sequence_005 [5] Event Sources and Event Flags
|
||||
* @page nil_test_sequence_005 [5] Suspend/Resume
|
||||
*
|
||||
* File: @ref nil_test_sequence_005.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* 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_EVENTS
|
||||
* .
|
||||
* This sequence tests the ChibiOS/NIL functionalities related to
|
||||
* threads suspend/resume.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage nil_test_005_001
|
||||
* - @subpage nil_test_005_002
|
||||
* - @subpage nil_test_005_003
|
||||
* - @subpage nil_test_005_004
|
||||
* - @subpage nil_test_005_005
|
||||
* - @subpage nil_test_005_006
|
||||
* - @subpage nil_test_005_007
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
static EVENTSOURCE_DECL(es1);
|
||||
static EVENTSOURCE_DECL(es2);
|
||||
|
||||
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 thread_t *tp1;
|
||||
static bool terminate;
|
||||
static thread_reference_t tr1;
|
||||
|
||||
/*
|
||||
* Direct events thread.
|
||||
* Resumer thread.
|
||||
*/
|
||||
static THD_FUNCTION(evtthd1, p) {
|
||||
static THD_FUNCTION(resumer, arg) {
|
||||
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtSignal((thread_t *)p, 1);
|
||||
}
|
||||
(void)arg;
|
||||
|
||||
/*
|
||||
* Broadcaster thread.
|
||||
*/
|
||||
static THD_FUNCTION(evtthd2, p) {
|
||||
/* Initializing global resources.*/
|
||||
terminate = false;
|
||||
tr1 = NULL;
|
||||
|
||||
(void)p;
|
||||
chEvtBroadcast(&es1);
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtBroadcast(&es2);
|
||||
while (!terminate) {
|
||||
chThdResume(&tr1, MSG_OK);
|
||||
chThdSleepMilliseconds(250);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -84,525 +64,83 @@ static THD_FUNCTION(evtthd2, p) {
|
|||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page nil_test_005_001 [5.1] Events registration
|
||||
* @page nil_test_005_001 [5.1] Suspend and Resume functionality
|
||||
*
|
||||
* <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.
|
||||
* The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
|
||||
* tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [5.1.1] An Event Source is initialized.
|
||||
* - [5.1.2] Two Event Listeners are registered on the Event Source,
|
||||
* the Event Source is tested to have listeners.
|
||||
* - [5.1.3] An Event Listener is unregistered, the Event Source must
|
||||
* still have listeners.
|
||||
* - [5.1.4] An Event Listener is unregistered, the Event Source must
|
||||
* not have listeners.
|
||||
* - [5.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.
|
||||
* - [5.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 nil_test_005_001_execute(void) {
|
||||
event_listener_t el1, el2;
|
||||
static void nil_test_005_001_setup(void) {
|
||||
thread_descriptor_t td = {
|
||||
.name = "resumer",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() - 1,
|
||||
.funcp = resumer,
|
||||
.arg = NULL
|
||||
};
|
||||
tp1 = chThdCreate(&td);
|
||||
}
|
||||
|
||||
/* [5.1.1] An Event Source is initialized.*/
|
||||
static void nil_test_005_001_teardown(void) {
|
||||
terminate = true;
|
||||
chThdWait(tp1);
|
||||
}
|
||||
|
||||
static void nil_test_005_001_execute(void) {
|
||||
systime_t time;
|
||||
msg_t msg;
|
||||
|
||||
/* [5.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);
|
||||
{
|
||||
chEvtObjectInit(&es1);
|
||||
chSysLock();
|
||||
msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE);
|
||||
chSysUnlock();
|
||||
test_assert(NULL == tr1, "not NULL");
|
||||
test_assert(MSG_OK == msg,"wrong returned message");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [5.1.2] Two Event Listeners are registered on the Event Source,
|
||||
the Event Source is tested to have listeners.*/
|
||||
/* [5.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);
|
||||
{
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es1, &el2, 2);
|
||||
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
|
||||
thread_reference_t tr = NULL;
|
||||
|
||||
chSysLock();
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chThdSuspendTimeoutS(&tr, TIME_MS2I(1000));
|
||||
chSysUnlock();
|
||||
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
|
||||
chTimeAddX(time, TIME_MS2I(1000) + 1),
|
||||
"out of time window");
|
||||
test_assert(NULL == tr, "not NULL");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong returned message");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [5.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");
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [5.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");
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_005_001 = {
|
||||
"Events registration",
|
||||
NULL,
|
||||
NULL,
|
||||
"Suspend and Resume functionality",
|
||||
nil_test_005_001_setup,
|
||||
nil_test_005_001_teardown,
|
||||
nil_test_005_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_005_002 [5.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>
|
||||
* - [5.2.1] Three evenf flag bits are raised then chEvtDispatch() is
|
||||
* invoked, the sequence of handlers calls is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_005_002_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void nil_test_005_002_execute(void) {
|
||||
|
||||
/* [5.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");
|
||||
}
|
||||
test_end_step(1);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_005_002 = {
|
||||
"Event Flags dispatching",
|
||||
nil_test_005_002_setup,
|
||||
NULL,
|
||||
nil_test_005_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_005_003 [5.3] Events Flags wait using chEvtWaitOne()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitOne() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [5.3.1] Setting three event flags.
|
||||
* - [5.3.2] Calling chEvtWaitOne() three times, each time a single
|
||||
* flag must be returned in order of priority.
|
||||
* - [5.3.3] Getting current time and starting a signaler thread, the
|
||||
* thread will set an event flag after 50mS.
|
||||
* - [5.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 nil_test_005_003_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void nil_test_005_003_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
thread_t *tp;
|
||||
|
||||
/* [5.3.1] Setting three event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(7);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [5.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");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [5.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 = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
thread_descriptor_t td = {
|
||||
.name = "event1",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() + 1,
|
||||
.funcp = evtthd1,
|
||||
.arg = chThdGetSelfX()
|
||||
};
|
||||
tp = chThdCreate(&td);
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [5.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,
|
||||
chTimeAddX(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");
|
||||
chThdWait(tp);
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_005_003 = {
|
||||
"Events Flags wait using chEvtWaitOne()",
|
||||
nil_test_005_003_setup,
|
||||
NULL,
|
||||
nil_test_005_003_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_005_004 [5.4] Events Flags wait using chEvtWaitAny()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitAny() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [5.4.1] Setting two, non contiguous, event flags.
|
||||
* - [5.4.2] Calling chEvtWaitAny() one time, the two flags must be
|
||||
* returned.
|
||||
* - [5.4.3] Getting current time and starting a signaler thread, the
|
||||
* thread will set an event flag after 50mS.
|
||||
* - [5.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 nil_test_005_004_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void nil_test_005_004_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
thread_t *tp;
|
||||
|
||||
/* [5.4.1] Setting two, non contiguous, event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(5);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [5.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");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [5.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 = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
thread_descriptor_t td = {
|
||||
.name = "event1",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() + 1,
|
||||
.funcp = evtthd1,
|
||||
.arg = chThdGetSelfX()
|
||||
};
|
||||
tp = chThdCreate(&td);
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [5.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,
|
||||
chTimeAddX(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");
|
||||
chThdWait(tp);
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_005_004 = {
|
||||
"Events Flags wait using chEvtWaitAny()",
|
||||
nil_test_005_004_setup,
|
||||
NULL,
|
||||
nil_test_005_004_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_005_005 [5.5] Events Flags wait using chEvtWaitAll()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitAll() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [5.5.1] Setting two, non contiguous, event flags.
|
||||
* - [5.5.2] Calling chEvtWaitAll() one time, the two flags must be
|
||||
* returned.
|
||||
* - [5.5.3] Setting one event flag.
|
||||
* - [5.5.4] Getting current time and starting a signaler thread, the
|
||||
* thread will set another event flag after 50mS.
|
||||
* - [5.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 nil_test_005_005_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void nil_test_005_005_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
thread_t *tp;
|
||||
|
||||
/* [5.5.1] Setting two, non contiguous, event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(5);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [5.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");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [5.5.3] Setting one event flag.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chEvtAddEvents(4);
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [5.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 = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
thread_descriptor_t td = {
|
||||
.name = "event1",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() + 1,
|
||||
.funcp = evtthd1,
|
||||
.arg = chThdGetSelfX()
|
||||
};
|
||||
tp = chThdCreate(&td);
|
||||
}
|
||||
test_end_step(4);
|
||||
|
||||
/* [5.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,
|
||||
chTimeAddX(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");
|
||||
chThdWait(tp);
|
||||
}
|
||||
test_end_step(5);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_005_005 = {
|
||||
"Events Flags wait using chEvtWaitAll()",
|
||||
nil_test_005_005_setup,
|
||||
NULL,
|
||||
nil_test_005_005_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_005_006 [5.6] Events Flags wait timeouts
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Timeout functionality is tested for chEvtWaitOneTimeout(),
|
||||
* chEvtWaitAnyTimeout() and chEvtWaitAllTimeout().
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [5.6.1] The functions are invoked first with TIME_IMMEDIATE
|
||||
* timeout, the timeout condition is tested.
|
||||
* - [5.6.2] The functions are invoked first with a 50mS timeout, the
|
||||
* timeout condition is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_005_006_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void nil_test_005_006_execute(void) {
|
||||
eventmask_t m;
|
||||
|
||||
/* [5.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");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [5.6.2] The functions are invoked first with a 50mS timeout, the
|
||||
timeout condition is tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_MS2I(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_MS2I(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_MS2I(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_005_006 = {
|
||||
"Events Flags wait timeouts",
|
||||
nil_test_005_006_setup,
|
||||
NULL,
|
||||
nil_test_005_006_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_005_007 [5.7] Broadcasting using chEvtBroadcast()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtBroadcast() is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [5.7.1] Registering on two event sources associating them with
|
||||
* flags 1 and 4.
|
||||
* - [5.7.2] Getting current time and starting a broadcaster thread,
|
||||
* the thread broadcast the first Event Source immediately and the
|
||||
* other after 50mS.
|
||||
* - [5.7.3] Calling chEvtWaitAll() then verifying that both event
|
||||
* flags have been received after 50mS and that the event flags mask
|
||||
* has been emptied.
|
||||
* - [5.7.4] Unregistering from the Event Sources.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_005_007_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
chEvtObjectInit(&es1);
|
||||
chEvtObjectInit(&es2);
|
||||
}
|
||||
|
||||
static void nil_test_005_007_execute(void) {
|
||||
eventmask_t m;
|
||||
event_listener_t el1, el2;
|
||||
systime_t target_time;
|
||||
thread_t *tp;
|
||||
|
||||
/* [5.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);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [5.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 = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
thread_descriptor_t td = {
|
||||
.name = "event2",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() + 1,
|
||||
.funcp = evtthd2,
|
||||
.arg = NULL
|
||||
};
|
||||
tp = chThdCreate(&td);
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [5.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,
|
||||
chTimeAddX(target_time, ALLOWED_DELAY),
|
||||
"out of time window");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
chThdWait(tp);
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [5.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");
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_005_007 = {
|
||||
"Broadcasting using chEvtBroadcast()",
|
||||
nil_test_005_007_setup,
|
||||
NULL,
|
||||
nil_test_005_007_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
@ -612,21 +150,13 @@ static const testcase_t nil_test_005_007 = {
|
|||
*/
|
||||
const testcase_t * const nil_test_sequence_005_array[] = {
|
||||
&nil_test_005_001,
|
||||
&nil_test_005_002,
|
||||
&nil_test_005_003,
|
||||
&nil_test_005_004,
|
||||
&nil_test_005_005,
|
||||
&nil_test_005_006,
|
||||
&nil_test_005_007,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Event Sources and Event Flags.
|
||||
* @brief Suspend/Resume.
|
||||
*/
|
||||
const testsequence_t nil_test_sequence_005 = {
|
||||
"Event Sources and Event Flags",
|
||||
"Suspend/Resume",
|
||||
nil_test_sequence_005_array
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_EVENTS */
|
||||
|
|
|
@ -21,40 +21,62 @@
|
|||
* @file nil_test_sequence_006.c
|
||||
* @brief Test Sequence 006 code.
|
||||
*
|
||||
* @page nil_test_sequence_006 [6] Synchronous Messages
|
||||
* @page nil_test_sequence_006 [6] Event Sources and Event Flags
|
||||
*
|
||||
* File: @ref nil_test_sequence_006.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the Synchronous
|
||||
* Messages subsystem.
|
||||
* 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_MESSAGES
|
||||
* - CH_CFG_USE_EVENTS
|
||||
* .
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage nil_test_006_001
|
||||
* - @subpage nil_test_006_002
|
||||
* - @subpage nil_test_006_003
|
||||
* - @subpage nil_test_006_004
|
||||
* - @subpage nil_test_006_005
|
||||
* - @subpage nil_test_006_006
|
||||
* - @subpage nil_test_006_007
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Messager thread.
|
||||
*/
|
||||
static THD_FUNCTION(messenger, p) {
|
||||
static EVENTSOURCE_DECL(es1);
|
||||
static EVENTSOURCE_DECL(es2);
|
||||
|
||||
chMsgSend(p, 'A');
|
||||
chMsgSend(p, 'B');
|
||||
chMsgSend(p, 'C');
|
||||
chMsgSend(p, 'D');
|
||||
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};
|
||||
|
||||
/*
|
||||
* Direct events thread.
|
||||
*/
|
||||
static THD_FUNCTION(evtthd1, p) {
|
||||
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtSignal((thread_t *)p, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Broadcaster thread.
|
||||
*/
|
||||
static THD_FUNCTION(evtthd2, p) {
|
||||
|
||||
(void)p;
|
||||
chEvtBroadcast(&es1);
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtBroadcast(&es2);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -62,61 +84,523 @@ static THD_FUNCTION(messenger, p) {
|
|||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page nil_test_006_001 [6.1] Messages Server loop
|
||||
* @page nil_test_006_001 [6.1] Events registration
|
||||
*
|
||||
* <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.
|
||||
* 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>
|
||||
* - [6.1.1] Starting the messenger thread.
|
||||
* - [6.1.2] Waiting for four messages then testing the receive order.
|
||||
* - [6.1.1] An Event Source is initialized.
|
||||
* - [6.1.2] Two Event Listeners are registered on the Event Source,
|
||||
* the Event Source is tested to have listeners.
|
||||
* - [6.1.3] An Event Listener is unregistered, the Event Source must
|
||||
* still have listeners.
|
||||
* - [6.1.4] An Event Listener is unregistered, the Event Source must
|
||||
* not have listeners.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_006_001_execute(void) {
|
||||
thread_t *tp, *tp1;
|
||||
msg_t msg;
|
||||
event_listener_t el1, el2;
|
||||
|
||||
/* [6.1.1] Starting the messenger thread.*/
|
||||
/* [6.1.1] An Event Source is initialized.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
thread_descriptor_t td = {
|
||||
.name = "messenger",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() - 1,
|
||||
.funcp = messenger,
|
||||
.arg = chThdGetSelfX()
|
||||
};
|
||||
tp1 = chThdCreate(&td);
|
||||
chEvtObjectInit(&es1);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [6.1.2] Waiting for four messages then testing the receive
|
||||
order.*/
|
||||
/* [6.1.2] Two Event Listeners are registered on the Event Source,
|
||||
the Event Source is tested to have listeners.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
unsigned i;
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es1, &el2, 2);
|
||||
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
tp = chMsgWait();
|
||||
msg = chMsgGet(tp);
|
||||
chMsgRelease(tp, msg);
|
||||
test_emit_token(msg);
|
||||
}
|
||||
chThdWait(tp1);
|
||||
test_assert_sequence("ABCD", "invalid sequence");
|
||||
/* [6.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");
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [6.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");
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_006_001 = {
|
||||
"Events registration",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_006_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_006_002 [6.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>
|
||||
* - [6.2.1] Three evenf flag bits are raised then chEvtDispatch() is
|
||||
* invoked, the sequence of handlers calls is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_006_002_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void nil_test_006_002_execute(void) {
|
||||
|
||||
/* [6.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");
|
||||
}
|
||||
test_end_step(1);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_006_002 = {
|
||||
"Event Flags dispatching",
|
||||
nil_test_006_002_setup,
|
||||
NULL,
|
||||
nil_test_006_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_006_003 [6.3] Events Flags wait using chEvtWaitOne()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitOne() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [6.3.1] Setting three event flags.
|
||||
* - [6.3.2] Calling chEvtWaitOne() three times, each time a single
|
||||
* flag must be returned in order of priority.
|
||||
* - [6.3.3] Getting current time and starting a signaler thread, the
|
||||
* thread will set an event flag after 50mS.
|
||||
* - [6.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 nil_test_006_003_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void nil_test_006_003_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
thread_t *tp;
|
||||
|
||||
/* [6.3.1] Setting three event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(7);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [6.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");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [6.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 = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
thread_descriptor_t td = {
|
||||
.name = "event1",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() + 1,
|
||||
.funcp = evtthd1,
|
||||
.arg = chThdGetSelfX()
|
||||
};
|
||||
tp = chThdCreate(&td);
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [6.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,
|
||||
chTimeAddX(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");
|
||||
chThdWait(tp);
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_006_003 = {
|
||||
"Events Flags wait using chEvtWaitOne()",
|
||||
nil_test_006_003_setup,
|
||||
NULL,
|
||||
nil_test_006_003_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_006_004 [6.4] Events Flags wait using chEvtWaitAny()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitAny() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [6.4.1] Setting two, non contiguous, event flags.
|
||||
* - [6.4.2] Calling chEvtWaitAny() one time, the two flags must be
|
||||
* returned.
|
||||
* - [6.4.3] Getting current time and starting a signaler thread, the
|
||||
* thread will set an event flag after 50mS.
|
||||
* - [6.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 nil_test_006_004_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void nil_test_006_004_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
thread_t *tp;
|
||||
|
||||
/* [6.4.1] Setting two, non contiguous, event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(5);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [6.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");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [6.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 = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
thread_descriptor_t td = {
|
||||
.name = "event1",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() + 1,
|
||||
.funcp = evtthd1,
|
||||
.arg = chThdGetSelfX()
|
||||
};
|
||||
tp = chThdCreate(&td);
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [6.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,
|
||||
chTimeAddX(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");
|
||||
chThdWait(tp);
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_006_004 = {
|
||||
"Events Flags wait using chEvtWaitAny()",
|
||||
nil_test_006_004_setup,
|
||||
NULL,
|
||||
nil_test_006_004_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_006_005 [6.5] Events Flags wait using chEvtWaitAll()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitAll() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [6.5.1] Setting two, non contiguous, event flags.
|
||||
* - [6.5.2] Calling chEvtWaitAll() one time, the two flags must be
|
||||
* returned.
|
||||
* - [6.5.3] Setting one event flag.
|
||||
* - [6.5.4] Getting current time and starting a signaler thread, the
|
||||
* thread will set another event flag after 50mS.
|
||||
* - [6.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 nil_test_006_005_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void nil_test_006_005_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
thread_t *tp;
|
||||
|
||||
/* [6.5.1] Setting two, non contiguous, event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(5);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [6.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");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [6.5.3] Setting one event flag.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chEvtAddEvents(4);
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [6.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 = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
thread_descriptor_t td = {
|
||||
.name = "event1",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() + 1,
|
||||
.funcp = evtthd1,
|
||||
.arg = chThdGetSelfX()
|
||||
};
|
||||
tp = chThdCreate(&td);
|
||||
}
|
||||
test_end_step(4);
|
||||
|
||||
/* [6.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,
|
||||
chTimeAddX(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");
|
||||
chThdWait(tp);
|
||||
}
|
||||
test_end_step(5);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_006_005 = {
|
||||
"Events Flags wait using chEvtWaitAll()",
|
||||
nil_test_006_005_setup,
|
||||
NULL,
|
||||
nil_test_006_005_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_006_006 [6.6] Events Flags wait timeouts
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Timeout functionality is tested for chEvtWaitOneTimeout(),
|
||||
* chEvtWaitAnyTimeout() and chEvtWaitAllTimeout().
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [6.6.1] The functions are invoked first with TIME_IMMEDIATE
|
||||
* timeout, the timeout condition is tested.
|
||||
* - [6.6.2] The functions are invoked first with a 50mS timeout, the
|
||||
* timeout condition is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_006_006_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void nil_test_006_006_execute(void) {
|
||||
eventmask_t m;
|
||||
|
||||
/* [6.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");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [6.6.2] The functions are invoked first with a 50mS timeout, the
|
||||
timeout condition is tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_MS2I(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_MS2I(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_MS2I(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_006_001 = {
|
||||
"Messages Server loop",
|
||||
static const testcase_t nil_test_006_006 = {
|
||||
"Events Flags wait timeouts",
|
||||
nil_test_006_006_setup,
|
||||
NULL,
|
||||
nil_test_006_006_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_006_007 [6.7] Broadcasting using chEvtBroadcast()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtBroadcast() is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [6.7.1] Registering on two event sources associating them with
|
||||
* flags 1 and 4.
|
||||
* - [6.7.2] Getting current time and starting a broadcaster thread,
|
||||
* the thread broadcast the first Event Source immediately and the
|
||||
* other after 50mS.
|
||||
* - [6.7.3] Calling chEvtWaitAll() then verifying that both event
|
||||
* flags have been received after 50mS and that the event flags mask
|
||||
* has been emptied.
|
||||
* - [6.7.4] Unregistering from the Event Sources.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_006_007_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
chEvtObjectInit(&es1);
|
||||
chEvtObjectInit(&es2);
|
||||
}
|
||||
|
||||
static void nil_test_006_007_execute(void) {
|
||||
eventmask_t m;
|
||||
event_listener_t el1, el2;
|
||||
systime_t target_time;
|
||||
thread_t *tp;
|
||||
|
||||
/* [6.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);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [6.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 = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
thread_descriptor_t td = {
|
||||
.name = "event2",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() + 1,
|
||||
.funcp = evtthd2,
|
||||
.arg = NULL
|
||||
};
|
||||
tp = chThdCreate(&td);
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [6.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,
|
||||
chTimeAddX(target_time, ALLOWED_DELAY),
|
||||
"out of time window");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
chThdWait(tp);
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [6.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");
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_006_007 = {
|
||||
"Broadcasting using chEvtBroadcast()",
|
||||
nil_test_006_007_setup,
|
||||
NULL,
|
||||
nil_test_006_001_execute
|
||||
nil_test_006_007_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -128,15 +612,21 @@ static const testcase_t nil_test_006_001 = {
|
|||
*/
|
||||
const testcase_t * const nil_test_sequence_006_array[] = {
|
||||
&nil_test_006_001,
|
||||
&nil_test_006_002,
|
||||
&nil_test_006_003,
|
||||
&nil_test_006_004,
|
||||
&nil_test_006_005,
|
||||
&nil_test_006_006,
|
||||
&nil_test_006_007,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Synchronous Messages.
|
||||
* @brief Event Sources and Event Flags.
|
||||
*/
|
||||
const testsequence_t nil_test_sequence_006 = {
|
||||
"Synchronous Messages",
|
||||
"Event Sources and Event Flags",
|
||||
nil_test_sequence_006_array
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_MESSAGES */
|
||||
#endif /* CH_CFG_USE_EVENTS */
|
||||
|
|
|
@ -21,613 +21,103 @@
|
|||
* @file nil_test_sequence_007.c
|
||||
* @brief Test Sequence 007 code.
|
||||
*
|
||||
* @page nil_test_sequence_007 [7] Benchmarks
|
||||
* @page nil_test_sequence_007 [7] Synchronous Messages
|
||||
*
|
||||
* File: @ref nil_test_sequence_007.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 Synchronous
|
||||
* Messages subsystem.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_MESSAGES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage nil_test_007_001
|
||||
* - @subpage nil_test_007_002
|
||||
* - @subpage nil_test_007_003
|
||||
* - @subpage nil_test_007_004
|
||||
* - @subpage nil_test_007_005
|
||||
* - @subpage nil_test_007_006
|
||||
* - @subpage nil_test_007_007
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_MESSAGES) || 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
|
||||
/*
|
||||
* Messager thread.
|
||||
*/
|
||||
static THD_FUNCTION(messenger, p) {
|
||||
|
||||
#if CH_CFG_USE_MESSAGES
|
||||
static THD_FUNCTION(bmk_thread1, p) {
|
||||
thread_t *tp;
|
||||
msg_t msg;
|
||||
|
||||
(void)p;
|
||||
do {
|
||||
tp = chMsgWait();
|
||||
msg = chMsgGet(tp);
|
||||
chMsgRelease(tp, msg);
|
||||
} while (msg);
|
||||
}
|
||||
|
||||
NOINLINE static unsigned int msg_loop_test(thread_t *tp) {
|
||||
systime_t start, end;
|
||||
|
||||
uint32_t n = 0;
|
||||
start = test_wait_tick();
|
||||
end = chTimeAddX(start, TIME_MS2I(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(NIL_STATE_SUSPENDED);
|
||||
msg = self->u1.msg;
|
||||
} while (msg == MSG_OK);
|
||||
chSysUnlock();
|
||||
chMsgSend(p, 'A');
|
||||
chMsgSend(p, 'B');
|
||||
chMsgSend(p, 'C');
|
||||
chMsgSend(p, 'D');
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page nil_test_007_001 [7.1] Messages performance #1
|
||||
* @page nil_test_007_001 [7.1] Messages Server loop
|
||||
*
|
||||
* <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
|
||||
* .
|
||||
* 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] The messenger thread is started at a lower priority than
|
||||
* the current thread.
|
||||
* - [7.1.2] The number of messages exchanged is counted in a one
|
||||
* second time window.
|
||||
* - [7.1.3] Score is printed.
|
||||
* - [7.1.1] Starting the messenger thread.
|
||||
* - [7.1.2] Waiting for four messages then testing the receive order.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_007_001_execute(void) {
|
||||
uint32_t n;
|
||||
thread_t *tp;
|
||||
thread_t *tp, *tp1;
|
||||
msg_t msg;
|
||||
|
||||
/* [7.1.1] The messenger thread is started at a lower priority than
|
||||
the current thread.*/
|
||||
/* [7.1.1] Starting the messenger thread.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
thread_descriptor_t td = {
|
||||
.name = "messenger",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() + 1,
|
||||
.funcp = bmk_thread1,
|
||||
.arg = NULL
|
||||
.prio = chThdGetPriorityX() - 1,
|
||||
.funcp = messenger,
|
||||
.arg = chThdGetSelfX()
|
||||
};
|
||||
tp = chThdCreate(&td);
|
||||
tp1 = chThdCreate(&td);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [7.1.2] The number of messages exchanged is counted in a one
|
||||
second time window.*/
|
||||
/* [7.1.2] Waiting for four messages then testing the receive
|
||||
order.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
n = msg_loop_test(tp);
|
||||
chThdWait(tp);
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
tp = chMsgWait();
|
||||
msg = chMsgGet(tp);
|
||||
chMsgRelease(tp, msg);
|
||||
test_emit_token(msg);
|
||||
}
|
||||
chThdWait(tp1);
|
||||
test_assert_sequence("ABCD", "invalid sequence");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [7.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");
|
||||
}
|
||||
test_end_step(3);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_007_001 = {
|
||||
"Messages performance #1",
|
||||
"Messages Server loop",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_007_001_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_MESSAGES */
|
||||
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page nil_test_007_002 [7.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>
|
||||
* - [7.2.1] The messenger thread is started at an higher priority than
|
||||
* the current thread.
|
||||
* - [7.2.2] The number of messages exchanged is counted in a one
|
||||
* second time window.
|
||||
* - [7.2.3] Score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_007_002_execute(void) {
|
||||
uint32_t n;
|
||||
thread_t *tp;
|
||||
|
||||
/* [7.2.1] The messenger thread is started at an higher priority than
|
||||
the current thread.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
thread_descriptor_t td = {
|
||||
.name = "messenger",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() - 1,
|
||||
.funcp = bmk_thread1,
|
||||
.arg = NULL
|
||||
};
|
||||
tp = chThdCreate(&td);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [7.2.2] The number of messages exchanged is counted in a one
|
||||
second time window.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
n = msg_loop_test(tp);
|
||||
chThdWait(tp);
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [7.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");
|
||||
}
|
||||
test_end_step(3);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_007_002 = {
|
||||
"Messages performance #2",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_007_002_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_MESSAGES */
|
||||
|
||||
/**
|
||||
* @page nil_test_007_003 [7.3] 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>
|
||||
* - [7.3.1] Starting the target thread at an higher priority level.
|
||||
* - [7.3.2] Waking up the thread as fast as possible in a one second
|
||||
* time window.
|
||||
* - [7.3.3] Stopping the target thread.
|
||||
* - [7.3.4] Score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_007_003_execute(void) {
|
||||
thread_t *tp;
|
||||
uint32_t n;
|
||||
|
||||
/* [7.3.1] Starting the target thread at an higher priority level.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
thread_descriptor_t td = {
|
||||
.name = "messenger",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() - 1,
|
||||
.funcp = bmk_thread4,
|
||||
.arg = NULL
|
||||
};
|
||||
tp = chThdCreate(&td);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [7.3.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 = chTimeAddX(start, TIME_MS2I(1000));
|
||||
do {
|
||||
chSysLock();
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSysUnlock();
|
||||
n += 4;
|
||||
} while (chVTIsSystemTimeWithinX(start, end));
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [7.3.3] Stopping the target thread.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chSysLock();
|
||||
chSchWakeupS(tp, MSG_TIMEOUT);
|
||||
chSysUnlock();
|
||||
chThdWait(tp);
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [7.3.4] Score is printed.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
test_print("--- Score : ");
|
||||
test_printn(n * 2);
|
||||
test_println(" ctxswc/S");
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_007_003 = {
|
||||
"Context Switch performance",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_007_003_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_007_004 [7.4] 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>
|
||||
* - [7.4.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.
|
||||
* - [7.4.2] Score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_007_004_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
/* [7.4.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);
|
||||
{
|
||||
systime_t start, end;
|
||||
thread_descriptor_t td = {
|
||||
.name = "messenger",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() + 1,
|
||||
.funcp = bmk_thread3,
|
||||
.arg = NULL
|
||||
};
|
||||
|
||||
n = 0;
|
||||
start = test_wait_tick();
|
||||
end = chTimeAddX(start, TIME_MS2I(1000));
|
||||
do {
|
||||
chThdWait(chThdCreate(&td));
|
||||
n++;
|
||||
} while (chVTIsSystemTimeWithinX(start, end));
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [7.4.2] Score is printed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_println(" threads/S");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_007_004 = {
|
||||
"Threads performance, full cycle",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_007_004_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_007_005 [7.5] 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>
|
||||
* - [7.5.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.
|
||||
* - [7.5.2] Score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_007_005_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
/* [7.5.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);
|
||||
{
|
||||
systime_t start, end;
|
||||
thread_descriptor_t td = {
|
||||
.name = "messenger",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() - 1,
|
||||
.funcp = bmk_thread3,
|
||||
.arg = NULL
|
||||
};
|
||||
|
||||
n = 0;
|
||||
start = test_wait_tick();
|
||||
end = chTimeAddX(start, TIME_MS2I(1000));
|
||||
do {
|
||||
chThdWait(chThdCreate(&td));
|
||||
n++;
|
||||
} while (chVTIsSystemTimeWithinX(start, end));
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [7.5.2] Score is printed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_println(" threads/S");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_007_005 = {
|
||||
"Threads performance, create/exit only",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_007_005_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page nil_test_007_006 [7.6] 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>
|
||||
* - [7.6.1] A semaphore is teken and released. The operation is
|
||||
* repeated continuously in a one-second time window.
|
||||
* - [7.6.2] The score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_007_006_setup(void) {
|
||||
chSemObjectInit(&sem1, 1);
|
||||
}
|
||||
|
||||
static void nil_test_007_006_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
/* [7.6.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 = chTimeAddX(start, TIME_MS2I(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));
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [7.6.2] The score is printed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
test_print("--- Score : ");
|
||||
test_printn(n * 4);
|
||||
test_println(" wait+signal/S");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_007_006 = {
|
||||
"Semaphores wait/signal performance",
|
||||
nil_test_007_006_setup,
|
||||
NULL,
|
||||
nil_test_007_006_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
||||
/**
|
||||
* @page nil_test_007_007 [7.7] RAM Footprint
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The memory size of the various kernel objects is printed.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [7.7.1] The size of the system area is printed.
|
||||
* - [7.7.2] The size of a thread structure is printed.
|
||||
* - [7.7.3] The size of a semaphore structure is printed.
|
||||
* - [7.7.4] The size of an event source is printed.
|
||||
* - [7.7.5] The size of an event listener is printed.
|
||||
* - [7.7.6] The size of a mailbox is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_007_007_execute(void) {
|
||||
|
||||
/* [7.7.1] The size of the system area is printed.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
test_print("--- System: ");
|
||||
test_printn(sizeof(nil_system_t));
|
||||
test_println(" bytes");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [7.7.2] The size of a thread structure is printed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
test_print("--- Thread: ");
|
||||
test_printn(sizeof(thread_t));
|
||||
test_println(" bytes");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [7.7.3] The size of a semaphore structure is printed.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
|
||||
test_print("--- Semaph: ");
|
||||
test_printn(sizeof(semaphore_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [7.7.4] The size of an event source is printed.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
|
||||
test_print("--- EventS: ");
|
||||
test_printn(sizeof(event_source_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
test_end_step(4);
|
||||
|
||||
/* [7.7.5] The size of an event listener is printed.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
|
||||
test_print("--- EventL: ");
|
||||
test_printn(sizeof(event_listener_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
test_end_step(5);
|
||||
|
||||
/* [7.7.6] The size of a mailbox is printed.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
#if CH_CFG_USE_MAILBOXES || defined(__DOXYGEN__)
|
||||
test_print("--- MailB.: ");
|
||||
test_printn(sizeof(mailbox_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
test_end_step(6);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_007_007 = {
|
||||
"RAM Footprint",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_007_007_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
|
@ -637,26 +127,16 @@ static const testcase_t nil_test_007_007 = {
|
|||
* @brief Array of test cases.
|
||||
*/
|
||||
const testcase_t * const nil_test_sequence_007_array[] = {
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
&nil_test_007_001,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
&nil_test_007_002,
|
||||
#endif
|
||||
&nil_test_007_003,
|
||||
&nil_test_007_004,
|
||||
&nil_test_007_005,
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&nil_test_007_006,
|
||||
#endif
|
||||
&nil_test_007_007,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Benchmarks.
|
||||
* @brief Synchronous Messages.
|
||||
*/
|
||||
const testsequence_t nil_test_sequence_007 = {
|
||||
"Benchmarks",
|
||||
"Synchronous Messages",
|
||||
nil_test_sequence_007_array
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_MESSAGES */
|
||||
|
|
|
@ -0,0 +1,662 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 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 "nil_test_root.h"
|
||||
|
||||
/**
|
||||
* @file nil_test_sequence_008.c
|
||||
* @brief Test Sequence 008 code.
|
||||
*
|
||||
* @page nil_test_sequence_008 [8] Benchmarks
|
||||
*
|
||||
* File: @ref nil_test_sequence_008.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 nil_test_008_001
|
||||
* - @subpage nil_test_008_002
|
||||
* - @subpage nil_test_008_003
|
||||
* - @subpage nil_test_008_004
|
||||
* - @subpage nil_test_008_005
|
||||
* - @subpage nil_test_008_006
|
||||
* - @subpage nil_test_008_007
|
||||
* .
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
|
||||
#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 = chTimeAddX(start, TIME_MS2I(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(NIL_STATE_SUSPENDED);
|
||||
msg = self->u1.msg;
|
||||
} while (msg == MSG_OK);
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page nil_test_008_001 [8.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>
|
||||
* - [8.1.1] The messenger thread is started at a lower priority than
|
||||
* the current thread.
|
||||
* - [8.1.2] The number of messages exchanged is counted in a one
|
||||
* second time window.
|
||||
* - [8.1.3] Score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_008_001_execute(void) {
|
||||
uint32_t n;
|
||||
thread_t *tp;
|
||||
|
||||
/* [8.1.1] The messenger thread is started at a lower priority than
|
||||
the current thread.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
thread_descriptor_t td = {
|
||||
.name = "messenger",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() + 1,
|
||||
.funcp = bmk_thread1,
|
||||
.arg = NULL
|
||||
};
|
||||
tp = chThdCreate(&td);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [8.1.2] The number of messages exchanged is counted in a one
|
||||
second time window.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
n = msg_loop_test(tp);
|
||||
chThdWait(tp);
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [8.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");
|
||||
}
|
||||
test_end_step(3);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_008_001 = {
|
||||
"Messages performance #1",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_008_001_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_MESSAGES */
|
||||
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page nil_test_008_002 [8.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>
|
||||
* - [8.2.1] The messenger thread is started at an higher priority than
|
||||
* the current thread.
|
||||
* - [8.2.2] The number of messages exchanged is counted in a one
|
||||
* second time window.
|
||||
* - [8.2.3] Score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_008_002_execute(void) {
|
||||
uint32_t n;
|
||||
thread_t *tp;
|
||||
|
||||
/* [8.2.1] The messenger thread is started at an higher priority than
|
||||
the current thread.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
thread_descriptor_t td = {
|
||||
.name = "messenger",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() - 1,
|
||||
.funcp = bmk_thread1,
|
||||
.arg = NULL
|
||||
};
|
||||
tp = chThdCreate(&td);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [8.2.2] The number of messages exchanged is counted in a one
|
||||
second time window.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
n = msg_loop_test(tp);
|
||||
chThdWait(tp);
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [8.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");
|
||||
}
|
||||
test_end_step(3);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_008_002 = {
|
||||
"Messages performance #2",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_008_002_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_MESSAGES */
|
||||
|
||||
/**
|
||||
* @page nil_test_008_003 [8.3] 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>
|
||||
* - [8.3.1] Starting the target thread at an higher priority level.
|
||||
* - [8.3.2] Waking up the thread as fast as possible in a one second
|
||||
* time window.
|
||||
* - [8.3.3] Stopping the target thread.
|
||||
* - [8.3.4] Score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_008_003_execute(void) {
|
||||
thread_t *tp;
|
||||
uint32_t n;
|
||||
|
||||
/* [8.3.1] Starting the target thread at an higher priority level.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
thread_descriptor_t td = {
|
||||
.name = "messenger",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() - 1,
|
||||
.funcp = bmk_thread4,
|
||||
.arg = NULL
|
||||
};
|
||||
tp = chThdCreate(&td);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [8.3.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 = chTimeAddX(start, TIME_MS2I(1000));
|
||||
do {
|
||||
chSysLock();
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSysUnlock();
|
||||
n += 4;
|
||||
} while (chVTIsSystemTimeWithinX(start, end));
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [8.3.3] Stopping the target thread.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chSysLock();
|
||||
chSchWakeupS(tp, MSG_TIMEOUT);
|
||||
chSysUnlock();
|
||||
chThdWait(tp);
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [8.3.4] Score is printed.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
test_print("--- Score : ");
|
||||
test_printn(n * 2);
|
||||
test_println(" ctxswc/S");
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_008_003 = {
|
||||
"Context Switch performance",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_008_003_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_008_004 [8.4] 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>
|
||||
* - [8.4.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.
|
||||
* - [8.4.2] Score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_008_004_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
/* [8.4.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);
|
||||
{
|
||||
systime_t start, end;
|
||||
thread_descriptor_t td = {
|
||||
.name = "messenger",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() + 1,
|
||||
.funcp = bmk_thread3,
|
||||
.arg = NULL
|
||||
};
|
||||
|
||||
n = 0;
|
||||
start = test_wait_tick();
|
||||
end = chTimeAddX(start, TIME_MS2I(1000));
|
||||
do {
|
||||
chThdWait(chThdCreate(&td));
|
||||
n++;
|
||||
} while (chVTIsSystemTimeWithinX(start, end));
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [8.4.2] Score is printed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_println(" threads/S");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_008_004 = {
|
||||
"Threads performance, full cycle",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_008_004_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page nil_test_008_005 [8.5] 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>
|
||||
* - [8.5.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.
|
||||
* - [8.5.2] Score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_008_005_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
/* [8.5.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);
|
||||
{
|
||||
systime_t start, end;
|
||||
thread_descriptor_t td = {
|
||||
.name = "messenger",
|
||||
.wbase = wa_common,
|
||||
.wend = THD_WORKING_AREA_END(wa_common),
|
||||
.prio = chThdGetPriorityX() - 1,
|
||||
.funcp = bmk_thread3,
|
||||
.arg = NULL
|
||||
};
|
||||
|
||||
n = 0;
|
||||
start = test_wait_tick();
|
||||
end = chTimeAddX(start, TIME_MS2I(1000));
|
||||
do {
|
||||
chThdWait(chThdCreate(&td));
|
||||
n++;
|
||||
} while (chVTIsSystemTimeWithinX(start, end));
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [8.5.2] Score is printed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_println(" threads/S");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_008_005 = {
|
||||
"Threads performance, create/exit only",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_008_005_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page nil_test_008_006 [8.6] 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>
|
||||
* - [8.6.1] A semaphore is teken and released. The operation is
|
||||
* repeated continuously in a one-second time window.
|
||||
* - [8.6.2] The score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_008_006_setup(void) {
|
||||
chSemObjectInit(&sem1, 1);
|
||||
}
|
||||
|
||||
static void nil_test_008_006_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
/* [8.6.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 = chTimeAddX(start, TIME_MS2I(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));
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [8.6.2] The score is printed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
test_print("--- Score : ");
|
||||
test_printn(n * 4);
|
||||
test_println(" wait+signal/S");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_008_006 = {
|
||||
"Semaphores wait/signal performance",
|
||||
nil_test_008_006_setup,
|
||||
NULL,
|
||||
nil_test_008_006_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
||||
/**
|
||||
* @page nil_test_008_007 [8.7] RAM Footprint
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The memory size of the various kernel objects is printed.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [8.7.1] The size of the system area is printed.
|
||||
* - [8.7.2] The size of a thread structure is printed.
|
||||
* - [8.7.3] The size of a semaphore structure is printed.
|
||||
* - [8.7.4] The size of an event source is printed.
|
||||
* - [8.7.5] The size of an event listener is printed.
|
||||
* - [8.7.6] The size of a mailbox is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void nil_test_008_007_execute(void) {
|
||||
|
||||
/* [8.7.1] The size of the system area is printed.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
test_print("--- System: ");
|
||||
test_printn(sizeof(nil_system_t));
|
||||
test_println(" bytes");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [8.7.2] The size of a thread structure is printed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
test_print("--- Thread: ");
|
||||
test_printn(sizeof(thread_t));
|
||||
test_println(" bytes");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [8.7.3] The size of a semaphore structure is printed.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
|
||||
test_print("--- Semaph: ");
|
||||
test_printn(sizeof(semaphore_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [8.7.4] The size of an event source is printed.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
|
||||
test_print("--- EventS: ");
|
||||
test_printn(sizeof(event_source_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
test_end_step(4);
|
||||
|
||||
/* [8.7.5] The size of an event listener is printed.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
|
||||
test_print("--- EventL: ");
|
||||
test_printn(sizeof(event_listener_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
test_end_step(5);
|
||||
|
||||
/* [8.7.6] The size of a mailbox is printed.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
#if CH_CFG_USE_MAILBOXES || defined(__DOXYGEN__)
|
||||
test_print("--- MailB.: ");
|
||||
test_printn(sizeof(mailbox_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
test_end_step(6);
|
||||
}
|
||||
|
||||
static const testcase_t nil_test_008_007 = {
|
||||
"RAM Footprint",
|
||||
NULL,
|
||||
NULL,
|
||||
nil_test_008_007_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Array of test cases.
|
||||
*/
|
||||
const testcase_t * const nil_test_sequence_008_array[] = {
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
&nil_test_008_001,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
&nil_test_008_002,
|
||||
#endif
|
||||
&nil_test_008_003,
|
||||
&nil_test_008_004,
|
||||
&nil_test_008_005,
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&nil_test_008_006,
|
||||
#endif
|
||||
&nil_test_008_007,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Benchmarks.
|
||||
*/
|
||||
const testsequence_t nil_test_sequence_008 = {
|
||||
"Benchmarks",
|
||||
nil_test_sequence_008_array
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 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 nil_test_sequence_008.h
|
||||
* @brief Test Sequence 008 header.
|
||||
*/
|
||||
|
||||
#ifndef NIL_TEST_SEQUENCE_008_H
|
||||
#define NIL_TEST_SEQUENCE_008_H
|
||||
|
||||
extern const testsequence_t nil_test_sequence_008;
|
||||
|
||||
#endif /* NIL_TEST_SEQUENCE_008_H */
|
|
@ -637,6 +637,25 @@ chSysEnable();]]></value>
|
|||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
</cases>
|
||||
</sequence>
|
||||
<sequence>
|
||||
<type index="0">
|
||||
<value>Internal Tests</value>
|
||||
</type>
|
||||
<brief>
|
||||
<value>Time and Intervals Functionality.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>This sequence tests the ChibiOS/NIL functionalities related to time and intervals management.</value>
|
||||
</description>
|
||||
<condition>
|
||||
<value />
|
||||
</condition>
|
||||
<shared_code>
|
||||
<value><![CDATA[#include "ch.h"]]></value>
|
||||
</shared_code>
|
||||
<cases>
|
||||
<case>
|
||||
<brief>
|
||||
<value>System Tick Counter functionality.</value>
|
||||
|
@ -667,16 +686,103 @@ chSysEnable();]]></value>
|
|||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[systime_t time = chVTGetSystemTimeX();
|
||||
while (time == chVTGetSystemTimeX()) {
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
<value><![CDATA[systime_t time = chVTGetSystemTimeX();
|
||||
while (time == chVTGetSystemTimeX()) {
|
||||
}]]></value>
|
||||
</code>
|
||||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
<case>
|
||||
<brief>
|
||||
<value>Time ranges functionality.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>The functionality of the API @p chTimeIsInRangeX() is tested.</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>Checking case where start == end, it must always evaluate as in range.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[
|
||||
bool b;
|
||||
|
||||
b = chTimeIsInRangeX((systime_t)0, (systime_t)0, (systime_t)0);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)-1, (systime_t)0, (systime_t)0);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)0, (systime_t)-1, (systime_t)-1);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)-1, (systime_t)-1, (systime_t)-1);
|
||||
test_assert(b == true, "not in range");
|
||||
]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>Checking boundaries for start < end.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[
|
||||
bool b;
|
||||
|
||||
b = chTimeIsInRangeX((systime_t)10, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)9, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == false, "in range");
|
||||
b = chTimeIsInRangeX((systime_t)99, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)100, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == false, "in range");
|
||||
]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>Checking boundaries for start > end.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[
|
||||
bool b;
|
||||
|
||||
b = chTimeIsInRangeX((systime_t)100, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)99, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == false, "in range");
|
||||
b = chTimeIsInRangeX((systime_t)9, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)10, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == false, "in range");
|
||||
]]></value>
|
||||
</code>
|
||||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
</cases>
|
||||
</sequence>
|
||||
<sequence>
|
||||
|
|
|
@ -9,7 +9,8 @@ TESTSRC += ${CHIBIOS}/test/rt/source/test/rt_test_root.c \
|
|||
${CHIBIOS}/test/rt/source/test/rt_test_sequence_007.c \
|
||||
${CHIBIOS}/test/rt/source/test/rt_test_sequence_008.c \
|
||||
${CHIBIOS}/test/rt/source/test/rt_test_sequence_009.c \
|
||||
${CHIBIOS}/test/rt/source/test/rt_test_sequence_010.c
|
||||
${CHIBIOS}/test/rt/source/test/rt_test_sequence_010.c \
|
||||
${CHIBIOS}/test/rt/source/test/rt_test_sequence_011.c
|
||||
|
||||
# Required include directories
|
||||
TESTINC += ${CHIBIOS}/test/rt/source/test
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
* - @subpage rt_test_sequence_008
|
||||
* - @subpage rt_test_sequence_009
|
||||
* - @subpage rt_test_sequence_010
|
||||
* - @subpage rt_test_sequence_011
|
||||
* .
|
||||
*/
|
||||
|
||||
|
@ -56,22 +57,23 @@ const testsequence_t * const rt_test_suite_array[] = {
|
|||
&rt_test_sequence_002,
|
||||
&rt_test_sequence_003,
|
||||
&rt_test_sequence_004,
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&rt_test_sequence_005,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&rt_test_sequence_006,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
&rt_test_sequence_007,
|
||||
#endif
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
&rt_test_sequence_008,
|
||||
#endif
|
||||
#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
&rt_test_sequence_009,
|
||||
#endif
|
||||
#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
|
||||
&rt_test_sequence_010,
|
||||
#endif
|
||||
&rt_test_sequence_011,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "rt_test_sequence_008.h"
|
||||
#include "rt_test_sequence_009.h"
|
||||
#include "rt_test_sequence_010.h"
|
||||
#include "rt_test_sequence_011.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ static void rt_test_001_001_execute(void) {
|
|||
test_println("");
|
||||
#endif
|
||||
}
|
||||
test_end_step(1);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_001_001 = {
|
||||
|
@ -135,6 +136,7 @@ static void rt_test_001_002_execute(void) {
|
|||
test_printn(CH_KERNEL_PATCH);
|
||||
test_println("");
|
||||
}
|
||||
test_end_step(1);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_001_002 = {
|
||||
|
@ -257,6 +259,7 @@ static void rt_test_001_003_execute(void) {
|
|||
test_printn(CH_DBG_THREADS_PROFILING);
|
||||
test_println("");
|
||||
}
|
||||
test_end_step(1);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_001_003 = {
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
* - @subpage rt_test_002_001
|
||||
* - @subpage rt_test_002_002
|
||||
* - @subpage rt_test_002_003
|
||||
* - @subpage rt_test_002_004
|
||||
* .
|
||||
*/
|
||||
|
||||
|
@ -91,6 +90,7 @@ static void rt_test_002_001_execute(void) {
|
|||
chSysUnlock();
|
||||
test_assert(result == false, "ready list check failed");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [2.1.2] Testing Virtual Timers List integrity.*/
|
||||
test_set_step(2);
|
||||
|
@ -100,6 +100,7 @@ static void rt_test_002_001_execute(void) {
|
|||
chSysUnlock();
|
||||
test_assert(result == false, "virtual timers list check failed");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [2.1.3] Testing Registry List integrity.*/
|
||||
test_set_step(3);
|
||||
|
@ -109,6 +110,7 @@ static void rt_test_002_001_execute(void) {
|
|||
chSysUnlock();
|
||||
test_assert(result == false, "registry list check failed");
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [2.1.4] Testing Port-defined integrity.*/
|
||||
test_set_step(4);
|
||||
|
@ -118,6 +120,7 @@ static void rt_test_002_001_execute(void) {
|
|||
chSysUnlock();
|
||||
test_assert(result == false, "port layer check failed");
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_002_001 = {
|
||||
|
@ -155,6 +158,7 @@ static void rt_test_002_002_execute(void) {
|
|||
sts = chSysGetStatusAndLockX();
|
||||
chSysRestoreStatusX(sts);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [2.2.2] Testing chSysGetStatusAndLockX() and
|
||||
chSysRestoreStatusX(), reentrant case.*/
|
||||
|
@ -165,6 +169,7 @@ static void rt_test_002_002_execute(void) {
|
|||
chSysRestoreStatusX(sts);
|
||||
chSysUnlock();
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [2.2.3] Testing chSysUnconditionalLock().*/
|
||||
test_set_step(3);
|
||||
|
@ -173,6 +178,7 @@ static void rt_test_002_002_execute(void) {
|
|||
chSysUnconditionalLock();
|
||||
chSysUnlock();
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [2.2.4] Testing chSysUnconditionalUnlock().*/
|
||||
test_set_step(4);
|
||||
|
@ -181,6 +187,7 @@ static void rt_test_002_002_execute(void) {
|
|||
chSysUnconditionalUnlock();
|
||||
chSysUnconditionalUnlock();
|
||||
}
|
||||
test_end_step(4);
|
||||
|
||||
/* [2.2.5] Testing from ISR context using a virtual timer.*/
|
||||
test_set_step(5);
|
||||
|
@ -191,6 +198,7 @@ static void rt_test_002_002_execute(void) {
|
|||
|
||||
test_assert(chVTIsArmed(&vt) == false, "timer still armed");
|
||||
}
|
||||
test_end_step(5);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_002_002 = {
|
||||
|
@ -222,6 +230,7 @@ static void rt_test_002_003_execute(void) {
|
|||
chSysSuspend();
|
||||
chSysEnable();
|
||||
}
|
||||
test_end_step(1);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_002_003 = {
|
||||
|
@ -231,40 +240,6 @@ static const testcase_t rt_test_002_003 = {
|
|||
rt_test_002_003_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_test_002_004 [2.4] System Tick Counter functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The functionality of the API @p chVTGetSystemTimeX() is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [2.4.1] A System Tick Counter increment is expected, the test
|
||||
* simply hangs if it does not happen.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_002_004_execute(void) {
|
||||
|
||||
/* [2.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 rt_test_002_004 = {
|
||||
"System Tick Counter functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_002_004_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
@ -276,7 +251,6 @@ const testcase_t * const rt_test_sequence_002_array[] = {
|
|||
&rt_test_002_001,
|
||||
&rt_test_002_002,
|
||||
&rt_test_002_003,
|
||||
&rt_test_002_004,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -21,19 +21,17 @@
|
|||
* @file rt_test_sequence_003.c
|
||||
* @brief Test Sequence 003 code.
|
||||
*
|
||||
* @page rt_test_sequence_003 [3] Threads Functionality
|
||||
* @page rt_test_sequence_003 [3] Time and Intervals Functionality
|
||||
*
|
||||
* File: @ref rt_test_sequence_003.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/RT functionalities related to
|
||||
* threading.
|
||||
* This sequence tests the ChibiOS/NIL functionalities related to time
|
||||
* and intervals management.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage rt_test_003_001
|
||||
* - @subpage rt_test_003_002
|
||||
* - @subpage rt_test_003_003
|
||||
* - @subpage rt_test_003_004
|
||||
* .
|
||||
*/
|
||||
|
||||
|
@ -41,290 +39,117 @@
|
|||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
static THD_FUNCTION(thread, p) {
|
||||
|
||||
test_emit_token(*(char *)p);
|
||||
}
|
||||
#include "ch.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page rt_test_003_001 [3.1] Thread Sleep functionality
|
||||
* @page rt_test_003_001 [3.1] System Tick Counter functionality
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The functionality of @p chThdSleep() and derivatives is tested.
|
||||
* The functionality of the API @p chVTGetSystemTimeX() is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [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.
|
||||
* - [3.1.1] A System Tick Counter increment is expected, the test
|
||||
* simply hangs if it does not happen.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_003_001_execute(void) {
|
||||
systime_t time;
|
||||
|
||||
/* [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.1] A System Tick Counter increment is expected, the test
|
||||
simply hangs if it does not happen.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleep(100);
|
||||
test_assert_time_window(chTimeAddX(time, 100),
|
||||
chTimeAddX(time, 100 + CH_CFG_ST_TIMEDELTA + 1),
|
||||
"out of time window");
|
||||
}
|
||||
|
||||
/* [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);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepMicroseconds(100000);
|
||||
test_assert_time_window(chTimeAddX(time, TIME_US2I(100000)),
|
||||
chTimeAddX(time, TIME_US2I(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(chTimeAddX(time, TIME_MS2I(100)),
|
||||
chTimeAddX(time, TIME_MS2I(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(chTimeAddX(time, TIME_S2I(1)),
|
||||
chTimeAddX(time, TIME_S2I(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(chTimeAddX(time, 100));
|
||||
test_assert_time_window(chTimeAddX(time, 100),
|
||||
chTimeAddX(time, 100 + CH_CFG_ST_TIMEDELTA + 1),
|
||||
"out of time window");
|
||||
systime_t time = chVTGetSystemTimeX();
|
||||
while (time == chVTGetSystemTimeX()) {
|
||||
}
|
||||
}
|
||||
test_end_step(1);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_003_001 = {
|
||||
"Thread Sleep functionality",
|
||||
"System Tick Counter functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_003_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_test_003_002 [3.2] Ready List functionality, threads priority order
|
||||
* @page rt_test_003_002 [3.2] Time ranges 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 functionality of the API @p chTimeIsInRangeX() is tested.
|
||||
*
|
||||
* <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.
|
||||
* - [3.2.1] Checking case where start == end, it must always evaluate
|
||||
* as in range.
|
||||
* - [3.2.2] Checking boundaries for start < end.
|
||||
* - [3.2.3] Checking boundaries for start > end.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_003_002_execute(void) {
|
||||
|
||||
/* [3.2.1] Creating 5 threads with increasing priority, execution
|
||||
sequence is tested.*/
|
||||
/* [3.2.1] Checking case where start == end, it must always evaluate
|
||||
as in range.*/
|
||||
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");
|
||||
}
|
||||
bool b;
|
||||
|
||||
/* [3.2.2] Creating 5 threads with decreasing priority, execution
|
||||
sequence is tested.*/
|
||||
b = chTimeIsInRangeX((systime_t)0, (systime_t)0, (systime_t)0);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)-1, (systime_t)0, (systime_t)0);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)0, (systime_t)-1, (systime_t)-1);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)-1, (systime_t)-1, (systime_t)-1);
|
||||
test_assert(b == true, "not in range");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [3.2.2] Checking boundaries for start < end.*/
|
||||
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");
|
||||
}
|
||||
bool b;
|
||||
|
||||
/* [3.2.3] Creating 5 threads with pseudo-random priority, execution
|
||||
sequence is tested.*/
|
||||
b = chTimeIsInRangeX((systime_t)10, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)9, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == false, "in range");
|
||||
b = chTimeIsInRangeX((systime_t)99, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)100, (systime_t)10, (systime_t)100);
|
||||
test_assert(b == false, "in range");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [3.2.3] Checking boundaries for start > end.*/
|
||||
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");
|
||||
bool b;
|
||||
|
||||
b = chTimeIsInRangeX((systime_t)100, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)99, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == false, "in range");
|
||||
b = chTimeIsInRangeX((systime_t)9, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == true, "not in range");
|
||||
b = chTimeIsInRangeX((systime_t)10, (systime_t)100, (systime_t)10);
|
||||
test_assert(b == false, "in range");
|
||||
}
|
||||
test_end_step(3);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_003_002 = {
|
||||
"Ready List functionality, threads priority order",
|
||||
"Time ranges functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_003_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_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 rt_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 rt_test_003_003 = {
|
||||
"Priority change test",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_003_003_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page rt_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 rt_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 rt_test_003_004 = {
|
||||
"Priority change test with Priority Inheritance",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_003_004_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_MUTEXES */
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
@ -335,17 +160,13 @@ static const testcase_t rt_test_003_004 = {
|
|||
const testcase_t * const rt_test_sequence_003_array[] = {
|
||||
&rt_test_003_001,
|
||||
&rt_test_003_002,
|
||||
&rt_test_003_003,
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
&rt_test_003_004,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Threads Functionality.
|
||||
* @brief Time and Intervals Functionality.
|
||||
*/
|
||||
const testsequence_t rt_test_sequence_003 = {
|
||||
"Threads Functionality",
|
||||
"Time and Intervals Functionality",
|
||||
rt_test_sequence_003_array
|
||||
};
|
||||
|
|
|
@ -21,16 +21,19 @@
|
|||
* @file rt_test_sequence_004.c
|
||||
* @brief Test Sequence 004 code.
|
||||
*
|
||||
* @page rt_test_sequence_004 [4] Suspend/Resume
|
||||
* @page rt_test_sequence_004 [4] Threads Functionality
|
||||
*
|
||||
* File: @ref rt_test_sequence_004.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/RT functionalities related to
|
||||
* threads suspend/resume.
|
||||
* threading.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage rt_test_004_001
|
||||
* - @subpage rt_test_004_002
|
||||
* - @subpage rt_test_004_003
|
||||
* - @subpage rt_test_004_004
|
||||
* .
|
||||
*/
|
||||
|
||||
|
@ -38,14 +41,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);
|
||||
}
|
||||
|
||||
|
@ -54,68 +51,294 @@ static THD_FUNCTION(thread1, p) {
|
|||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page rt_test_004_001 [4.1] Suspend and Resume functionality
|
||||
* @page rt_test_004_001 [4.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>
|
||||
* - [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.
|
||||
* - [4.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.
|
||||
* - [4.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.
|
||||
* - [4.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.
|
||||
* - [4.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.
|
||||
* - [4.1.5] Function chThdSleepUntil() is tested with a timeline of
|
||||
* "now" + 100 ticks.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_004_001_setup(void) {
|
||||
tr1 = NULL;
|
||||
}
|
||||
|
||||
static void rt_test_004_001_execute(void) {
|
||||
systime_t time;
|
||||
msg_t msg;
|
||||
|
||||
/* [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.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(chTimeAddX(time, 100),
|
||||
chTimeAddX(time, 100 + CH_CFG_ST_TIMEDELTA + 1),
|
||||
"out of time window");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [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.*/
|
||||
/* [4.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, TIME_MS2I(1000));
|
||||
chSysUnlock();
|
||||
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
|
||||
chTimeAddX(time, TIME_MS2I(1000) + CH_CFG_ST_TIMEDELTA + 1),
|
||||
chThdSleepMicroseconds(100000);
|
||||
test_assert_time_window(chTimeAddX(time, TIME_US2I(100000)),
|
||||
chTimeAddX(time, TIME_US2I(100000) + CH_CFG_ST_TIMEDELTA + 1),
|
||||
"out of time window");
|
||||
test_assert(NULL == tr1, "not NULL");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong returned message");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [4.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(chTimeAddX(time, TIME_MS2I(100)),
|
||||
chTimeAddX(time, TIME_MS2I(100) + CH_CFG_ST_TIMEDELTA + 1),
|
||||
"out of time window");
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [4.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(chTimeAddX(time, TIME_S2I(1)),
|
||||
chTimeAddX(time, TIME_S2I(1) + CH_CFG_ST_TIMEDELTA + 1),
|
||||
"out of time window");
|
||||
}
|
||||
test_end_step(4);
|
||||
|
||||
/* [4.1.5] Function chThdSleepUntil() is tested with a timeline of
|
||||
"now" + 100 ticks.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleepUntil(chTimeAddX(time, 100));
|
||||
test_assert_time_window(chTimeAddX(time, 100),
|
||||
chTimeAddX(time, 100 + CH_CFG_ST_TIMEDELTA + 1),
|
||||
"out of time window");
|
||||
}
|
||||
test_end_step(5);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_004_001 = {
|
||||
"Suspend and Resume functionality",
|
||||
rt_test_004_001_setup,
|
||||
"Thread Sleep functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_004_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_test_004_002 [4.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>
|
||||
* - [4.2.1] Creating 5 threads with increasing priority, execution
|
||||
* sequence is tested.
|
||||
* - [4.2.2] Creating 5 threads with decreasing priority, execution
|
||||
* sequence is tested.
|
||||
* - [4.2.3] Creating 5 threads with pseudo-random priority, execution
|
||||
* sequence is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_004_002_execute(void) {
|
||||
|
||||
/* [4.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");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [4.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");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [4.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");
|
||||
}
|
||||
test_end_step(3);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_004_002 = {
|
||||
"Ready List functionality, threads priority order",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_004_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_test_004_003 [4.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>
|
||||
* - [4.3.1] Thread priority is increased by one then a check is
|
||||
* performed.
|
||||
* - [4.3.2] Thread priority is returned to the previous value then a
|
||||
* check is performed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_004_003_execute(void) {
|
||||
tprio_t prio, p1;
|
||||
|
||||
/* [4.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");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [4.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");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_004_003 = {
|
||||
"Priority change test",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_004_003_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page rt_test_004_004 [4.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>
|
||||
* - [4.4.1] Simulating a priority boost situation (prio > realprio).
|
||||
* - [4.4.2] Raising thread priority above original priority but below
|
||||
* the boosted level.
|
||||
* - [4.4.3] Raising thread priority above the boosted level.
|
||||
* - [4.4.4] Restoring original conditions.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_004_004_execute(void) {
|
||||
tprio_t prio, p1;
|
||||
|
||||
/* [4.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");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [4.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");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [4.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");
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [4.4.4] Restoring original conditions.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
chSysLock();
|
||||
chThdGetSelfX()->prio = prio;
|
||||
chThdGetSelfX()->realprio = prio;
|
||||
chSysUnlock();
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_004_004 = {
|
||||
"Priority change test with Priority Inheritance",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_004_004_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_MUTEXES */
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
@ -125,13 +348,18 @@ static const testcase_t rt_test_004_001 = {
|
|||
*/
|
||||
const testcase_t * const rt_test_sequence_004_array[] = {
|
||||
&rt_test_004_001,
|
||||
&rt_test_004_002,
|
||||
&rt_test_004_003,
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
&rt_test_004_004,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Suspend/Resume.
|
||||
* @brief Threads Functionality.
|
||||
*/
|
||||
const testsequence_t rt_test_sequence_004 = {
|
||||
"Suspend/Resume",
|
||||
"Threads Functionality",
|
||||
rt_test_sequence_004_array
|
||||
};
|
||||
|
|
|
@ -21,66 +21,32 @@
|
|||
* @file rt_test_sequence_005.c
|
||||
* @brief Test Sequence 005 code.
|
||||
*
|
||||
* @page rt_test_sequence_005 [5] Counter Semaphores
|
||||
* @page rt_test_sequence_005 [5] Suspend/Resume
|
||||
*
|
||||
* File: @ref rt_test_sequence_005.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 rt_test_005_001
|
||||
* - @subpage rt_test_005_002
|
||||
* - @subpage rt_test_005_003
|
||||
* - @subpage rt_test_005_004
|
||||
* - @subpage rt_test_005_005
|
||||
* - @subpage rt_test_005_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);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -88,404 +54,68 @@ static THD_FUNCTION(thread4, p) {
|
|||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page rt_test_005_001 [5.1] Semaphore primitives, no state change
|
||||
* @page rt_test_005_001 [5.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>
|
||||
* - [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.
|
||||
* - [5.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.
|
||||
* - [5.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 rt_test_005_001_setup(void) {
|
||||
chSemObjectInit(&sem1, 1);
|
||||
}
|
||||
|
||||
static void rt_test_005_001_teardown(void) {
|
||||
chSemReset(&sem1, 0);
|
||||
tr1 = NULL;
|
||||
}
|
||||
|
||||
static void rt_test_005_001_execute(void) {
|
||||
|
||||
/* [5.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");
|
||||
}
|
||||
|
||||
/* [5.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");
|
||||
}
|
||||
|
||||
/* [5.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 rt_test_005_001 = {
|
||||
"Semaphore primitives, no state change",
|
||||
rt_test_005_001_setup,
|
||||
rt_test_005_001_teardown,
|
||||
rt_test_005_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_test_005_002 [5.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>
|
||||
* - [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 rt_test_005_002_setup(void) {
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static void rt_test_005_002_execute(void) {
|
||||
|
||||
/* [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);
|
||||
{
|
||||
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 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 rt_test_005_002 = {
|
||||
"Semaphore enqueuing test",
|
||||
rt_test_005_002_setup,
|
||||
NULL,
|
||||
rt_test_005_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_test_005_003 [5.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>
|
||||
* - [5.3.1] Testing special case TIME_IMMEDIATE.
|
||||
* - [5.3.2] Testing non-timeout condition.
|
||||
* - [5.3.3] Testing timeout condition.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_005_003_setup(void) {
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static void rt_test_005_003_execute(void) {
|
||||
unsigned i;
|
||||
systime_t target_time;
|
||||
systime_t time;
|
||||
msg_t msg;
|
||||
|
||||
/* [5.3.1] Testing special case TIME_IMMEDIATE.*/
|
||||
/* [5.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
is remotely resumed with message @p MSG_OK. On return the message
|
||||
and the state of the reference are tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
msg = 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] Testing non-timeout condition.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
thread2, 0);
|
||||
msg = chSemWaitTimeout(&sem1, TIME_MS2I(500));
|
||||
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();
|
||||
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");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [5.3.3] Testing timeout condition.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
target_time = chTimeAddX(test_wait_tick(), TIME_MS2I(5 * 50));
|
||||
for (i = 0; i < 5; i++) {
|
||||
test_emit_token('A' + i);
|
||||
msg = chSemWaitTimeout(&sem1, TIME_MS2I(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,
|
||||
chTimeAddX(target_time, ALLOWED_DELAY),
|
||||
"out of time window");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_005_003 = {
|
||||
"Semaphore timeout test",
|
||||
rt_test_005_003_setup,
|
||||
NULL,
|
||||
rt_test_005_003_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_test_005_004 [5.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>
|
||||
* - [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 rt_test_005_004_setup(void) {
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static void rt_test_005_004_execute(void) {
|
||||
|
||||
/* [5.4.1] A thread is created, it goes to wait on the semaphore.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread1, "A");
|
||||
}
|
||||
|
||||
/* [5.4.2] The semaphore counter is increased by two, it is then
|
||||
tested to be one, the thread must have completed.*/
|
||||
/* [5.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);
|
||||
{
|
||||
chSysLock();
|
||||
chSemAddCounterI(&sem1, 2);
|
||||
chSchRescheduleS();
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chThdSuspendTimeoutS(&tr1, TIME_MS2I(1000));
|
||||
chSysUnlock();
|
||||
test_wait_threads();
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 1, "invalid counter");
|
||||
test_assert_sequence("A", "invalid sequence");
|
||||
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
|
||||
chTimeAddX(time, TIME_MS2I(1000) + CH_CFG_ST_TIMEDELTA + 1),
|
||||
"out of time window");
|
||||
test_assert(NULL == tr1, "not NULL");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong returned message");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_005_004 = {
|
||||
"Testing chSemAddCounterI() functionality",
|
||||
rt_test_005_004_setup,
|
||||
static const testcase_t rt_test_005_001 = {
|
||||
"Suspend and Resume functionality",
|
||||
rt_test_005_001_setup,
|
||||
NULL,
|
||||
rt_test_005_004_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_test_005_005 [5.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>
|
||||
* - [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 rt_test_005_005_setup(void) {
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static void rt_test_005_005_teardown(void) {
|
||||
test_wait_threads();
|
||||
}
|
||||
|
||||
static void rt_test_005_005_execute(void) {
|
||||
|
||||
/* [5.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);
|
||||
}
|
||||
|
||||
/* [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);
|
||||
{
|
||||
chSemSignalWait(&sem1, &sem1);
|
||||
test_assert(queue_isempty(&sem1.queue), "queue not empty");
|
||||
test_assert(sem1.cnt == 0, "counter not zero");
|
||||
}
|
||||
|
||||
/* [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);
|
||||
{
|
||||
chSemSignalWait(&sem1, &sem1);
|
||||
test_assert(queue_isempty(&sem1.queue), "queue not empty");
|
||||
test_assert(sem1.cnt == 0, "counter not zero");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_005_005 = {
|
||||
"Testing chSemWaitSignal() functionality",
|
||||
rt_test_005_005_setup,
|
||||
rt_test_005_005_teardown,
|
||||
rt_test_005_005_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_test_005_006 [5.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>
|
||||
* - [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 rt_test_005_006_teardown(void) {
|
||||
test_wait_threads();
|
||||
}
|
||||
|
||||
static void rt_test_005_006_execute(void) {
|
||||
binary_semaphore_t bsem;
|
||||
msg_t msg;
|
||||
|
||||
/* [5.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");
|
||||
}
|
||||
|
||||
/* [5.6.2] Resetting the binary semaphore in "taken" state, the state
|
||||
must not change.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chBSemReset(&bsem, true);
|
||||
test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken");
|
||||
}
|
||||
|
||||
/* [5.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);
|
||||
}
|
||||
|
||||
/* [5.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");
|
||||
}
|
||||
|
||||
/* [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);
|
||||
{
|
||||
chBSemSignal(&bsem);
|
||||
test_assert_lock(chBSemGetStateI(&bsem) ==false, "still taken");
|
||||
test_assert_lock(chSemGetCounterI(&bsem.sem) == 1, "unexpected counter");
|
||||
}
|
||||
|
||||
/* [5.6.6] Signaling the binary semaphore again, the internal state
|
||||
must not change from "not taken".*/
|
||||
test_set_step(6);
|
||||
{
|
||||
chBSemSignal(&bsem);
|
||||
test_assert_lock(chBSemGetStateI(&bsem) == false, "taken");
|
||||
test_assert_lock(chSemGetCounterI(&bsem.sem) == 1, "unexpected counter");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_005_006 = {
|
||||
"Testing Binary Semaphores special case",
|
||||
NULL,
|
||||
rt_test_005_006_teardown,
|
||||
rt_test_005_006_execute
|
||||
rt_test_005_001_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -497,20 +127,13 @@ static const testcase_t rt_test_005_006 = {
|
|||
*/
|
||||
const testcase_t * const rt_test_sequence_005_array[] = {
|
||||
&rt_test_005_001,
|
||||
&rt_test_005_002,
|
||||
&rt_test_005_003,
|
||||
&rt_test_005_004,
|
||||
&rt_test_005_005,
|
||||
&rt_test_005_006,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Counter Semaphores.
|
||||
* @brief Suspend/Resume.
|
||||
*/
|
||||
const testsequence_t rt_test_sequence_005 = {
|
||||
"Counter Semaphores",
|
||||
"Suspend/Resume",
|
||||
rt_test_sequence_005_array
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -21,56 +21,37 @@
|
|||
* @file rt_test_sequence_008.c
|
||||
* @brief Test Sequence 008 code.
|
||||
*
|
||||
* @page rt_test_sequence_008 [8] Event Sources and Event Flags
|
||||
* @page rt_test_sequence_008 [8] Synchronous Messages
|
||||
*
|
||||
* File: @ref rt_test_sequence_008.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 rt_test_008_001
|
||||
* - @subpage rt_test_008_002
|
||||
* - @subpage rt_test_008_003
|
||||
* - @subpage rt_test_008_004
|
||||
* - @subpage rt_test_008_005
|
||||
* - @subpage rt_test_008_006
|
||||
* - @subpage rt_test_008_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');
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -78,477 +59,56 @@ static THD_FUNCTION(evt_thread7, p) {
|
|||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @page rt_test_008_001 [8.1] Events registration
|
||||
* @page rt_test_008_001 [8.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>
|
||||
* - [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.
|
||||
* - [8.1.1] Starting the messenger thread.
|
||||
* - [8.1.2] Waiting for four messages then testing the receive order.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_008_001_execute(void) {
|
||||
event_listener_t el1, el2;
|
||||
thread_t *tp;
|
||||
msg_t msg;
|
||||
|
||||
/* [8.1.1] An Event Source is initialized.*/
|
||||
/* [8.1.1] Starting the messenger thread.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtObjectInit(&es1);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() + 1,
|
||||
msg_thread1, chThdGetSelfX());
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [8.1.2] Two Event Listeners are registered on the Event Source,
|
||||
the Event Source is tested to have listeners.*/
|
||||
/* [8.1.2] Waiting for four messages then testing the receive
|
||||
order.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es1, &el2, 2);
|
||||
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
|
||||
}
|
||||
unsigned i;
|
||||
|
||||
/* [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");
|
||||
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");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_008_001 = {
|
||||
"Events registration",
|
||||
"Messages Server loop",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_008_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_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 rt_test_008_002_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void rt_test_008_002_execute(void) {
|
||||
|
||||
/* [8.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 rt_test_008_002 = {
|
||||
"Event Flags dispatching",
|
||||
rt_test_008_002_setup,
|
||||
NULL,
|
||||
rt_test_008_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_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.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_008_003_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void rt_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);
|
||||
{
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(m == 1, "single event error");
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(m == 2, "single event error");
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(m == 4, "single event error");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
}
|
||||
|
||||
/* [8.3.3] Getting current time and starting a signaler thread, the
|
||||
thread will set an event flag after 50mS.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
target_time = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread3, chThdGetSelfX());
|
||||
}
|
||||
|
||||
/* [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);
|
||||
{
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert_time_window(target_time,
|
||||
chTimeAddX(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 rt_test_008_003 = {
|
||||
"Events Flags wait using chEvtWaitOne()",
|
||||
rt_test_008_003_setup,
|
||||
NULL,
|
||||
rt_test_008_003_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_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 rt_test_008_004_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void rt_test_008_004_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
|
||||
/* [8.4.1] Setting two, non contiguous, event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(5);
|
||||
}
|
||||
|
||||
/* [8.4.2] Calling chEvtWaitAny() one time, the two flags must be
|
||||
returned.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
m = chEvtWaitAny(ALL_EVENTS);
|
||||
test_assert(m == 5, "unexpected pending bit");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
}
|
||||
|
||||
/* [8.4.3] Getting current time and starting a signaler thread, the
|
||||
thread will set an event flag after 50mS.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
target_time = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread3, chThdGetSelfX());
|
||||
}
|
||||
|
||||
/* [8.4.4] Calling chEvtWaitAny() then verifying that the event has
|
||||
been received after 50mS and that the event flags mask has been
|
||||
emptied.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
m = chEvtWaitAny(ALL_EVENTS);
|
||||
test_assert_time_window(target_time,
|
||||
chTimeAddX(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 rt_test_008_004 = {
|
||||
"Events Flags wait using chEvtWaitAny()",
|
||||
rt_test_008_004_setup,
|
||||
NULL,
|
||||
rt_test_008_004_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_test_008_005 [8.5] Events Flags wait using chEvtWaitAll()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitAll() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [8.5.1] Setting two, non contiguous, event flags.
|
||||
* - [8.5.2] Calling chEvtWaitAll() one time, the two flags must be
|
||||
* returned.
|
||||
* - [8.5.3] Setting one event flag.
|
||||
* - [8.5.4] Getting current time and starting a signaler thread, the
|
||||
* thread will set another event flag after 50mS.
|
||||
* - [8.5.5] Calling chEvtWaitAll() then verifying that both event
|
||||
* flags have been received after 50mS and that the event flags mask
|
||||
* has been emptied.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_008_005_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void rt_test_008_005_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
|
||||
/* [8.5.1] Setting two, non contiguous, event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(5);
|
||||
}
|
||||
|
||||
/* [8.5.2] Calling chEvtWaitAll() one time, the two flags must be
|
||||
returned.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
m = chEvtWaitAll(5);
|
||||
test_assert(m == 5, "unexpected pending bit");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
}
|
||||
|
||||
/* [8.5.3] Setting one event flag.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chEvtAddEvents(4);
|
||||
}
|
||||
|
||||
/* [8.5.4] Getting current time and starting a signaler thread, the
|
||||
thread will set another event flag after 50mS.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
target_time = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread3, chThdGetSelfX());
|
||||
}
|
||||
|
||||
/* [8.5.5] Calling chEvtWaitAll() then verifying that both event
|
||||
flags have been received after 50mS and that the event flags mask
|
||||
has been emptied.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
m = chEvtWaitAll(5);
|
||||
test_assert_time_window(target_time,
|
||||
chTimeAddX(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 rt_test_008_005 = {
|
||||
"Events Flags wait using chEvtWaitAll()",
|
||||
rt_test_008_005_setup,
|
||||
NULL,
|
||||
rt_test_008_005_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page rt_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 rt_test_008_006_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void rt_test_008_006_execute(void) {
|
||||
eventmask_t m;
|
||||
|
||||
/* [8.6.1] The functions are invoked first with TIME_IMMEDIATE
|
||||
timeout, the timeout condition is tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(m == 0, "spurious event");
|
||||
}
|
||||
|
||||
/* [8.6.2] The functions are invoked first with a 50mS timeout, the
|
||||
timeout condition is tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_MS2I(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_MS2I(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_MS2I(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_008_006 = {
|
||||
"Events Flags wait timeouts",
|
||||
rt_test_008_006_setup,
|
||||
NULL,
|
||||
rt_test_008_006_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_EVENTS_TIMEOUT */
|
||||
|
||||
/**
|
||||
* @page rt_test_008_007 [8.7] Broadcasting using chEvtBroadcast()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtBroadcast() is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [8.7.1] Registering on two event sources associating them with
|
||||
* flags 1 and 4.
|
||||
* - [8.7.2] Getting current time and starting a broadcaster thread,
|
||||
* the thread broadcast the first Event Source immediately and the
|
||||
* other after 50mS.
|
||||
* - [8.7.3] Calling chEvtWaitAll() then verifying that both event
|
||||
* flags have been received after 50mS and that the event flags mask
|
||||
* has been emptied.
|
||||
* - [8.7.4] Unregistering from the Event Sources.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_008_007_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
chEvtObjectInit(&es1);
|
||||
chEvtObjectInit(&es2);
|
||||
}
|
||||
|
||||
static void rt_test_008_007_execute(void) {
|
||||
eventmask_t m;
|
||||
event_listener_t el1, el2;
|
||||
systime_t target_time;
|
||||
|
||||
/* [8.7.1] Registering on two event sources associating them with
|
||||
flags 1 and 4.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es2, &el2, 4);
|
||||
}
|
||||
|
||||
/* [8.7.2] Getting current time and starting a broadcaster thread,
|
||||
the thread broadcast the first Event Source immediately and the
|
||||
other after 50mS.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
target_time = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread7, "A");
|
||||
}
|
||||
|
||||
/* [8.7.3] Calling chEvtWaitAll() then verifying that both event
|
||||
flags have been received after 50mS and that the event flags mask
|
||||
has been emptied.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
m = chEvtWaitAll(5);
|
||||
test_assert_time_window(target_time,
|
||||
chTimeAddX(target_time, ALLOWED_DELAY),
|
||||
"out of time window");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
test_wait_threads();
|
||||
}
|
||||
|
||||
/* [8.7.4] Unregistering from the Event Sources.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
chEvtUnregister(&es1, &el1);
|
||||
chEvtUnregister(&es2, &el2);
|
||||
test_assert(!chEvtIsListeningI(&es1), "stuck listener");
|
||||
test_assert(!chEvtIsListeningI(&es2), "stuck listener");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_008_007 = {
|
||||
"Broadcasting using chEvtBroadcast()",
|
||||
rt_test_008_007_setup,
|
||||
NULL,
|
||||
rt_test_008_007_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
@ -558,23 +118,15 @@ static const testcase_t rt_test_008_007 = {
|
|||
*/
|
||||
const testcase_t * const rt_test_sequence_008_array[] = {
|
||||
&rt_test_008_001,
|
||||
&rt_test_008_002,
|
||||
&rt_test_008_003,
|
||||
&rt_test_008_004,
|
||||
&rt_test_008_005,
|
||||
#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
|
||||
&rt_test_008_006,
|
||||
#endif
|
||||
&rt_test_008_007,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Event Sources and Event Flags.
|
||||
* @brief Synchronous Messages.
|
||||
*/
|
||||
const testsequence_t rt_test_sequence_008 = {
|
||||
"Event Sources and Event Flags",
|
||||
"Synchronous Messages",
|
||||
rt_test_sequence_008_array
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_EVENTS */
|
||||
#endif /* CH_CFG_USE_MESSAGES */
|
||||
|
|
|
@ -21,247 +21,557 @@
|
|||
* @file rt_test_sequence_009.c
|
||||
* @brief Test Sequence 009 code.
|
||||
*
|
||||
* @page rt_test_sequence_009 [9] Dynamic threads
|
||||
* @page rt_test_sequence_009 [9] Event Sources and Event Flags
|
||||
*
|
||||
* File: @ref rt_test_sequence_009.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the dynamic thread
|
||||
* creation APIs.
|
||||
* 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_DYNAMIC
|
||||
* - CH_CFG_USE_EVENTS
|
||||
* .
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage rt_test_009_001
|
||||
* - @subpage rt_test_009_002
|
||||
* - @subpage rt_test_009_003
|
||||
* - @subpage rt_test_009_004
|
||||
* - @subpage rt_test_009_005
|
||||
* - @subpage rt_test_009_006
|
||||
* - @subpage rt_test_009_007
|
||||
* .
|
||||
*/
|
||||
|
||||
#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_EVENTS) || 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 EVENTSOURCE_DECL(es1);
|
||||
static EVENTSOURCE_DECL(es2);
|
||||
|
||||
static THD_FUNCTION(dyn_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};
|
||||
|
||||
test_emit_token(*(char *)p);
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page rt_test_009_001 [9.1] Threads creation from Memory Heap
|
||||
* @page rt_test_009_001 [9.1] Events registration
|
||||
*
|
||||
* <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
|
||||
* .
|
||||
* 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>
|
||||
* - [9.1.1] Getting base priority for threads.
|
||||
* - [9.1.2] Getting heap info before the test.
|
||||
* - [9.1.3] Creating thread 1, it is expected to succeed.
|
||||
* - [9.1.4] Creating thread 2, it is expected to succeed.
|
||||
* - [9.1.5] Creating thread 3, it is expected to fail.
|
||||
* - [9.1.6] Letting threads execute then checking the start order and
|
||||
* freeing memory.
|
||||
* - [9.1.7] Getting heap info again for verification.
|
||||
* - [9.1.1] An Event Source is initialized.
|
||||
* - [9.1.2] Two Event Listeners are registered on the Event Source,
|
||||
* the Event Source is tested to have listeners.
|
||||
* - [9.1.3] An Event Listener is unregistered, the Event Source must
|
||||
* still have listeners.
|
||||
* - [9.1.4] An Event Listener is unregistered, the Event Source must
|
||||
* not have listeners.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_009_001_setup(void) {
|
||||
chHeapObjectInit(&heap1, test_buffer, sizeof test_buffer);
|
||||
}
|
||||
|
||||
static void rt_test_009_001_execute(void) {
|
||||
size_t n1, total1, largest1;
|
||||
size_t n2, total2, largest2;
|
||||
tprio_t prio;
|
||||
event_listener_t el1, el2;
|
||||
|
||||
/* [9.1.1] Getting base priority for threads.*/
|
||||
/* [9.1.1] An Event Source is initialized.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
prio = chThdGetPriorityX();
|
||||
chEvtObjectInit(&es1);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [9.1.2] Getting heap info before the test.*/
|
||||
/* [9.1.2] Two Event Listeners are registered on the Event Source,
|
||||
the Event Source is tested to have listeners.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
n1 = chHeapStatus(&heap1, &total1, &largest1);
|
||||
test_assert(n1 == 1, "heap fragmented");
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es1, &el2, 2);
|
||||
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [9.1.3] Creating thread 1, it is expected to succeed.*/
|
||||
/* [9.1.3] An Event Listener is unregistered, the Event Source must
|
||||
still have listeners.*/
|
||||
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");
|
||||
chEvtUnregister(&es1, &el1);
|
||||
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [9.1.4] Creating thread 2, it is expected to succeed.*/
|
||||
/* [9.1.4] An Event Listener is unregistered, the Event Source must
|
||||
not have listeners.*/
|
||||
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");
|
||||
}
|
||||
|
||||
/* [9.1.5] Creating thread 3, it is expected to fail.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
threads[2] = chThdCreateFromHeap(&heap1,
|
||||
(((size_t)-1) >> 1U) + 1U,
|
||||
"dyn3",
|
||||
prio-3, dyn_thread1, "C");
|
||||
test_assert(threads[2] == NULL, "thread creation not failed");
|
||||
}
|
||||
|
||||
/* [9.1.6] Letting threads execute then checking the start order and
|
||||
freeing memory.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
test_wait_threads();
|
||||
test_assert_sequence("AB", "invalid sequence");
|
||||
}
|
||||
|
||||
/* [9.1.7] Getting heap info again for verification.*/
|
||||
test_set_step(7);
|
||||
{
|
||||
n2 = chHeapStatus(&heap1, &total2, &largest2);
|
||||
test_assert(n1 == n2, "fragmentation changed");
|
||||
test_assert(total1 == total2, "total free space changed");
|
||||
test_assert(largest1 == largest2, "largest fragment size changed");
|
||||
chEvtUnregister(&es1, &el2);
|
||||
test_assert_lock(!chEvtIsListeningI(&es1), "stuck listener");
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_009_001 = {
|
||||
"Threads creation from Memory Heap",
|
||||
rt_test_009_001_setup,
|
||||
"Events registration",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_009_001_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_HEAP */
|
||||
|
||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page rt_test_009_002 [9.2] Threads creation from Memory Pool
|
||||
* @page rt_test_009_002 [9.2] Event Flags dispatching
|
||||
*
|
||||
* <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 test dispatches three event flags and verifies that the
|
||||
* associated event handlers are invoked in LSb-first order.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [9.2.1] Adding four working areas to the pool.
|
||||
* - [9.2.2] Getting base priority for threads.
|
||||
* - [9.2.3] Creating the five threads.
|
||||
* - [9.2.4] Testing that only the fifth thread creation failed.
|
||||
* - [9.2.5] Letting them run, free the memory then checking the
|
||||
* execution sequence.
|
||||
* - [9.2.6] Testing that the pool contains four elements again.
|
||||
* - [9.2.1] Three evenf flag bits are raised then chEvtDispatch() is
|
||||
* invoked, the sequence of handlers calls is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_009_002_setup(void) {
|
||||
chPoolObjectInit(&mp1, THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), NULL);
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void rt_test_009_002_execute(void) {
|
||||
unsigned i;
|
||||
tprio_t prio;
|
||||
|
||||
/* [9.2.1] Adding four working areas to the pool.*/
|
||||
/* [9.2.1] Three evenf flag bits are raised then chEvtDispatch() is
|
||||
invoked, the sequence of handlers calls is tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
chPoolFree(&mp1, wa[i]);
|
||||
}
|
||||
|
||||
/* [9.2.2] Getting base priority for threads.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
prio = chThdGetPriorityX();
|
||||
}
|
||||
|
||||
/* [9.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");
|
||||
}
|
||||
|
||||
/* [9.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");
|
||||
}
|
||||
|
||||
/* [9.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");
|
||||
}
|
||||
|
||||
/* [9.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");
|
||||
chEvtDispatch(evhndl, 7);
|
||||
test_assert_sequence("ABC", "invalid sequence");
|
||||
}
|
||||
test_end_step(1);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_009_002 = {
|
||||
"Threads creation from Memory Pool",
|
||||
"Event Flags dispatching",
|
||||
rt_test_009_002_setup,
|
||||
NULL,
|
||||
rt_test_009_002_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_MEMPOOLS */
|
||||
|
||||
/**
|
||||
* @page rt_test_009_003 [9.3] Events Flags wait using chEvtWaitOne()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitOne() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [9.3.1] Setting three event flags.
|
||||
* - [9.3.2] Calling chEvtWaitOne() three times, each time a single
|
||||
* flag must be returned in order of priority.
|
||||
* - [9.3.3] Getting current time and starting a signaler thread, the
|
||||
* thread will set an event flag after 50mS.
|
||||
* - [9.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 rt_test_009_003_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void rt_test_009_003_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
|
||||
/* [9.3.1] Setting three event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(7);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [9.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");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [9.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 = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread3, chThdGetSelfX());
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [9.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,
|
||||
chTimeAddX(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();
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_009_003 = {
|
||||
"Events Flags wait using chEvtWaitOne()",
|
||||
rt_test_009_003_setup,
|
||||
NULL,
|
||||
rt_test_009_003_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_test_009_004 [9.4] Events Flags wait using chEvtWaitAny()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitAny() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [9.4.1] Setting two, non contiguous, event flags.
|
||||
* - [9.4.2] Calling chEvtWaitAny() one time, the two flags must be
|
||||
* returned.
|
||||
* - [9.4.3] Getting current time and starting a signaler thread, the
|
||||
* thread will set an event flag after 50mS.
|
||||
* - [9.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 rt_test_009_004_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void rt_test_009_004_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
|
||||
/* [9.4.1] Setting two, non contiguous, event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(5);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [9.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");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [9.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 = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread3, chThdGetSelfX());
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [9.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,
|
||||
chTimeAddX(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();
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_009_004 = {
|
||||
"Events Flags wait using chEvtWaitAny()",
|
||||
rt_test_009_004_setup,
|
||||
NULL,
|
||||
rt_test_009_004_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_test_009_005 [9.5] Events Flags wait using chEvtWaitAll()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtWaitAll() is tested under various scenarios.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [9.5.1] Setting two, non contiguous, event flags.
|
||||
* - [9.5.2] Calling chEvtWaitAll() one time, the two flags must be
|
||||
* returned.
|
||||
* - [9.5.3] Setting one event flag.
|
||||
* - [9.5.4] Getting current time and starting a signaler thread, the
|
||||
* thread will set another event flag after 50mS.
|
||||
* - [9.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 rt_test_009_005_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void rt_test_009_005_execute(void) {
|
||||
eventmask_t m;
|
||||
systime_t target_time;
|
||||
|
||||
/* [9.5.1] Setting two, non contiguous, event flags.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
chEvtAddEvents(5);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [9.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");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [9.5.3] Setting one event flag.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
chEvtAddEvents(4);
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [9.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 = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread3, chThdGetSelfX());
|
||||
}
|
||||
test_end_step(4);
|
||||
|
||||
/* [9.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,
|
||||
chTimeAddX(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();
|
||||
}
|
||||
test_end_step(5);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_009_005 = {
|
||||
"Events Flags wait using chEvtWaitAll()",
|
||||
rt_test_009_005_setup,
|
||||
NULL,
|
||||
rt_test_009_005_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page rt_test_009_006 [9.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>
|
||||
* - [9.6.1] The functions are invoked first with TIME_IMMEDIATE
|
||||
* timeout, the timeout condition is tested.
|
||||
* - [9.6.2] The functions are invoked first with a 50mS timeout, the
|
||||
* timeout condition is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_009_006_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void rt_test_009_006_execute(void) {
|
||||
eventmask_t m;
|
||||
|
||||
/* [9.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");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [9.6.2] The functions are invoked first with a 50mS timeout, the
|
||||
timeout condition is tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_MS2I(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_MS2I(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_MS2I(50));
|
||||
test_assert(m == 0, "spurious event");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_009_006 = {
|
||||
"Events Flags wait timeouts",
|
||||
rt_test_009_006_setup,
|
||||
NULL,
|
||||
rt_test_009_006_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_EVENTS_TIMEOUT */
|
||||
|
||||
/**
|
||||
* @page rt_test_009_007 [9.7] Broadcasting using chEvtBroadcast()
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Functionality of chEvtBroadcast() is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [9.7.1] Registering on two event sources associating them with
|
||||
* flags 1 and 4.
|
||||
* - [9.7.2] Getting current time and starting a broadcaster thread,
|
||||
* the thread broadcast the first Event Source immediately and the
|
||||
* other after 50mS.
|
||||
* - [9.7.3] Calling chEvtWaitAll() then verifying that both event
|
||||
* flags have been received after 50mS and that the event flags mask
|
||||
* has been emptied.
|
||||
* - [9.7.4] Unregistering from the Event Sources.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_009_007_setup(void) {
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
chEvtObjectInit(&es1);
|
||||
chEvtObjectInit(&es2);
|
||||
}
|
||||
|
||||
static void rt_test_009_007_execute(void) {
|
||||
eventmask_t m;
|
||||
event_listener_t el1, el2;
|
||||
systime_t target_time;
|
||||
|
||||
/* [9.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);
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [9.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 = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
evt_thread7, "A");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [9.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,
|
||||
chTimeAddX(target_time, ALLOWED_DELAY),
|
||||
"out of time window");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(m == 0, "stuck event");
|
||||
test_wait_threads();
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [9.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");
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_009_007 = {
|
||||
"Broadcasting using chEvtBroadcast()",
|
||||
rt_test_009_007_setup,
|
||||
NULL,
|
||||
rt_test_009_007_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
|
@ -271,21 +581,24 @@ static const testcase_t rt_test_009_002 = {
|
|||
* @brief Array of test cases.
|
||||
*/
|
||||
const testcase_t * const rt_test_sequence_009_array[] = {
|
||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
&rt_test_009_001,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
||||
&rt_test_009_002,
|
||||
&rt_test_009_003,
|
||||
&rt_test_009_004,
|
||||
&rt_test_009_005,
|
||||
#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
|
||||
&rt_test_009_006,
|
||||
#endif
|
||||
&rt_test_009_007,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Dynamic threads.
|
||||
* @brief Event Sources and Event Flags.
|
||||
*/
|
||||
const testsequence_t rt_test_sequence_009 = {
|
||||
"Dynamic threads",
|
||||
"Event Sources and Event Flags",
|
||||
rt_test_sequence_009_array
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_DYNAMIC */
|
||||
#endif /* CH_CFG_USE_EVENTS */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 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 rt_test_sequence_011.h
|
||||
* @brief Test Sequence 011 header.
|
||||
*/
|
||||
|
||||
#ifndef RT_TEST_SEQUENCE_011_H
|
||||
#define RT_TEST_SEQUENCE_011_H
|
||||
|
||||
extern const testsequence_t rt_test_sequence_011;
|
||||
|
||||
#endif /* RT_TEST_SEQUENCE_011_H */
|
Loading…
Reference in New Issue