Improvement to time stamps, added test code.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@13745 27425a3e-05d8-49a3-a47f-9c15f0e5edd8
This commit is contained in:
parent
02b653d98c
commit
ffd47a7f3a
|
@ -495,17 +495,24 @@ void chVTDoTickI(void) {
|
||||||
*/
|
*/
|
||||||
systimestamp_t chVTGetTimeStampI(void) {
|
systimestamp_t chVTGetTimeStampI(void) {
|
||||||
systimestamp_t last, stamp;
|
systimestamp_t last, stamp;
|
||||||
|
systime_t now;
|
||||||
|
|
||||||
chDbgCheckClassI();
|
chDbgCheckClassI();
|
||||||
|
|
||||||
|
/* Current system time.*/
|
||||||
|
now = chVTGetSystemTimeX();
|
||||||
|
|
||||||
/* Last time stamp generated.*/
|
/* Last time stamp generated.*/
|
||||||
last = ch.vtlist.laststamp;
|
last = ch.vtlist.laststamp;
|
||||||
|
|
||||||
/* Interval between the last time stamp and current time used for a new
|
/* Interval between the last time stamp and current time used for a new
|
||||||
time stamp. Note that this fails if the interval is larger than a
|
time stamp. Note that this fails if the interval is larger than a
|
||||||
systime_t type.*/
|
systime_t type.*/
|
||||||
stamp = last + (systimestamp_t)chTimeDiffX((sysinterval_t)last,
|
stamp = last + (systimestamp_t)chTimeDiffX((sysinterval_t)last, now);
|
||||||
chVTGetSystemTimeX());
|
|
||||||
|
chDbgAssert(ch.vtlist.laststamp <= stamp, "wrapped");
|
||||||
|
|
||||||
|
/* Storing the new stamp.*/
|
||||||
ch.vtlist.laststamp = stamp;
|
ch.vtlist.laststamp = stamp;
|
||||||
|
|
||||||
return stamp;
|
return stamp;
|
||||||
|
|
|
@ -647,7 +647,7 @@ chSysEnable();]]></value>
|
||||||
<value>Time and Intervals Functionality.</value>
|
<value>Time and Intervals Functionality.</value>
|
||||||
</brief>
|
</brief>
|
||||||
<description>
|
<description>
|
||||||
<value>This sequence tests the ChibiOS/NIL functionalities related to time and intervals management.</value>
|
<value>This sequence tests the ChibiOS/RT functionalities related to time and intervals management.</value>
|
||||||
</description>
|
</description>
|
||||||
<condition>
|
<condition>
|
||||||
<value />
|
<value />
|
||||||
|
@ -788,6 +788,74 @@ test_assert(b == false, "in range");
|
||||||
</case>
|
</case>
|
||||||
</cases>
|
</cases>
|
||||||
</sequence>
|
</sequence>
|
||||||
|
<sequence>
|
||||||
|
<type index="0">
|
||||||
|
<value>Internal Tests</value>
|
||||||
|
</type>
|
||||||
|
<brief>
|
||||||
|
<value>Time Stamps Functionality.</value>
|
||||||
|
</brief>
|
||||||
|
<description>
|
||||||
|
<value>This sequence tests the ChibiOS/RT functionalities related to time stamps.</value>
|
||||||
|
</description>
|
||||||
|
<condition>
|
||||||
|
<value />
|
||||||
|
</condition>
|
||||||
|
<shared_code>
|
||||||
|
<value><![CDATA[#include "ch.h"]]></value>
|
||||||
|
</shared_code>
|
||||||
|
<cases>
|
||||||
|
<case>
|
||||||
|
<brief>
|
||||||
|
<value>Time Stamps functionality.</value>
|
||||||
|
</brief>
|
||||||
|
<description>
|
||||||
|
<value>The functionality of the API @p chVTGetTimeStamp() 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>Time stamps are generated and checked for monotonicity.</value>
|
||||||
|
</description>
|
||||||
|
<tags>
|
||||||
|
<value />
|
||||||
|
</tags>
|
||||||
|
<code>
|
||||||
|
<value><![CDATA[
|
||||||
|
systime_t start, end;
|
||||||
|
systimestamp_t last, now;
|
||||||
|
|
||||||
|
last = chVTGetTimeStamp();
|
||||||
|
start = test_wait_tick();
|
||||||
|
end = chTimeAddX(start, TIME_MS2I(1000));
|
||||||
|
do {
|
||||||
|
now = chVTGetTimeStamp();
|
||||||
|
test_assert(last <= now, "not monotonic");
|
||||||
|
last = now;
|
||||||
|
#if defined(SIMULATOR)
|
||||||
|
_sim_check_for_interrupts();
|
||||||
|
#endif
|
||||||
|
} while (chVTIsSystemTimeWithinX(start, end));]]></value>
|
||||||
|
</code>
|
||||||
|
</step>
|
||||||
|
</steps>
|
||||||
|
</case>
|
||||||
|
</cases>
|
||||||
|
</sequence>
|
||||||
<sequence>
|
<sequence>
|
||||||
<type index="0">
|
<type index="0">
|
||||||
<value>Internal Tests</value>
|
<value>Internal Tests</value>
|
||||||
|
|
|
@ -10,7 +10,8 @@ TESTSRC += ${CHIBIOS}/test/rt/source/test/rt_test_root.c \
|
||||||
${CHIBIOS}/test/rt/source/test/rt_test_sequence_008.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_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
|
${CHIBIOS}/test/rt/source/test/rt_test_sequence_011.c \
|
||||||
|
${CHIBIOS}/test/rt/source/test/rt_test_sequence_012.c
|
||||||
|
|
||||||
# Required include directories
|
# Required include directories
|
||||||
TESTINC += ${CHIBIOS}/test/rt/source/test
|
TESTINC += ${CHIBIOS}/test/rt/source/test
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
* - @subpage rt_test_sequence_009
|
* - @subpage rt_test_sequence_009
|
||||||
* - @subpage rt_test_sequence_010
|
* - @subpage rt_test_sequence_010
|
||||||
* - @subpage rt_test_sequence_011
|
* - @subpage rt_test_sequence_011
|
||||||
|
* - @subpage rt_test_sequence_012
|
||||||
* .
|
* .
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -58,22 +59,23 @@ const testsequence_t * const rt_test_suite_array[] = {
|
||||||
&rt_test_sequence_003,
|
&rt_test_sequence_003,
|
||||||
&rt_test_sequence_004,
|
&rt_test_sequence_004,
|
||||||
&rt_test_sequence_005,
|
&rt_test_sequence_005,
|
||||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
|
||||||
&rt_test_sequence_006,
|
&rt_test_sequence_006,
|
||||||
#endif
|
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
|
||||||
&rt_test_sequence_007,
|
&rt_test_sequence_007,
|
||||||
#endif
|
#endif
|
||||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||||
&rt_test_sequence_008,
|
&rt_test_sequence_008,
|
||||||
#endif
|
#endif
|
||||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||||
&rt_test_sequence_009,
|
&rt_test_sequence_009,
|
||||||
#endif
|
#endif
|
||||||
#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
|
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||||
&rt_test_sequence_010,
|
&rt_test_sequence_010,
|
||||||
#endif
|
#endif
|
||||||
|
#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
|
||||||
&rt_test_sequence_011,
|
&rt_test_sequence_011,
|
||||||
|
#endif
|
||||||
|
&rt_test_sequence_012,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "rt_test_sequence_009.h"
|
#include "rt_test_sequence_009.h"
|
||||||
#include "rt_test_sequence_010.h"
|
#include "rt_test_sequence_010.h"
|
||||||
#include "rt_test_sequence_011.h"
|
#include "rt_test_sequence_011.h"
|
||||||
|
#include "rt_test_sequence_012.h"
|
||||||
|
|
||||||
#if !defined(__DOXYGEN__)
|
#if !defined(__DOXYGEN__)
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* File: @ref rt_test_sequence_003.c
|
* File: @ref rt_test_sequence_003.c
|
||||||
*
|
*
|
||||||
* <h2>Description</h2>
|
* <h2>Description</h2>
|
||||||
* This sequence tests the ChibiOS/NIL functionalities related to time
|
* This sequence tests the ChibiOS/RT functionalities related to time
|
||||||
* and intervals management.
|
* and intervals management.
|
||||||
*
|
*
|
||||||
* <h2>Test Cases</h2>
|
* <h2>Test Cases</h2>
|
||||||
|
|
|
@ -21,19 +21,16 @@
|
||||||
* @file rt_test_sequence_004.c
|
* @file rt_test_sequence_004.c
|
||||||
* @brief Test Sequence 004 code.
|
* @brief Test Sequence 004 code.
|
||||||
*
|
*
|
||||||
* @page rt_test_sequence_004 [4] Threads Functionality
|
* @page rt_test_sequence_004 [4] Time Stamps Functionality
|
||||||
*
|
*
|
||||||
* File: @ref rt_test_sequence_004.c
|
* File: @ref rt_test_sequence_004.c
|
||||||
*
|
*
|
||||||
* <h2>Description</h2>
|
* <h2>Description</h2>
|
||||||
* This sequence tests the ChibiOS/RT functionalities related to
|
* This sequence tests the ChibiOS/RT functionalities related to time
|
||||||
* threading.
|
* stamps.
|
||||||
*
|
*
|
||||||
* <h2>Test Cases</h2>
|
* <h2>Test Cases</h2>
|
||||||
* - @subpage rt_test_004_001
|
* - @subpage rt_test_004_001
|
||||||
* - @subpage rt_test_004_002
|
|
||||||
* - @subpage rt_test_004_003
|
|
||||||
* - @subpage rt_test_004_004
|
|
||||||
* .
|
* .
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -41,304 +38,53 @@
|
||||||
* Shared code.
|
* Shared code.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static THD_FUNCTION(thread, p) {
|
#include "ch.h"
|
||||||
|
|
||||||
test_emit_token(*(char *)p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Test cases.
|
* Test cases.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @page rt_test_004_001 [4.1] Thread Sleep functionality
|
* @page rt_test_004_001 [4.1] Time Stamps functionality
|
||||||
*
|
*
|
||||||
* <h2>Description</h2>
|
* <h2>Description</h2>
|
||||||
* The functionality of @p chThdSleep() and derivatives is tested.
|
* The functionality of the API @p chVTGetTimeStamp() is tested.
|
||||||
*
|
*
|
||||||
* <h2>Test Steps</h2>
|
* <h2>Test Steps</h2>
|
||||||
* - [4.1.1] The current system time is read then a sleep is performed
|
* - [4.1.1] Time stamps are generated and checked for monotonicity.
|
||||||
* 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_execute(void) {
|
static void rt_test_004_001_execute(void) {
|
||||||
systime_t time;
|
|
||||||
|
|
||||||
/* [4.1.1] The current system time is read then a sleep is performed
|
/* [4.1.1] Time stamps are generated and checked for monotonicity.*/
|
||||||
for 100 system ticks and on exit the system time is verified
|
|
||||||
again.*/
|
|
||||||
test_set_step(1);
|
test_set_step(1);
|
||||||
{
|
{
|
||||||
time = chVTGetSystemTimeX();
|
systime_t start, end;
|
||||||
chThdSleep(100);
|
systimestamp_t last, now;
|
||||||
test_assert_time_window(chTimeAddX(time, 100),
|
|
||||||
chTimeAddX(time, 100 + CH_CFG_ST_TIMEDELTA + 1),
|
last = chVTGetTimeStamp();
|
||||||
"out of time window");
|
start = test_wait_tick();
|
||||||
|
end = chTimeAddX(start, TIME_MS2I(1000));
|
||||||
|
do {
|
||||||
|
now = chVTGetTimeStamp();
|
||||||
|
test_assert(last <= now, "not monotonic");
|
||||||
|
last = now;
|
||||||
|
#if defined(SIMULATOR)
|
||||||
|
_sim_check_for_interrupts();
|
||||||
|
#endif
|
||||||
|
} while (chVTIsSystemTimeWithinX(start, end));
|
||||||
}
|
}
|
||||||
test_end_step(1);
|
test_end_step(1);
|
||||||
|
|
||||||
/* [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);
|
|
||||||
{
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
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 = {
|
static const testcase_t rt_test_004_001 = {
|
||||||
"Thread Sleep functionality",
|
"Time Stamps functionality",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
rt_test_004_001_execute
|
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.
|
* Exported data.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -348,18 +94,13 @@ static const testcase_t rt_test_004_004 = {
|
||||||
*/
|
*/
|
||||||
const testcase_t * const rt_test_sequence_004_array[] = {
|
const testcase_t * const rt_test_sequence_004_array[] = {
|
||||||
&rt_test_004_001,
|
&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
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Threads Functionality.
|
* @brief Time Stamps Functionality.
|
||||||
*/
|
*/
|
||||||
const testsequence_t rt_test_sequence_004 = {
|
const testsequence_t rt_test_sequence_004 = {
|
||||||
"Threads Functionality",
|
"Time Stamps Functionality",
|
||||||
rt_test_sequence_004_array
|
rt_test_sequence_004_array
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,16 +21,19 @@
|
||||||
* @file rt_test_sequence_005.c
|
* @file rt_test_sequence_005.c
|
||||||
* @brief Test Sequence 005 code.
|
* @brief Test Sequence 005 code.
|
||||||
*
|
*
|
||||||
* @page rt_test_sequence_005 [5] Suspend/Resume
|
* @page rt_test_sequence_005 [5] Threads Functionality
|
||||||
*
|
*
|
||||||
* File: @ref rt_test_sequence_005.c
|
* File: @ref rt_test_sequence_005.c
|
||||||
*
|
*
|
||||||
* <h2>Description</h2>
|
* <h2>Description</h2>
|
||||||
* This sequence tests the ChibiOS/RT functionalities related to
|
* This sequence tests the ChibiOS/RT functionalities related to
|
||||||
* threads suspend/resume.
|
* threading.
|
||||||
*
|
*
|
||||||
* <h2>Test Cases</h2>
|
* <h2>Test Cases</h2>
|
||||||
* - @subpage rt_test_005_001
|
* - @subpage rt_test_005_001
|
||||||
|
* - @subpage rt_test_005_002
|
||||||
|
* - @subpage rt_test_005_003
|
||||||
|
* - @subpage rt_test_005_004
|
||||||
* .
|
* .
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -38,14 +41,8 @@
|
||||||
* Shared code.
|
* 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);
|
test_emit_token(*(char *)p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,70 +51,294 @@ static THD_FUNCTION(thread1, p) {
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @page rt_test_005_001 [5.1] Suspend and Resume functionality
|
* @page rt_test_005_001 [5.1] Thread Sleep functionality
|
||||||
*
|
*
|
||||||
* <h2>Description</h2>
|
* <h2>Description</h2>
|
||||||
* The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
|
* The functionality of @p chThdSleep() and derivatives is tested.
|
||||||
* tested.
|
|
||||||
*
|
*
|
||||||
* <h2>Test Steps</h2>
|
* <h2>Test Steps</h2>
|
||||||
* - [5.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
* - [5.1.1] The current system time is read then a sleep is performed
|
||||||
* is remotely resumed with message @p MSG_OK. On return the message
|
* for 100 system ticks and on exit the system time is verified
|
||||||
* and the state of the reference are tested.
|
* again.
|
||||||
* - [5.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
* - [5.1.2] The current system time is read then a sleep is performed
|
||||||
* is not resumed so a timeout must occur. On return the message and
|
* for 100000 microseconds and on exit the system time is verified
|
||||||
* the state of the reference are tested.
|
* again.
|
||||||
|
* - [5.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.
|
||||||
|
* - [5.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.
|
||||||
|
* - [5.1.5] Function chThdSleepUntil() is tested with a timeline of
|
||||||
|
* "now" + 100 ticks.
|
||||||
* .
|
* .
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void rt_test_005_001_setup(void) {
|
|
||||||
tr1 = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rt_test_005_001_execute(void) {
|
static void rt_test_005_001_execute(void) {
|
||||||
systime_t time;
|
systime_t time;
|
||||||
msg_t msg;
|
|
||||||
|
|
||||||
/* [5.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
/* [5.1.1] The current system time is read then a sleep is performed
|
||||||
is remotely resumed with message @p MSG_OK. On return the message
|
for 100 system ticks and on exit the system time is verified
|
||||||
and the state of the reference are tested.*/
|
again.*/
|
||||||
test_set_step(1);
|
test_set_step(1);
|
||||||
{
|
{
|
||||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread1, "A");
|
time = chVTGetSystemTimeX();
|
||||||
chSysLock();
|
chThdSleep(100);
|
||||||
msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE);
|
test_assert_time_window(chTimeAddX(time, 100),
|
||||||
chSysUnlock();
|
chTimeAddX(time, 100 + CH_CFG_ST_TIMEDELTA + 1),
|
||||||
test_assert(NULL == tr1, "not NULL");
|
"out of time window");
|
||||||
test_assert(MSG_OK == msg,"wrong returned message");
|
|
||||||
test_wait_threads();
|
|
||||||
}
|
}
|
||||||
test_end_step(1);
|
test_end_step(1);
|
||||||
|
|
||||||
/* [5.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
/* [5.1.2] The current system time is read then a sleep is performed
|
||||||
is not resumed so a timeout must occur. On return the message and
|
for 100000 microseconds and on exit the system time is verified
|
||||||
the state of the reference are tested.*/
|
again.*/
|
||||||
test_set_step(2);
|
test_set_step(2);
|
||||||
{
|
{
|
||||||
chSysLock();
|
|
||||||
time = chVTGetSystemTimeX();
|
time = chVTGetSystemTimeX();
|
||||||
msg = chThdSuspendTimeoutS(&tr1, TIME_MS2I(1000));
|
chThdSleepMicroseconds(100000);
|
||||||
chSysUnlock();
|
test_assert_time_window(chTimeAddX(time, TIME_US2I(100000)),
|
||||||
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
|
chTimeAddX(time, TIME_US2I(100000) + CH_CFG_ST_TIMEDELTA + 1),
|
||||||
chTimeAddX(time, TIME_MS2I(1000) + CH_CFG_ST_TIMEDELTA + 1),
|
|
||||||
"out of time window");
|
"out of time window");
|
||||||
test_assert(NULL == tr1, "not NULL");
|
}
|
||||||
test_assert(MSG_TIMEOUT == msg, "wrong returned message");
|
test_end_step(2);
|
||||||
|
|
||||||
|
/* [5.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);
|
||||||
|
|
||||||
|
/* [5.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);
|
||||||
|
|
||||||
|
/* [5.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_005_001 = {
|
||||||
|
"Thread Sleep functionality",
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
rt_test_005_001_execute
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @page rt_test_005_002 [5.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>
|
||||||
|
* - [5.2.1] Creating 5 threads with increasing priority, execution
|
||||||
|
* sequence is tested.
|
||||||
|
* - [5.2.2] Creating 5 threads with decreasing priority, execution
|
||||||
|
* sequence is tested.
|
||||||
|
* - [5.2.3] Creating 5 threads with pseudo-random priority, execution
|
||||||
|
* sequence is tested.
|
||||||
|
* .
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void rt_test_005_002_execute(void) {
|
||||||
|
|
||||||
|
/* [5.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);
|
||||||
|
|
||||||
|
/* [5.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);
|
||||||
|
|
||||||
|
/* [5.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_005_002 = {
|
||||||
|
"Ready List functionality, threads priority order",
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
rt_test_005_002_execute
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @page rt_test_005_003 [5.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>
|
||||||
|
* - [5.3.1] Thread priority is increased by one then a check is
|
||||||
|
* performed.
|
||||||
|
* - [5.3.2] Thread priority is returned to the previous value then a
|
||||||
|
* check is performed.
|
||||||
|
* .
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void rt_test_005_003_execute(void) {
|
||||||
|
tprio_t prio, p1;
|
||||||
|
|
||||||
|
/* [5.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);
|
||||||
|
|
||||||
|
/* [5.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);
|
test_end_step(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const testcase_t rt_test_005_001 = {
|
static const testcase_t rt_test_005_003 = {
|
||||||
"Suspend and Resume functionality",
|
"Priority change test",
|
||||||
rt_test_005_001_setup,
|
|
||||||
NULL,
|
NULL,
|
||||||
rt_test_005_001_execute
|
NULL,
|
||||||
|
rt_test_005_003_execute
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||||
|
/**
|
||||||
|
* @page rt_test_005_004 [5.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>
|
||||||
|
* - [5.4.1] Simulating a priority boost situation (prio > realprio).
|
||||||
|
* - [5.4.2] Raising thread priority above original priority but below
|
||||||
|
* the boosted level.
|
||||||
|
* - [5.4.3] Raising thread priority above the boosted level.
|
||||||
|
* - [5.4.4] Restoring original conditions.
|
||||||
|
* .
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void rt_test_005_004_execute(void) {
|
||||||
|
tprio_t prio, p1;
|
||||||
|
|
||||||
|
/* [5.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);
|
||||||
|
|
||||||
|
/* [5.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);
|
||||||
|
|
||||||
|
/* [5.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);
|
||||||
|
|
||||||
|
/* [5.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_005_004 = {
|
||||||
|
"Priority change test with Priority Inheritance",
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
rt_test_005_004_execute
|
||||||
|
};
|
||||||
|
#endif /* CH_CFG_USE_MUTEXES */
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Exported data.
|
* Exported data.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -127,13 +348,18 @@ static const testcase_t rt_test_005_001 = {
|
||||||
*/
|
*/
|
||||||
const testcase_t * const rt_test_sequence_005_array[] = {
|
const testcase_t * const rt_test_sequence_005_array[] = {
|
||||||
&rt_test_005_001,
|
&rt_test_005_001,
|
||||||
|
&rt_test_005_002,
|
||||||
|
&rt_test_005_003,
|
||||||
|
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||||
|
&rt_test_005_004,
|
||||||
|
#endif
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Suspend/Resume.
|
* @brief Threads Functionality.
|
||||||
*/
|
*/
|
||||||
const testsequence_t rt_test_sequence_005 = {
|
const testsequence_t rt_test_sequence_005 = {
|
||||||
"Suspend/Resume",
|
"Threads Functionality",
|
||||||
rt_test_sequence_005_array
|
rt_test_sequence_005_array
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,66 +21,32 @@
|
||||||
* @file rt_test_sequence_006.c
|
* @file rt_test_sequence_006.c
|
||||||
* @brief Test Sequence 006 code.
|
* @brief Test Sequence 006 code.
|
||||||
*
|
*
|
||||||
* @page rt_test_sequence_006 [6] Counter Semaphores
|
* @page rt_test_sequence_006 [6] Suspend/Resume
|
||||||
*
|
*
|
||||||
* File: @ref rt_test_sequence_006.c
|
* File: @ref rt_test_sequence_006.c
|
||||||
*
|
*
|
||||||
* <h2>Description</h2>
|
* <h2>Description</h2>
|
||||||
* This sequence tests the ChibiOS/RT functionalities related to
|
* This sequence tests the ChibiOS/RT functionalities related to
|
||||||
* counter semaphores.
|
* threads suspend/resume.
|
||||||
*
|
|
||||||
* <h2>Conditions</h2>
|
|
||||||
* This sequence is only executed if the following preprocessor condition
|
|
||||||
* evaluates to true:
|
|
||||||
* - CH_CFG_USE_SEMAPHORES
|
|
||||||
* .
|
|
||||||
*
|
*
|
||||||
* <h2>Test Cases</h2>
|
* <h2>Test Cases</h2>
|
||||||
* - @subpage rt_test_006_001
|
* - @subpage rt_test_006_001
|
||||||
* - @subpage rt_test_006_002
|
|
||||||
* - @subpage rt_test_006_003
|
|
||||||
* - @subpage rt_test_006_004
|
|
||||||
* - @subpage rt_test_006_005
|
|
||||||
* - @subpage rt_test_006_006
|
|
||||||
* .
|
* .
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Shared code.
|
* Shared code.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "ch.h"
|
static thread_reference_t tr1;
|
||||||
|
|
||||||
static semaphore_t sem1;
|
|
||||||
|
|
||||||
static THD_FUNCTION(thread1, p) {
|
static THD_FUNCTION(thread1, p) {
|
||||||
|
|
||||||
chSemWait(&sem1);
|
|
||||||
test_emit_token(*(char *)p);
|
|
||||||
}
|
|
||||||
|
|
||||||
static THD_FUNCTION(thread2, p) {
|
|
||||||
|
|
||||||
(void)p;
|
|
||||||
chThdSleepMilliseconds(50);
|
|
||||||
chSysLock();
|
chSysLock();
|
||||||
chSemSignalI(&sem1); /* For coverage reasons */
|
chThdResumeI(&tr1, MSG_OK);
|
||||||
chSchRescheduleS();
|
chSchRescheduleS();
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
}
|
test_emit_token(*(char *)p);
|
||||||
|
|
||||||
static THD_FUNCTION(thread3, p) {
|
|
||||||
|
|
||||||
(void)p;
|
|
||||||
chSemWait(&sem1);
|
|
||||||
chSemSignal(&sem1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static THD_FUNCTION(thread4, p) {
|
|
||||||
|
|
||||||
chBSemSignal((binary_semaphore_t *)p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -88,423 +54,68 @@ static THD_FUNCTION(thread4, p) {
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @page rt_test_006_001 [6.1] Semaphore primitives, no state change
|
* @page rt_test_006_001 [6.1] Suspend and Resume functionality
|
||||||
*
|
*
|
||||||
* <h2>Description</h2>
|
* <h2>Description</h2>
|
||||||
* Wait, Signal and Reset primitives are tested. The testing thread
|
* The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
|
||||||
* does not trigger a state change.
|
* tested.
|
||||||
*
|
*
|
||||||
* <h2>Test Steps</h2>
|
* <h2>Test Steps</h2>
|
||||||
* - [6.1.1] The function chSemWait() is invoked, after return the
|
* - [6.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||||
* counter and the returned message are tested.
|
* is remotely resumed with message @p MSG_OK. On return the message
|
||||||
* - [6.1.2] The function chSemSignal() is invoked, after return the
|
* and the state of the reference are tested.
|
||||||
* counter is tested.
|
* - [6.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||||
* - [6.1.3] The function chSemReset() is invoked, after return the
|
* is not resumed so a timeout must occur. On return the message and
|
||||||
* counter is tested.
|
* the state of the reference are tested.
|
||||||
* .
|
* .
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void rt_test_006_001_setup(void) {
|
static void rt_test_006_001_setup(void) {
|
||||||
chSemObjectInit(&sem1, 1);
|
tr1 = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
static void rt_test_006_001_teardown(void) {
|
|
||||||
chSemReset(&sem1, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rt_test_006_001_execute(void) {
|
static void rt_test_006_001_execute(void) {
|
||||||
|
systime_t time;
|
||||||
/* [6.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_t msg;
|
||||||
|
|
||||||
msg = chSemWait(&sem1);
|
/* [6.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
is remotely resumed with message @p MSG_OK. On return the message
|
||||||
test_assert(MSG_OK == msg, "wrong returned message");
|
and the state of the reference are tested.*/
|
||||||
}
|
|
||||||
test_end_step(1);
|
|
||||||
|
|
||||||
/* [6.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);
|
|
||||||
|
|
||||||
/* [6.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 rt_test_006_001 = {
|
|
||||||
"Semaphore primitives, no state change",
|
|
||||||
rt_test_006_001_setup,
|
|
||||||
rt_test_006_001_teardown,
|
|
||||||
rt_test_006_001_execute
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @page rt_test_006_002 [6.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>
|
|
||||||
* - [6.2.1] Five threads are created with mixed priority levels (not
|
|
||||||
* increasing nor decreasing). Threads enqueue on a semaphore
|
|
||||||
* initialized to zero.
|
|
||||||
* - [6.2.2] The semaphore is signaled 5 times. The thread activation
|
|
||||||
* sequence is tested.
|
|
||||||
* .
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void rt_test_006_002_setup(void) {
|
|
||||||
chSemObjectInit(&sem1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rt_test_006_002_execute(void) {
|
|
||||||
|
|
||||||
/* [6.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);
|
test_set_step(1);
|
||||||
{
|
{
|
||||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, thread1, "A");
|
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread1, "A");
|
||||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+1, thread1, "B");
|
chSysLock();
|
||||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, thread1, "C");
|
msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE);
|
||||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+4, thread1, "D");
|
chSysUnlock();
|
||||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+2, thread1, "E");
|
test_assert(NULL == tr1, "not NULL");
|
||||||
}
|
test_assert(MSG_OK == msg,"wrong returned message");
|
||||||
test_end_step(1);
|
|
||||||
|
|
||||||
/* [6.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();
|
test_wait_threads();
|
||||||
#if CH_CFG_USE_SEMAPHORES_PRIORITY
|
|
||||||
test_assert_sequence("ADCEB", "invalid sequence");
|
|
||||||
#else
|
|
||||||
test_assert_sequence("ABCDE", "invalid sequence");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
test_end_step(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const testcase_t rt_test_006_002 = {
|
|
||||||
"Semaphore enqueuing test",
|
|
||||||
rt_test_006_002_setup,
|
|
||||||
NULL,
|
|
||||||
rt_test_006_002_execute
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @page rt_test_006_003 [6.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>
|
|
||||||
* - [6.3.1] Testing special case TIME_IMMEDIATE.
|
|
||||||
* - [6.3.2] Testing non-timeout condition.
|
|
||||||
* - [6.3.3] Testing timeout condition.
|
|
||||||
* .
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void rt_test_006_003_setup(void) {
|
|
||||||
chSemObjectInit(&sem1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rt_test_006_003_execute(void) {
|
|
||||||
unsigned i;
|
|
||||||
systime_t target_time;
|
|
||||||
msg_t msg;
|
|
||||||
|
|
||||||
/* [6.3.1] Testing special case TIME_IMMEDIATE.*/
|
|
||||||
test_set_step(1);
|
|
||||||
{
|
|
||||||
msg = chSemWaitTimeout(&sem1, TIME_IMMEDIATE);
|
|
||||||
test_assert(msg == MSG_TIMEOUT, "wrong wake-up message");
|
|
||||||
test_assert(queue_isempty(&sem1.queue), "queue not empty");
|
|
||||||
test_assert(sem1.cnt == 0, "counter not zero");
|
|
||||||
}
|
}
|
||||||
test_end_step(1);
|
test_end_step(1);
|
||||||
|
|
||||||
/* [6.3.2] Testing non-timeout condition.*/
|
/* [6.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||||
test_set_step(2);
|
is not resumed so a timeout must occur. On return the message and
|
||||||
{
|
the state of the reference are tested.*/
|
||||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
|
||||||
thread2, 0);
|
|
||||||
msg = chSemWaitTimeout(&sem1, TIME_MS2I(500));
|
|
||||||
test_wait_threads();
|
|
||||||
test_assert(msg == MSG_OK, "wrong wake-up message");
|
|
||||||
test_assert(queue_isempty(&sem1.queue), "queue not empty");
|
|
||||||
test_assert(sem1.cnt == 0, "counter not zero");
|
|
||||||
}
|
|
||||||
test_end_step(2);
|
|
||||||
|
|
||||||
/* [6.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");
|
|
||||||
}
|
|
||||||
test_end_step(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const testcase_t rt_test_006_003 = {
|
|
||||||
"Semaphore timeout test",
|
|
||||||
rt_test_006_003_setup,
|
|
||||||
NULL,
|
|
||||||
rt_test_006_003_execute
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @page rt_test_006_004 [6.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>
|
|
||||||
* - [6.4.1] A thread is created, it goes to wait on the semaphore.
|
|
||||||
* - [6.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_006_004_setup(void) {
|
|
||||||
chSemObjectInit(&sem1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rt_test_006_004_execute(void) {
|
|
||||||
|
|
||||||
/* [6.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");
|
|
||||||
}
|
|
||||||
test_end_step(1);
|
|
||||||
|
|
||||||
/* [6.4.2] The semaphore counter is increased by two, it is then
|
|
||||||
tested to be one, the thread must have completed.*/
|
|
||||||
test_set_step(2);
|
test_set_step(2);
|
||||||
{
|
{
|
||||||
chSysLock();
|
chSysLock();
|
||||||
chSemAddCounterI(&sem1, 2);
|
time = chVTGetSystemTimeX();
|
||||||
chSchRescheduleS();
|
msg = chThdSuspendTimeoutS(&tr1, TIME_MS2I(1000));
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
test_wait_threads();
|
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
|
||||||
test_assert_lock(chSemGetCounterI(&sem1) == 1, "invalid counter");
|
chTimeAddX(time, TIME_MS2I(1000) + CH_CFG_ST_TIMEDELTA + 1),
|
||||||
test_assert_sequence("A", "invalid sequence");
|
"out of time window");
|
||||||
|
test_assert(NULL == tr1, "not NULL");
|
||||||
|
test_assert(MSG_TIMEOUT == msg, "wrong returned message");
|
||||||
}
|
}
|
||||||
test_end_step(2);
|
test_end_step(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const testcase_t rt_test_006_004 = {
|
static const testcase_t rt_test_006_001 = {
|
||||||
"Testing chSemAddCounterI() functionality",
|
"Suspend and Resume functionality",
|
||||||
rt_test_006_004_setup,
|
rt_test_006_001_setup,
|
||||||
NULL,
|
NULL,
|
||||||
rt_test_006_004_execute
|
rt_test_006_001_execute
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @page rt_test_006_005 [6.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>
|
|
||||||
* - [6.5.1] An higher priority thread is created that performs
|
|
||||||
* non-atomical wait and signal operations on a semaphore.
|
|
||||||
* - [6.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.
|
|
||||||
* - [6.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_006_005_setup(void) {
|
|
||||||
chSemObjectInit(&sem1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rt_test_006_005_teardown(void) {
|
|
||||||
test_wait_threads();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rt_test_006_005_execute(void) {
|
|
||||||
|
|
||||||
/* [6.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);
|
|
||||||
}
|
|
||||||
test_end_step(1);
|
|
||||||
|
|
||||||
/* [6.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");
|
|
||||||
}
|
|
||||||
test_end_step(2);
|
|
||||||
|
|
||||||
/* [6.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");
|
|
||||||
}
|
|
||||||
test_end_step(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const testcase_t rt_test_006_005 = {
|
|
||||||
"Testing chSemWaitSignal() functionality",
|
|
||||||
rt_test_006_005_setup,
|
|
||||||
rt_test_006_005_teardown,
|
|
||||||
rt_test_006_005_execute
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @page rt_test_006_006 [6.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>
|
|
||||||
* - [6.6.1] Creating a binary semaphore in "taken" state, the state is
|
|
||||||
* checked.
|
|
||||||
* - [6.6.2] Resetting the binary semaphore in "taken" state, the state
|
|
||||||
* must not change.
|
|
||||||
* - [6.6.3] Starting a signaler thread at a lower priority.
|
|
||||||
* - [6.6.4] Waiting for the binary semaphore to be signaled, the
|
|
||||||
* semaphore is expected to be taken.
|
|
||||||
* - [6.6.5] Signaling the binary semaphore, checking the binary
|
|
||||||
* semaphore state to be "not taken" and the underlying counter
|
|
||||||
* semaphore counter to be one.
|
|
||||||
* - [6.6.6] Signaling the binary semaphore again, the internal state
|
|
||||||
* must not change from "not taken".
|
|
||||||
* .
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void rt_test_006_006_teardown(void) {
|
|
||||||
test_wait_threads();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rt_test_006_006_execute(void) {
|
|
||||||
binary_semaphore_t bsem;
|
|
||||||
msg_t msg;
|
|
||||||
|
|
||||||
/* [6.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");
|
|
||||||
}
|
|
||||||
test_end_step(1);
|
|
||||||
|
|
||||||
/* [6.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");
|
|
||||||
}
|
|
||||||
test_end_step(2);
|
|
||||||
|
|
||||||
/* [6.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);
|
|
||||||
}
|
|
||||||
test_end_step(3);
|
|
||||||
|
|
||||||
/* [6.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");
|
|
||||||
}
|
|
||||||
test_end_step(4);
|
|
||||||
|
|
||||||
/* [6.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");
|
|
||||||
}
|
|
||||||
test_end_step(5);
|
|
||||||
|
|
||||||
/* [6.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");
|
|
||||||
}
|
|
||||||
test_end_step(6);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const testcase_t rt_test_006_006 = {
|
|
||||||
"Testing Binary Semaphores special case",
|
|
||||||
NULL,
|
|
||||||
rt_test_006_006_teardown,
|
|
||||||
rt_test_006_006_execute
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -516,20 +127,13 @@ static const testcase_t rt_test_006_006 = {
|
||||||
*/
|
*/
|
||||||
const testcase_t * const rt_test_sequence_006_array[] = {
|
const testcase_t * const rt_test_sequence_006_array[] = {
|
||||||
&rt_test_006_001,
|
&rt_test_006_001,
|
||||||
&rt_test_006_002,
|
|
||||||
&rt_test_006_003,
|
|
||||||
&rt_test_006_004,
|
|
||||||
&rt_test_006_005,
|
|
||||||
&rt_test_006_006,
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Counter Semaphores.
|
* @brief Suspend/Resume.
|
||||||
*/
|
*/
|
||||||
const testsequence_t rt_test_sequence_006 = {
|
const testsequence_t rt_test_sequence_006 = {
|
||||||
"Counter Semaphores",
|
"Suspend/Resume",
|
||||||
rt_test_sequence_006_array
|
rt_test_sequence_006_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_009.c
|
* @file rt_test_sequence_009.c
|
||||||
* @brief Test Sequence 009 code.
|
* @brief Test Sequence 009 code.
|
||||||
*
|
*
|
||||||
* @page rt_test_sequence_009 [9] Event Sources and Event Flags
|
* @page rt_test_sequence_009 [9] Synchronous Messages
|
||||||
*
|
*
|
||||||
* File: @ref rt_test_sequence_009.c
|
* File: @ref rt_test_sequence_009.c
|
||||||
*
|
*
|
||||||
* <h2>Description</h2>
|
* <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>
|
* <h2>Conditions</h2>
|
||||||
* This sequence is only executed if the following preprocessor condition
|
* This sequence is only executed if the following preprocessor condition
|
||||||
* evaluates to true:
|
* evaluates to true:
|
||||||
* - CH_CFG_USE_EVENTS
|
* - CH_CFG_USE_MESSAGES
|
||||||
* .
|
* .
|
||||||
*
|
*
|
||||||
* <h2>Test Cases</h2>
|
* <h2>Test Cases</h2>
|
||||||
* - @subpage rt_test_009_001
|
* - @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_EVENTS) || defined(__DOXYGEN__)
|
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Shared code.
|
* Shared code.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static EVENTSOURCE_DECL(es1);
|
static THD_FUNCTION(msg_thread1, p) {
|
||||||
static EVENTSOURCE_DECL(es2);
|
|
||||||
|
|
||||||
static void h1(eventid_t id) {(void)id;test_emit_token('A');}
|
chMsgSend(p, 'A');
|
||||||
static void h2(eventid_t id) {(void)id;test_emit_token('B');}
|
chMsgSend(p, 'B');
|
||||||
static void h3(eventid_t id) {(void)id;test_emit_token('C');}
|
chMsgSend(p, 'C');
|
||||||
static ROMCONST evhandler_t evhndl[] = {h1, h2, h3};
|
chMsgSend(p, 'D');
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -78,501 +59,56 @@ static THD_FUNCTION(evt_thread7, p) {
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @page rt_test_009_001 [9.1] Events registration
|
* @page rt_test_009_001 [9.1] Messages Server loop
|
||||||
*
|
*
|
||||||
* <h2>Description</h2>
|
* <h2>Description</h2>
|
||||||
* Two event listeners are registered on an event source and then
|
* A messenger thread is spawned that sends four messages back to the
|
||||||
* unregistered in the same order.<br> The test expects that the even
|
* tester thread.<br> The test expect to receive the messages in the
|
||||||
* source has listeners after the registrations and after the first
|
* correct sequence and to not find a fifth message waiting.
|
||||||
* unregistration, then, after the second unegistration, the test
|
|
||||||
* expects no more listeners.
|
|
||||||
*
|
*
|
||||||
* <h2>Test Steps</h2>
|
* <h2>Test Steps</h2>
|
||||||
* - [9.1.1] An Event Source is initialized.
|
* - [9.1.1] Starting the messenger thread.
|
||||||
* - [9.1.2] Two Event Listeners are registered on the Event Source,
|
* - [9.1.2] Waiting for four messages then testing the receive order.
|
||||||
* 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_execute(void) {
|
static void rt_test_009_001_execute(void) {
|
||||||
event_listener_t el1, el2;
|
thread_t *tp;
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
/* [9.1.1] An Event Source is initialized.*/
|
/* [9.1.1] Starting the messenger thread.*/
|
||||||
test_set_step(1);
|
test_set_step(1);
|
||||||
{
|
{
|
||||||
chEvtObjectInit(&es1);
|
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() + 1,
|
||||||
|
msg_thread1, chThdGetSelfX());
|
||||||
}
|
}
|
||||||
test_end_step(1);
|
test_end_step(1);
|
||||||
|
|
||||||
/* [9.1.2] Two Event Listeners are registered on the Event Source,
|
/* [9.1.2] Waiting for four messages then testing the receive
|
||||||
the Event Source is tested to have listeners.*/
|
order.*/
|
||||||
test_set_step(2);
|
test_set_step(2);
|
||||||
{
|
{
|
||||||
chEvtRegisterMask(&es1, &el1, 1);
|
unsigned i;
|
||||||
chEvtRegisterMask(&es1, &el2, 2);
|
|
||||||
test_assert_lock(chEvtIsListeningI(&es1), "no 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);
|
test_end_step(2);
|
||||||
|
|
||||||
/* [9.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);
|
|
||||||
|
|
||||||
/* [9.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 rt_test_009_001 = {
|
static const testcase_t rt_test_009_001 = {
|
||||||
"Events registration",
|
"Messages Server loop",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
rt_test_009_001_execute
|
rt_test_009_001_execute
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @page rt_test_009_002 [9.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>
|
|
||||||
* - [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) {
|
|
||||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rt_test_009_002_execute(void) {
|
|
||||||
|
|
||||||
/* [9.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 rt_test_009_002 = {
|
|
||||||
"Event Flags dispatching",
|
|
||||||
rt_test_009_002_setup,
|
|
||||||
NULL,
|
|
||||||
rt_test_009_002_execute
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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.
|
* Exported data.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -582,23 +118,15 @@ static const testcase_t rt_test_009_007 = {
|
||||||
*/
|
*/
|
||||||
const testcase_t * const rt_test_sequence_009_array[] = {
|
const testcase_t * const rt_test_sequence_009_array[] = {
|
||||||
&rt_test_009_001,
|
&rt_test_009_001,
|
||||||
&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
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Event Sources and Event Flags.
|
* @brief Synchronous Messages.
|
||||||
*/
|
*/
|
||||||
const testsequence_t rt_test_sequence_009 = {
|
const testsequence_t rt_test_sequence_009 = {
|
||||||
"Event Sources and Event Flags",
|
"Synchronous Messages",
|
||||||
rt_test_sequence_009_array
|
rt_test_sequence_009_array
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CH_CFG_USE_EVENTS */
|
#endif /* CH_CFG_USE_MESSAGES */
|
||||||
|
|
|
@ -21,260 +21,557 @@
|
||||||
* @file rt_test_sequence_010.c
|
* @file rt_test_sequence_010.c
|
||||||
* @brief Test Sequence 010 code.
|
* @brief Test Sequence 010 code.
|
||||||
*
|
*
|
||||||
* @page rt_test_sequence_010 [10] Dynamic threads
|
* @page rt_test_sequence_010 [10] Event Sources and Event Flags
|
||||||
*
|
*
|
||||||
* File: @ref rt_test_sequence_010.c
|
* File: @ref rt_test_sequence_010.c
|
||||||
*
|
*
|
||||||
* <h2>Description</h2>
|
* <h2>Description</h2>
|
||||||
* This module implements the test sequence for the dynamic thread
|
* This module implements the test sequence for the Events subsystem.
|
||||||
* creation APIs.
|
|
||||||
*
|
*
|
||||||
* <h2>Conditions</h2>
|
* <h2>Conditions</h2>
|
||||||
* This sequence is only executed if the following preprocessor condition
|
* This sequence is only executed if the following preprocessor condition
|
||||||
* evaluates to true:
|
* evaluates to true:
|
||||||
* - CH_CFG_USE_DYNAMIC
|
* - CH_CFG_USE_EVENTS
|
||||||
* .
|
* .
|
||||||
*
|
*
|
||||||
* <h2>Test Cases</h2>
|
* <h2>Test Cases</h2>
|
||||||
* - @subpage rt_test_010_001
|
* - @subpage rt_test_010_001
|
||||||
* - @subpage rt_test_010_002
|
* - @subpage rt_test_010_002
|
||||||
|
* - @subpage rt_test_010_003
|
||||||
|
* - @subpage rt_test_010_004
|
||||||
|
* - @subpage rt_test_010_005
|
||||||
|
* - @subpage rt_test_010_006
|
||||||
|
* - @subpage rt_test_010_007
|
||||||
* .
|
* .
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
|
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Shared code.
|
* Shared code.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#if CH_CFG_USE_HEAP
|
static EVENTSOURCE_DECL(es1);
|
||||||
static memory_heap_t heap1;
|
static EVENTSOURCE_DECL(es2);
|
||||||
#endif
|
|
||||||
#if CH_CFG_USE_MEMPOOLS
|
|
||||||
static memory_pool_t mp1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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.
|
* Test cases.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
|
||||||
/**
|
/**
|
||||||
* @page rt_test_010_001 [10.1] Threads creation from Memory Heap
|
* @page rt_test_010_001 [10.1] Events registration
|
||||||
*
|
*
|
||||||
* <h2>Description</h2>
|
* <h2>Description</h2>
|
||||||
* Two threads are started by allocating the memory from the Memory
|
* Two event listeners are registered on an event source and then
|
||||||
* Heap then a third thread is started with a huge stack
|
* unregistered in the same order.<br> The test expects that the even
|
||||||
* requirement.<br> The test expects the first two threads to
|
* source has listeners after the registrations and after the first
|
||||||
* successfully start and the third one to fail.
|
* unregistration, then, after the second unegistration, the test
|
||||||
*
|
* expects no more listeners.
|
||||||
* <h2>Conditions</h2>
|
|
||||||
* This test is only executed if the following preprocessor condition
|
|
||||||
* evaluates to true:
|
|
||||||
* - CH_CFG_USE_HEAP
|
|
||||||
* .
|
|
||||||
*
|
*
|
||||||
* <h2>Test Steps</h2>
|
* <h2>Test Steps</h2>
|
||||||
* - [10.1.1] Getting base priority for threads.
|
* - [10.1.1] An Event Source is initialized.
|
||||||
* - [10.1.2] Getting heap info before the test.
|
* - [10.1.2] Two Event Listeners are registered on the Event Source,
|
||||||
* - [10.1.3] Creating thread 1, it is expected to succeed.
|
* the Event Source is tested to have listeners.
|
||||||
* - [10.1.4] Creating thread 2, it is expected to succeed.
|
* - [10.1.3] An Event Listener is unregistered, the Event Source must
|
||||||
* - [10.1.5] Creating thread 3, it is expected to fail.
|
* still have listeners.
|
||||||
* - [10.1.6] Letting threads execute then checking the start order and
|
* - [10.1.4] An Event Listener is unregistered, the Event Source must
|
||||||
* freeing memory.
|
* not have listeners.
|
||||||
* - [10.1.7] Getting heap info again for verification.
|
|
||||||
* .
|
* .
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void rt_test_010_001_setup(void) {
|
|
||||||
chHeapObjectInit(&heap1, test_buffer, sizeof test_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rt_test_010_001_execute(void) {
|
static void rt_test_010_001_execute(void) {
|
||||||
size_t n1, total1, largest1;
|
event_listener_t el1, el2;
|
||||||
size_t n2, total2, largest2;
|
|
||||||
tprio_t prio;
|
|
||||||
|
|
||||||
/* [10.1.1] Getting base priority for threads.*/
|
/* [10.1.1] An Event Source is initialized.*/
|
||||||
test_set_step(1);
|
test_set_step(1);
|
||||||
{
|
{
|
||||||
prio = chThdGetPriorityX();
|
chEvtObjectInit(&es1);
|
||||||
}
|
}
|
||||||
test_end_step(1);
|
test_end_step(1);
|
||||||
|
|
||||||
/* [10.1.2] Getting heap info before the test.*/
|
/* [10.1.2] Two Event Listeners are registered on the Event Source,
|
||||||
|
the Event Source is tested to have listeners.*/
|
||||||
test_set_step(2);
|
test_set_step(2);
|
||||||
{
|
{
|
||||||
n1 = chHeapStatus(&heap1, &total1, &largest1);
|
chEvtRegisterMask(&es1, &el1, 1);
|
||||||
test_assert(n1 == 1, "heap fragmented");
|
chEvtRegisterMask(&es1, &el2, 2);
|
||||||
|
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
|
||||||
}
|
}
|
||||||
test_end_step(2);
|
test_end_step(2);
|
||||||
|
|
||||||
/* [10.1.3] Creating thread 1, it is expected to succeed.*/
|
/* [10.1.3] An Event Listener is unregistered, the Event Source must
|
||||||
|
still have listeners.*/
|
||||||
test_set_step(3);
|
test_set_step(3);
|
||||||
{
|
{
|
||||||
threads[0] = chThdCreateFromHeap(&heap1,
|
chEvtUnregister(&es1, &el1);
|
||||||
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
|
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
|
||||||
"dyn1",
|
|
||||||
prio-1, dyn_thread1, "A");
|
|
||||||
test_assert(threads[0] != NULL, "thread creation failed");
|
|
||||||
}
|
}
|
||||||
test_end_step(3);
|
test_end_step(3);
|
||||||
|
|
||||||
/* [10.1.4] Creating thread 2, it is expected to succeed.*/
|
/* [10.1.4] An Event Listener is unregistered, the Event Source must
|
||||||
|
not have listeners.*/
|
||||||
test_set_step(4);
|
test_set_step(4);
|
||||||
{
|
{
|
||||||
threads[1] = chThdCreateFromHeap(&heap1,
|
chEvtUnregister(&es1, &el2);
|
||||||
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
|
test_assert_lock(!chEvtIsListeningI(&es1), "stuck listener");
|
||||||
"dyn2",
|
|
||||||
prio-2, dyn_thread1, "B");
|
|
||||||
test_assert(threads[1] != NULL, "thread creation failed");
|
|
||||||
}
|
}
|
||||||
test_end_step(4);
|
test_end_step(4);
|
||||||
|
|
||||||
/* [10.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");
|
|
||||||
}
|
|
||||||
test_end_step(5);
|
|
||||||
|
|
||||||
/* [10.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");
|
|
||||||
}
|
|
||||||
test_end_step(6);
|
|
||||||
|
|
||||||
/* [10.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");
|
|
||||||
}
|
|
||||||
test_end_step(7);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const testcase_t rt_test_010_001 = {
|
static const testcase_t rt_test_010_001 = {
|
||||||
"Threads creation from Memory Heap",
|
"Events registration",
|
||||||
rt_test_010_001_setup,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
rt_test_010_001_execute
|
rt_test_010_001_execute
|
||||||
};
|
};
|
||||||
#endif /* CH_CFG_USE_HEAP */
|
|
||||||
|
|
||||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
|
||||||
/**
|
/**
|
||||||
* @page rt_test_010_002 [10.2] Threads creation from Memory Pool
|
* @page rt_test_010_002 [10.2] Event Flags dispatching
|
||||||
*
|
*
|
||||||
* <h2>Description</h2>
|
* <h2>Description</h2>
|
||||||
* Five thread creation are attempted from a pool containing only four
|
* The test dispatches three event flags and verifies that the
|
||||||
* elements.<br> The test expects the first four threads to
|
* associated event handlers are invoked in LSb-first order.
|
||||||
* 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
|
|
||||||
* .
|
|
||||||
*
|
*
|
||||||
* <h2>Test Steps</h2>
|
* <h2>Test Steps</h2>
|
||||||
* - [10.2.1] Adding four working areas to the pool.
|
* - [10.2.1] Three evenf flag bits are raised then chEvtDispatch() is
|
||||||
* - [10.2.2] Getting base priority for threads.
|
* invoked, the sequence of handlers calls is tested.
|
||||||
* - [10.2.3] Creating the five threads.
|
|
||||||
* - [10.2.4] Testing that only the fifth thread creation failed.
|
|
||||||
* - [10.2.5] Letting them run, free the memory then checking the
|
|
||||||
* execution sequence.
|
|
||||||
* - [10.2.6] Testing that the pool contains four elements again.
|
|
||||||
* .
|
* .
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void rt_test_010_002_setup(void) {
|
static void rt_test_010_002_setup(void) {
|
||||||
chPoolObjectInit(&mp1, THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), NULL);
|
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rt_test_010_002_execute(void) {
|
static void rt_test_010_002_execute(void) {
|
||||||
unsigned i;
|
|
||||||
tprio_t prio;
|
|
||||||
|
|
||||||
/* [10.2.1] Adding four working areas to the pool.*/
|
/* [10.2.1] Three evenf flag bits are raised then chEvtDispatch() is
|
||||||
|
invoked, the sequence of handlers calls is tested.*/
|
||||||
test_set_step(1);
|
test_set_step(1);
|
||||||
{
|
{
|
||||||
for (i = 0; i < 4; i++)
|
chEvtDispatch(evhndl, 7);
|
||||||
chPoolFree(&mp1, wa[i]);
|
test_assert_sequence("ABC", "invalid sequence");
|
||||||
}
|
}
|
||||||
test_end_step(1);
|
test_end_step(1);
|
||||||
|
|
||||||
/* [10.2.2] Getting base priority for threads.*/
|
|
||||||
test_set_step(2);
|
|
||||||
{
|
|
||||||
prio = chThdGetPriorityX();
|
|
||||||
}
|
|
||||||
test_end_step(2);
|
|
||||||
|
|
||||||
/* [10.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");
|
|
||||||
}
|
|
||||||
test_end_step(3);
|
|
||||||
|
|
||||||
/* [10.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");
|
|
||||||
}
|
|
||||||
test_end_step(4);
|
|
||||||
|
|
||||||
/* [10.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");
|
|
||||||
}
|
|
||||||
test_end_step(5);
|
|
||||||
|
|
||||||
/* [10.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");
|
|
||||||
}
|
|
||||||
test_end_step(6);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const testcase_t rt_test_010_002 = {
|
static const testcase_t rt_test_010_002 = {
|
||||||
"Threads creation from Memory Pool",
|
"Event Flags dispatching",
|
||||||
rt_test_010_002_setup,
|
rt_test_010_002_setup,
|
||||||
NULL,
|
NULL,
|
||||||
rt_test_010_002_execute
|
rt_test_010_002_execute
|
||||||
};
|
};
|
||||||
#endif /* CH_CFG_USE_MEMPOOLS */
|
|
||||||
|
/**
|
||||||
|
* @page rt_test_010_003 [10.3] Events Flags wait using chEvtWaitOne()
|
||||||
|
*
|
||||||
|
* <h2>Description</h2>
|
||||||
|
* Functionality of chEvtWaitOne() is tested under various scenarios.
|
||||||
|
*
|
||||||
|
* <h2>Test Steps</h2>
|
||||||
|
* - [10.3.1] Setting three event flags.
|
||||||
|
* - [10.3.2] Calling chEvtWaitOne() three times, each time a single
|
||||||
|
* flag must be returned in order of priority.
|
||||||
|
* - [10.3.3] Getting current time and starting a signaler thread, the
|
||||||
|
* thread will set an event flag after 50mS.
|
||||||
|
* - [10.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_010_003_setup(void) {
|
||||||
|
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rt_test_010_003_execute(void) {
|
||||||
|
eventmask_t m;
|
||||||
|
systime_t target_time;
|
||||||
|
|
||||||
|
/* [10.3.1] Setting three event flags.*/
|
||||||
|
test_set_step(1);
|
||||||
|
{
|
||||||
|
chEvtAddEvents(7);
|
||||||
|
}
|
||||||
|
test_end_step(1);
|
||||||
|
|
||||||
|
/* [10.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);
|
||||||
|
|
||||||
|
/* [10.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);
|
||||||
|
|
||||||
|
/* [10.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_010_003 = {
|
||||||
|
"Events Flags wait using chEvtWaitOne()",
|
||||||
|
rt_test_010_003_setup,
|
||||||
|
NULL,
|
||||||
|
rt_test_010_003_execute
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @page rt_test_010_004 [10.4] Events Flags wait using chEvtWaitAny()
|
||||||
|
*
|
||||||
|
* <h2>Description</h2>
|
||||||
|
* Functionality of chEvtWaitAny() is tested under various scenarios.
|
||||||
|
*
|
||||||
|
* <h2>Test Steps</h2>
|
||||||
|
* - [10.4.1] Setting two, non contiguous, event flags.
|
||||||
|
* - [10.4.2] Calling chEvtWaitAny() one time, the two flags must be
|
||||||
|
* returned.
|
||||||
|
* - [10.4.3] Getting current time and starting a signaler thread, the
|
||||||
|
* thread will set an event flag after 50mS.
|
||||||
|
* - [10.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_010_004_setup(void) {
|
||||||
|
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rt_test_010_004_execute(void) {
|
||||||
|
eventmask_t m;
|
||||||
|
systime_t target_time;
|
||||||
|
|
||||||
|
/* [10.4.1] Setting two, non contiguous, event flags.*/
|
||||||
|
test_set_step(1);
|
||||||
|
{
|
||||||
|
chEvtAddEvents(5);
|
||||||
|
}
|
||||||
|
test_end_step(1);
|
||||||
|
|
||||||
|
/* [10.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);
|
||||||
|
|
||||||
|
/* [10.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);
|
||||||
|
|
||||||
|
/* [10.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_010_004 = {
|
||||||
|
"Events Flags wait using chEvtWaitAny()",
|
||||||
|
rt_test_010_004_setup,
|
||||||
|
NULL,
|
||||||
|
rt_test_010_004_execute
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @page rt_test_010_005 [10.5] Events Flags wait using chEvtWaitAll()
|
||||||
|
*
|
||||||
|
* <h2>Description</h2>
|
||||||
|
* Functionality of chEvtWaitAll() is tested under various scenarios.
|
||||||
|
*
|
||||||
|
* <h2>Test Steps</h2>
|
||||||
|
* - [10.5.1] Setting two, non contiguous, event flags.
|
||||||
|
* - [10.5.2] Calling chEvtWaitAll() one time, the two flags must be
|
||||||
|
* returned.
|
||||||
|
* - [10.5.3] Setting one event flag.
|
||||||
|
* - [10.5.4] Getting current time and starting a signaler thread, the
|
||||||
|
* thread will set another event flag after 50mS.
|
||||||
|
* - [10.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_010_005_setup(void) {
|
||||||
|
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rt_test_010_005_execute(void) {
|
||||||
|
eventmask_t m;
|
||||||
|
systime_t target_time;
|
||||||
|
|
||||||
|
/* [10.5.1] Setting two, non contiguous, event flags.*/
|
||||||
|
test_set_step(1);
|
||||||
|
{
|
||||||
|
chEvtAddEvents(5);
|
||||||
|
}
|
||||||
|
test_end_step(1);
|
||||||
|
|
||||||
|
/* [10.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);
|
||||||
|
|
||||||
|
/* [10.5.3] Setting one event flag.*/
|
||||||
|
test_set_step(3);
|
||||||
|
{
|
||||||
|
chEvtAddEvents(4);
|
||||||
|
}
|
||||||
|
test_end_step(3);
|
||||||
|
|
||||||
|
/* [10.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);
|
||||||
|
|
||||||
|
/* [10.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_010_005 = {
|
||||||
|
"Events Flags wait using chEvtWaitAll()",
|
||||||
|
rt_test_010_005_setup,
|
||||||
|
NULL,
|
||||||
|
rt_test_010_005_execute
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
|
||||||
|
/**
|
||||||
|
* @page rt_test_010_006 [10.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>
|
||||||
|
* - [10.6.1] The functions are invoked first with TIME_IMMEDIATE
|
||||||
|
* timeout, the timeout condition is tested.
|
||||||
|
* - [10.6.2] The functions are invoked first with a 50mS timeout, the
|
||||||
|
* timeout condition is tested.
|
||||||
|
* .
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void rt_test_010_006_setup(void) {
|
||||||
|
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rt_test_010_006_execute(void) {
|
||||||
|
eventmask_t m;
|
||||||
|
|
||||||
|
/* [10.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);
|
||||||
|
|
||||||
|
/* [10.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_010_006 = {
|
||||||
|
"Events Flags wait timeouts",
|
||||||
|
rt_test_010_006_setup,
|
||||||
|
NULL,
|
||||||
|
rt_test_010_006_execute
|
||||||
|
};
|
||||||
|
#endif /* CH_CFG_USE_EVENTS_TIMEOUT */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @page rt_test_010_007 [10.7] Broadcasting using chEvtBroadcast()
|
||||||
|
*
|
||||||
|
* <h2>Description</h2>
|
||||||
|
* Functionality of chEvtBroadcast() is tested.
|
||||||
|
*
|
||||||
|
* <h2>Test Steps</h2>
|
||||||
|
* - [10.7.1] Registering on two event sources associating them with
|
||||||
|
* flags 1 and 4.
|
||||||
|
* - [10.7.2] Getting current time and starting a broadcaster thread,
|
||||||
|
* the thread broadcast the first Event Source immediately and the
|
||||||
|
* other after 50mS.
|
||||||
|
* - [10.7.3] Calling chEvtWaitAll() then verifying that both event
|
||||||
|
* flags have been received after 50mS and that the event flags mask
|
||||||
|
* has been emptied.
|
||||||
|
* - [10.7.4] Unregistering from the Event Sources.
|
||||||
|
* .
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void rt_test_010_007_setup(void) {
|
||||||
|
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||||
|
chEvtObjectInit(&es1);
|
||||||
|
chEvtObjectInit(&es2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rt_test_010_007_execute(void) {
|
||||||
|
eventmask_t m;
|
||||||
|
event_listener_t el1, el2;
|
||||||
|
systime_t target_time;
|
||||||
|
|
||||||
|
/* [10.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);
|
||||||
|
|
||||||
|
/* [10.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);
|
||||||
|
|
||||||
|
/* [10.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);
|
||||||
|
|
||||||
|
/* [10.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_010_007 = {
|
||||||
|
"Broadcasting using chEvtBroadcast()",
|
||||||
|
rt_test_010_007_setup,
|
||||||
|
NULL,
|
||||||
|
rt_test_010_007_execute
|
||||||
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Exported data.
|
* Exported data.
|
||||||
|
@ -284,21 +581,24 @@ static const testcase_t rt_test_010_002 = {
|
||||||
* @brief Array of test cases.
|
* @brief Array of test cases.
|
||||||
*/
|
*/
|
||||||
const testcase_t * const rt_test_sequence_010_array[] = {
|
const testcase_t * const rt_test_sequence_010_array[] = {
|
||||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
|
||||||
&rt_test_010_001,
|
&rt_test_010_001,
|
||||||
#endif
|
|
||||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
|
||||||
&rt_test_010_002,
|
&rt_test_010_002,
|
||||||
|
&rt_test_010_003,
|
||||||
|
&rt_test_010_004,
|
||||||
|
&rt_test_010_005,
|
||||||
|
#if (CH_CFG_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
|
||||||
|
&rt_test_010_006,
|
||||||
#endif
|
#endif
|
||||||
|
&rt_test_010_007,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Dynamic threads.
|
* @brief Event Sources and Event Flags.
|
||||||
*/
|
*/
|
||||||
const testsequence_t rt_test_sequence_010 = {
|
const testsequence_t rt_test_sequence_010 = {
|
||||||
"Dynamic threads",
|
"Event Sources and Event Flags",
|
||||||
rt_test_sequence_010_array
|
rt_test_sequence_010_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_012.h
|
||||||
|
* @brief Test Sequence 012 header.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RT_TEST_SEQUENCE_012_H
|
||||||
|
#define RT_TEST_SEQUENCE_012_H
|
||||||
|
|
||||||
|
extern const testsequence_t rt_test_sequence_012;
|
||||||
|
|
||||||
|
#endif /* RT_TEST_SEQUENCE_012_H */
|
Loading…
Reference in New Issue