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 last, stamp;
|
||||
systime_t now;
|
||||
|
||||
chDbgCheckClassI();
|
||||
|
||||
/* Current system time.*/
|
||||
now = chVTGetSystemTimeX();
|
||||
|
||||
/* Last time stamp generated.*/
|
||||
last = ch.vtlist.laststamp;
|
||||
|
||||
/* 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
|
||||
systime_t type.*/
|
||||
stamp = last + (systimestamp_t)chTimeDiffX((sysinterval_t)last,
|
||||
chVTGetSystemTimeX());
|
||||
stamp = last + (systimestamp_t)chTimeDiffX((sysinterval_t)last, now);
|
||||
|
||||
chDbgAssert(ch.vtlist.laststamp <= stamp, "wrapped");
|
||||
|
||||
/* Storing the new stamp.*/
|
||||
ch.vtlist.laststamp = stamp;
|
||||
|
||||
return stamp;
|
||||
|
|
|
@ -647,7 +647,7 @@ chSysEnable();]]></value>
|
|||
<value>Time and Intervals Functionality.</value>
|
||||
</brief>
|
||||
<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>
|
||||
<condition>
|
||||
<value />
|
||||
|
@ -788,6 +788,74 @@ test_assert(b == false, "in range");
|
|||
</case>
|
||||
</cases>
|
||||
</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>
|
||||
<type index="0">
|
||||
<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_009.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
|
||||
TESTINC += ${CHIBIOS}/test/rt/source/test
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
* - @subpage rt_test_sequence_009
|
||||
* - @subpage rt_test_sequence_010
|
||||
* - @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_004,
|
||||
&rt_test_sequence_005,
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&rt_test_sequence_006,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&rt_test_sequence_007,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
&rt_test_sequence_008,
|
||||
#endif
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
|
||||
&rt_test_sequence_009,
|
||||
#endif
|
||||
#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
&rt_test_sequence_010,
|
||||
#endif
|
||||
#if (CH_CFG_USE_DYNAMIC) || defined(__DOXYGEN__)
|
||||
&rt_test_sequence_011,
|
||||
#endif
|
||||
&rt_test_sequence_012,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "rt_test_sequence_009.h"
|
||||
#include "rt_test_sequence_010.h"
|
||||
#include "rt_test_sequence_011.h"
|
||||
#include "rt_test_sequence_012.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* File: @ref rt_test_sequence_003.c
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
|
|
|
@ -21,19 +21,16 @@
|
|||
* @file rt_test_sequence_004.c
|
||||
* @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
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/RT functionalities related to
|
||||
* threading.
|
||||
* This sequence tests the ChibiOS/RT functionalities related to time
|
||||
* stamps.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @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.
|
||||
****************************************************************************/
|
||||
|
||||
static THD_FUNCTION(thread, p) {
|
||||
|
||||
test_emit_token(*(char *)p);
|
||||
}
|
||||
#include "ch.h"
|
||||
|
||||
/****************************************************************************
|
||||
* 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>
|
||||
* The functionality of @p chThdSleep() and derivatives is tested.
|
||||
* The functionality of the API @p chVTGetTimeStamp() is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.1.1] The current system time is read then a sleep is performed
|
||||
* for 100 system ticks and on exit the system time is verified
|
||||
* again.
|
||||
* - [4.1.2] The current system time is read then a sleep is performed
|
||||
* for 100000 microseconds and on exit the system time is verified
|
||||
* again.
|
||||
* - [4.1.3] The current system time is read then a sleep is performed
|
||||
* for 100 milliseconds and on exit the system time is verified
|
||||
* again.
|
||||
* - [4.1.4] The current system time is read then a sleep is performed
|
||||
* for 1 second and on exit the system time is verified again.
|
||||
* - [4.1.5] Function chThdSleepUntil() is tested with a timeline of
|
||||
* "now" + 100 ticks.
|
||||
* - [4.1.1] Time stamps are generated and checked for monotonicity.
|
||||
* .
|
||||
*/
|
||||
|
||||
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
|
||||
for 100 system ticks and on exit the system time is verified
|
||||
again.*/
|
||||
/* [4.1.1] Time stamps are generated and checked for monotonicity.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleep(100);
|
||||
test_assert_time_window(chTimeAddX(time, 100),
|
||||
chTimeAddX(time, 100 + CH_CFG_ST_TIMEDELTA + 1),
|
||||
"out of time window");
|
||||
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));
|
||||
}
|
||||
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 = {
|
||||
"Thread Sleep functionality",
|
||||
"Time Stamps functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_004_001_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_test_004_002 [4.2] Ready List functionality, threads priority order
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads, are enqueued in the ready list and atomically
|
||||
* executed. The test expects the threads to perform their operations
|
||||
* in correct priority order regardless of the initial order.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.2.1] Creating 5 threads with increasing priority, execution
|
||||
* sequence is tested.
|
||||
* - [4.2.2] Creating 5 threads with decreasing priority, execution
|
||||
* sequence is tested.
|
||||
* - [4.2.3] Creating 5 threads with pseudo-random priority, execution
|
||||
* sequence is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_004_002_execute(void) {
|
||||
|
||||
/* [4.2.1] Creating 5 threads with increasing priority, execution
|
||||
sequence is tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
|
||||
test_wait_threads();
|
||||
test_assert_sequence("ABCDE", "invalid sequence");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [4.2.2] Creating 5 threads with decreasing priority, execution
|
||||
sequence is tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
|
||||
test_wait_threads();
|
||||
test_assert_sequence("ABCDE", "invalid sequence");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [4.2.3] Creating 5 threads with pseudo-random priority, execution
|
||||
sequence is tested.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D");
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E");
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A");
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C");
|
||||
test_wait_threads();
|
||||
test_assert_sequence("ABCDE", "invalid sequence");
|
||||
}
|
||||
test_end_step(3);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_004_002 = {
|
||||
"Ready List functionality, threads priority order",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_004_002_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page rt_test_004_003 [4.3] Priority change test
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A series of priority changes are performed on the current thread in
|
||||
* order to verify that the priority change happens as expected.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.3.1] Thread priority is increased by one then a check is
|
||||
* performed.
|
||||
* - [4.3.2] Thread priority is returned to the previous value then a
|
||||
* check is performed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_004_003_execute(void) {
|
||||
tprio_t prio, p1;
|
||||
|
||||
/* [4.3.1] Thread priority is increased by one then a check is
|
||||
performed.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
prio = chThdGetPriorityX();
|
||||
p1 = chThdSetPriority(prio + 1);
|
||||
test_assert(p1 == prio, "unexpected returned priority level");
|
||||
test_assert(chThdGetPriorityX() == prio + 1, "unexpected priority level");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [4.3.2] Thread priority is returned to the previous value then a
|
||||
check is performed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
p1 = chThdSetPriority(p1);
|
||||
test_assert(p1 == prio + 1, "unexpected returned priority level");
|
||||
test_assert(chThdGetPriorityX() == prio, "unexpected priority level");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_004_003 = {
|
||||
"Priority change test",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_004_003_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page rt_test_004_004 [4.4] Priority change test with Priority Inheritance
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A series of priority changes are performed on the current thread in
|
||||
* order to verify that the priority change happens as expected.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_MUTEXES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [4.4.1] Simulating a priority boost situation (prio > realprio).
|
||||
* - [4.4.2] Raising thread priority above original priority but below
|
||||
* the boosted level.
|
||||
* - [4.4.3] Raising thread priority above the boosted level.
|
||||
* - [4.4.4] Restoring original conditions.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_004_004_execute(void) {
|
||||
tprio_t prio, p1;
|
||||
|
||||
/* [4.4.1] Simulating a priority boost situation (prio > realprio).*/
|
||||
test_set_step(1);
|
||||
{
|
||||
prio = chThdGetPriorityX();
|
||||
chThdGetSelfX()->prio += 2;
|
||||
test_assert(chThdGetPriorityX() == prio + 2, "unexpected priority level");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [4.4.2] Raising thread priority above original priority but below
|
||||
the boosted level.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
p1 = chThdSetPriority(prio + 1);
|
||||
test_assert(p1 == prio, "unexpected returned priority level");
|
||||
test_assert(chThdGetSelfX()->prio == prio + 2, "unexpected priority level");
|
||||
test_assert(chThdGetSelfX()->realprio == prio + 1, "unexpected returned real priority level");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [4.4.3] Raising thread priority above the boosted level.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
p1 = chThdSetPriority(prio + 3);
|
||||
test_assert(p1 == prio + 1, "unexpected returned priority level");
|
||||
test_assert(chThdGetSelfX()->prio == prio + 3, "unexpected priority level");
|
||||
test_assert(chThdGetSelfX()->realprio == prio + 3, "unexpected real priority level");
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [4.4.4] Restoring original conditions.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
chSysLock();
|
||||
chThdGetSelfX()->prio = prio;
|
||||
chThdGetSelfX()->realprio = prio;
|
||||
chSysUnlock();
|
||||
}
|
||||
test_end_step(4);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_004_004 = {
|
||||
"Priority change test with Priority Inheritance",
|
||||
NULL,
|
||||
NULL,
|
||||
rt_test_004_004_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_MUTEXES */
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
@ -348,18 +94,13 @@ static const testcase_t rt_test_004_004 = {
|
|||
*/
|
||||
const testcase_t * const rt_test_sequence_004_array[] = {
|
||||
&rt_test_004_001,
|
||||
&rt_test_004_002,
|
||||
&rt_test_004_003,
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
&rt_test_004_004,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Threads Functionality.
|
||||
* @brief Time Stamps Functionality.
|
||||
*/
|
||||
const testsequence_t rt_test_sequence_004 = {
|
||||
"Threads Functionality",
|
||||
"Time Stamps Functionality",
|
||||
rt_test_sequence_004_array
|
||||
};
|
||||
|
|
|
@ -21,16 +21,19 @@
|
|||
* @file rt_test_sequence_005.c
|
||||
* @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
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/RT functionalities related to
|
||||
* threads suspend/resume.
|
||||
* threading.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @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.
|
||||
****************************************************************************/
|
||||
|
||||
static thread_reference_t tr1;
|
||||
static THD_FUNCTION(thread, p) {
|
||||
|
||||
static THD_FUNCTION(thread1, p) {
|
||||
|
||||
chSysLock();
|
||||
chThdResumeI(&tr1, MSG_OK);
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
test_emit_token(*(char *)p);
|
||||
}
|
||||
|
||||
|
@ -54,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>
|
||||
* The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
|
||||
* tested.
|
||||
* The functionality of @p chThdSleep() and derivatives is tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [5.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
* is remotely resumed with message @p MSG_OK. On return the message
|
||||
* and the state of the reference are tested.
|
||||
* - [5.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
* is not resumed so a timeout must occur. On return the message and
|
||||
* the state of the reference are tested.
|
||||
* - [5.1.1] The current system time is read then a sleep is performed
|
||||
* for 100 system ticks and on exit the system time is verified
|
||||
* again.
|
||||
* - [5.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.
|
||||
* - [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) {
|
||||
systime_t time;
|
||||
msg_t msg;
|
||||
|
||||
/* [5.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
is remotely resumed with message @p MSG_OK. On return the message
|
||||
and the state of the reference are tested.*/
|
||||
/* [5.1.1] The current system time is read then a sleep is performed
|
||||
for 100 system ticks and on exit the system time is verified
|
||||
again.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread1, "A");
|
||||
chSysLock();
|
||||
msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE);
|
||||
chSysUnlock();
|
||||
test_assert(NULL == tr1, "not NULL");
|
||||
test_assert(MSG_OK == msg,"wrong returned message");
|
||||
test_wait_threads();
|
||||
time = chVTGetSystemTimeX();
|
||||
chThdSleep(100);
|
||||
test_assert_time_window(chTimeAddX(time, 100),
|
||||
chTimeAddX(time, 100 + CH_CFG_ST_TIMEDELTA + 1),
|
||||
"out of time window");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [5.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
is not resumed so a timeout must occur. On return the message and
|
||||
the state of the reference are tested.*/
|
||||
/* [5.1.2] The current system time is read then a sleep is performed
|
||||
for 100000 microseconds and on exit the system time is verified
|
||||
again.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chSysLock();
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chThdSuspendTimeoutS(&tr1, TIME_MS2I(1000));
|
||||
chSysUnlock();
|
||||
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
|
||||
chTimeAddX(time, TIME_MS2I(1000) + CH_CFG_ST_TIMEDELTA + 1),
|
||||
chThdSleepMicroseconds(100000);
|
||||
test_assert_time_window(chTimeAddX(time, TIME_US2I(100000)),
|
||||
chTimeAddX(time, TIME_US2I(100000) + CH_CFG_ST_TIMEDELTA + 1),
|
||||
"out of time window");
|
||||
test_assert(NULL == tr1, "not NULL");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong returned message");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [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);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_005_001 = {
|
||||
"Suspend and Resume functionality",
|
||||
rt_test_005_001_setup,
|
||||
static const testcase_t rt_test_005_003 = {
|
||||
"Priority change test",
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
@ -127,13 +348,18 @@ static const testcase_t rt_test_005_001 = {
|
|||
*/
|
||||
const testcase_t * const rt_test_sequence_005_array[] = {
|
||||
&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
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Suspend/Resume.
|
||||
* @brief Threads Functionality.
|
||||
*/
|
||||
const testsequence_t rt_test_sequence_005 = {
|
||||
"Suspend/Resume",
|
||||
"Threads Functionality",
|
||||
rt_test_sequence_005_array
|
||||
};
|
||||
|
|
|
@ -21,66 +21,32 @@
|
|||
* @file rt_test_sequence_006.c
|
||||
* @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
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This sequence tests the ChibiOS/RT functionalities related to
|
||||
* counter semaphores.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
* threads suspend/resume.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage rt_test_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.
|
||||
****************************************************************************/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
static semaphore_t sem1;
|
||||
static thread_reference_t tr1;
|
||||
|
||||
static THD_FUNCTION(thread1, p) {
|
||||
|
||||
chSemWait(&sem1);
|
||||
test_emit_token(*(char *)p);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread2, p) {
|
||||
|
||||
(void)p;
|
||||
chThdSleepMilliseconds(50);
|
||||
chSysLock();
|
||||
chSemSignalI(&sem1); /* For coverage reasons */
|
||||
chThdResumeI(&tr1, MSG_OK);
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread3, p) {
|
||||
|
||||
(void)p;
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread4, p) {
|
||||
|
||||
chBSemSignal((binary_semaphore_t *)p);
|
||||
test_emit_token(*(char *)p);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -88,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>
|
||||
* Wait, Signal and Reset primitives are tested. The testing thread
|
||||
* does not trigger a state change.
|
||||
* The functionality of chThdSuspendTimeoutS() and chThdResumeI() is
|
||||
* tested.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [6.1.1] The function chSemWait() is invoked, after return the
|
||||
* counter and the returned message are tested.
|
||||
* - [6.1.2] The function chSemSignal() is invoked, after return the
|
||||
* counter is tested.
|
||||
* - [6.1.3] The function chSemReset() is invoked, after return the
|
||||
* counter is tested.
|
||||
* - [6.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
* is remotely resumed with message @p MSG_OK. On return the message
|
||||
* and the state of the reference are tested.
|
||||
* - [6.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
* is not resumed so a timeout must occur. On return the message and
|
||||
* the state of the reference are tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_006_001_setup(void) {
|
||||
chSemObjectInit(&sem1, 1);
|
||||
}
|
||||
|
||||
static void rt_test_006_001_teardown(void) {
|
||||
chSemReset(&sem1, 0);
|
||||
tr1 = NULL;
|
||||
}
|
||||
|
||||
static void rt_test_006_001_execute(void) {
|
||||
|
||||
/* [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 = chSemWait(&sem1);
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
|
||||
test_assert(MSG_OK == msg, "wrong returned message");
|
||||
}
|
||||
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);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, thread1, "A");
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+1, thread1, "B");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, thread1, "C");
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+4, thread1, "D");
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+2, thread1, "E");
|
||||
}
|
||||
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();
|
||||
#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;
|
||||
systime_t time;
|
||||
msg_t msg;
|
||||
|
||||
/* [6.3.1] Testing special case TIME_IMMEDIATE.*/
|
||||
/* [6.1.1] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
is remotely resumed with message @p MSG_OK. On return the message
|
||||
and the state of the reference are tested.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
msg = chSemWaitTimeout(&sem1, TIME_IMMEDIATE);
|
||||
test_assert(msg == MSG_TIMEOUT, "wrong wake-up message");
|
||||
test_assert(queue_isempty(&sem1.queue), "queue not empty");
|
||||
test_assert(sem1.cnt == 0, "counter not zero");
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [6.3.2] Testing non-timeout condition.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
thread2, 0);
|
||||
msg = chSemWaitTimeout(&sem1, TIME_MS2I(500));
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread1, "A");
|
||||
chSysLock();
|
||||
msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE);
|
||||
chSysUnlock();
|
||||
test_assert(NULL == tr1, "not NULL");
|
||||
test_assert(MSG_OK == msg,"wrong returned message");
|
||||
test_wait_threads();
|
||||
test_assert(msg == MSG_OK, "wrong wake-up message");
|
||||
test_assert(queue_isempty(&sem1.queue), "queue not empty");
|
||||
test_assert(sem1.cnt == 0, "counter not zero");
|
||||
}
|
||||
test_end_step(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.*/
|
||||
/* [6.1.2] The function chThdSuspendTimeoutS() is invoked, the thread
|
||||
is not resumed so a timeout must occur. On return the message and
|
||||
the state of the reference are tested.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chSysLock();
|
||||
chSemAddCounterI(&sem1, 2);
|
||||
chSchRescheduleS();
|
||||
time = chVTGetSystemTimeX();
|
||||
msg = chThdSuspendTimeoutS(&tr1, TIME_MS2I(1000));
|
||||
chSysUnlock();
|
||||
test_wait_threads();
|
||||
test_assert_lock(chSemGetCounterI(&sem1) == 1, "invalid counter");
|
||||
test_assert_sequence("A", "invalid sequence");
|
||||
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
|
||||
chTimeAddX(time, TIME_MS2I(1000) + CH_CFG_ST_TIMEDELTA + 1),
|
||||
"out of time window");
|
||||
test_assert(NULL == tr1, "not NULL");
|
||||
test_assert(MSG_TIMEOUT == msg, "wrong returned message");
|
||||
}
|
||||
test_end_step(2);
|
||||
}
|
||||
|
||||
static const testcase_t rt_test_006_004 = {
|
||||
"Testing chSemAddCounterI() functionality",
|
||||
rt_test_006_004_setup,
|
||||
static const testcase_t rt_test_006_001 = {
|
||||
"Suspend and Resume functionality",
|
||||
rt_test_006_001_setup,
|
||||
NULL,
|
||||
rt_test_006_004_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
|
||||
rt_test_006_001_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -516,20 +127,13 @@ static const testcase_t rt_test_006_006 = {
|
|||
*/
|
||||
const testcase_t * const rt_test_sequence_006_array[] = {
|
||||
&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
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Counter Semaphores.
|
||||
* @brief Suspend/Resume.
|
||||
*/
|
||||
const testsequence_t rt_test_sequence_006 = {
|
||||
"Counter Semaphores",
|
||||
"Suspend/Resume",
|
||||
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
|
||||
* @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
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the Events subsystem.
|
||||
* This module implements the test sequence for the Synchronous
|
||||
* Messages subsystem.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_EVENTS
|
||||
* - CH_CFG_USE_MESSAGES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage rt_test_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.
|
||||
****************************************************************************/
|
||||
|
||||
static EVENTSOURCE_DECL(es1);
|
||||
static EVENTSOURCE_DECL(es2);
|
||||
static THD_FUNCTION(msg_thread1, p) {
|
||||
|
||||
static void h1(eventid_t id) {(void)id;test_emit_token('A');}
|
||||
static void h2(eventid_t id) {(void)id;test_emit_token('B');}
|
||||
static void h3(eventid_t id) {(void)id;test_emit_token('C');}
|
||||
static ROMCONST evhandler_t evhndl[] = {h1, h2, h3};
|
||||
|
||||
static THD_FUNCTION(evt_thread3, p) {
|
||||
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtSignal((thread_t *)p, 1);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(evt_thread7, p) {
|
||||
|
||||
(void)p;
|
||||
chEvtBroadcast(&es1);
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtBroadcast(&es2);
|
||||
chMsgSend(p, 'A');
|
||||
chMsgSend(p, 'B');
|
||||
chMsgSend(p, 'C');
|
||||
chMsgSend(p, 'D');
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -78,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>
|
||||
* Two event listeners are registered on an event source and then
|
||||
* unregistered in the same order.<br> The test expects that the even
|
||||
* source has listeners after the registrations and after the first
|
||||
* unregistration, then, after the second unegistration, the test
|
||||
* expects no more listeners.
|
||||
* A messenger thread is spawned that sends four messages back to the
|
||||
* tester thread.<br> The test expect to receive the messages in the
|
||||
* correct sequence and to not find a fifth message waiting.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [9.1.1] An Event Source is initialized.
|
||||
* - [9.1.2] Two Event Listeners are registered on the Event Source,
|
||||
* the Event Source is tested to have listeners.
|
||||
* - [9.1.3] An Event Listener is unregistered, the Event Source must
|
||||
* still have listeners.
|
||||
* - [9.1.4] An Event Listener is unregistered, the Event Source must
|
||||
* not have listeners.
|
||||
* - [9.1.1] Starting the messenger thread.
|
||||
* - [9.1.2] Waiting for four messages then testing the receive order.
|
||||
* .
|
||||
*/
|
||||
|
||||
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);
|
||||
{
|
||||
chEvtObjectInit(&es1);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() + 1,
|
||||
msg_thread1, chThdGetSelfX());
|
||||
}
|
||||
test_end_step(1);
|
||||
|
||||
/* [9.1.2] Two Event Listeners are registered on the Event Source,
|
||||
the Event Source is tested to have listeners.*/
|
||||
/* [9.1.2] Waiting for four messages then testing the receive
|
||||
order.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es1, &el2, 2);
|
||||
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
|
||||
unsigned i;
|
||||
|
||||
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);
|
||||
|
||||
/* [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 = {
|
||||
"Events registration",
|
||||
"Messages Server loop",
|
||||
NULL,
|
||||
NULL,
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
@ -582,23 +118,15 @@ static const testcase_t rt_test_009_007 = {
|
|||
*/
|
||||
const testcase_t * const rt_test_sequence_009_array[] = {
|
||||
&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
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Event Sources and Event Flags.
|
||||
* @brief Synchronous Messages.
|
||||
*/
|
||||
const testsequence_t rt_test_sequence_009 = {
|
||||
"Event Sources and Event Flags",
|
||||
"Synchronous Messages",
|
||||
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
|
||||
* @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
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the dynamic thread
|
||||
* creation APIs.
|
||||
* This module implements the test sequence for the Events subsystem.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_DYNAMIC
|
||||
* - CH_CFG_USE_EVENTS
|
||||
* .
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage rt_test_010_001
|
||||
* - @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.
|
||||
****************************************************************************/
|
||||
|
||||
#if CH_CFG_USE_HEAP
|
||||
static memory_heap_t heap1;
|
||||
#endif
|
||||
#if CH_CFG_USE_MEMPOOLS
|
||||
static memory_pool_t mp1;
|
||||
#endif
|
||||
static EVENTSOURCE_DECL(es1);
|
||||
static EVENTSOURCE_DECL(es2);
|
||||
|
||||
static THD_FUNCTION(dyn_thread1, p) {
|
||||
static void h1(eventid_t id) {(void)id;test_emit_token('A');}
|
||||
static void h2(eventid_t id) {(void)id;test_emit_token('B');}
|
||||
static void h3(eventid_t id) {(void)id;test_emit_token('C');}
|
||||
static ROMCONST evhandler_t evhndl[] = {h1, h2, h3};
|
||||
|
||||
test_emit_token(*(char *)p);
|
||||
static THD_FUNCTION(evt_thread3, p) {
|
||||
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtSignal((thread_t *)p, 1);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(evt_thread7, p) {
|
||||
|
||||
(void)p;
|
||||
chEvtBroadcast(&es1);
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtBroadcast(&es2);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page rt_test_010_001 [10.1] Threads creation from Memory Heap
|
||||
* @page rt_test_010_001 [10.1] Events registration
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Two threads are started by allocating the memory from the Memory
|
||||
* Heap then a third thread is started with a huge stack
|
||||
* requirement.<br> The test expects the first two threads to
|
||||
* successfully start and the third one to fail.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_HEAP
|
||||
* .
|
||||
* Two event listeners are registered on an event source and then
|
||||
* unregistered in the same order.<br> The test expects that the even
|
||||
* source has listeners after the registrations and after the first
|
||||
* unregistration, then, after the second unegistration, the test
|
||||
* expects no more listeners.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [10.1.1] Getting base priority for threads.
|
||||
* - [10.1.2] Getting heap info before the test.
|
||||
* - [10.1.3] Creating thread 1, it is expected to succeed.
|
||||
* - [10.1.4] Creating thread 2, it is expected to succeed.
|
||||
* - [10.1.5] Creating thread 3, it is expected to fail.
|
||||
* - [10.1.6] Letting threads execute then checking the start order and
|
||||
* freeing memory.
|
||||
* - [10.1.7] Getting heap info again for verification.
|
||||
* - [10.1.1] An Event Source is initialized.
|
||||
* - [10.1.2] Two Event Listeners are registered on the Event Source,
|
||||
* the Event Source is tested to have listeners.
|
||||
* - [10.1.3] An Event Listener is unregistered, the Event Source must
|
||||
* still have listeners.
|
||||
* - [10.1.4] An Event Listener is unregistered, the Event Source must
|
||||
* not have listeners.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void rt_test_010_001_setup(void) {
|
||||
chHeapObjectInit(&heap1, test_buffer, sizeof test_buffer);
|
||||
}
|
||||
|
||||
static void rt_test_010_001_execute(void) {
|
||||
size_t n1, total1, largest1;
|
||||
size_t n2, total2, largest2;
|
||||
tprio_t prio;
|
||||
event_listener_t el1, el2;
|
||||
|
||||
/* [10.1.1] Getting base priority for threads.*/
|
||||
/* [10.1.1] An Event Source is initialized.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
prio = chThdGetPriorityX();
|
||||
chEvtObjectInit(&es1);
|
||||
}
|
||||
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);
|
||||
{
|
||||
n1 = chHeapStatus(&heap1, &total1, &largest1);
|
||||
test_assert(n1 == 1, "heap fragmented");
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es1, &el2, 2);
|
||||
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
|
||||
}
|
||||
test_end_step(2);
|
||||
|
||||
/* [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);
|
||||
{
|
||||
threads[0] = chThdCreateFromHeap(&heap1,
|
||||
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
|
||||
"dyn1",
|
||||
prio-1, dyn_thread1, "A");
|
||||
test_assert(threads[0] != NULL, "thread creation failed");
|
||||
chEvtUnregister(&es1, &el1);
|
||||
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
|
||||
}
|
||||
test_end_step(3);
|
||||
|
||||
/* [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);
|
||||
{
|
||||
threads[1] = chThdCreateFromHeap(&heap1,
|
||||
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
|
||||
"dyn2",
|
||||
prio-2, dyn_thread1, "B");
|
||||
test_assert(threads[1] != NULL, "thread creation failed");
|
||||
chEvtUnregister(&es1, &el2);
|
||||
test_assert_lock(!chEvtIsListeningI(&es1), "stuck listener");
|
||||
}
|
||||
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 = {
|
||||
"Threads creation from Memory Heap",
|
||||
rt_test_010_001_setup,
|
||||
"Events registration",
|
||||
NULL,
|
||||
NULL,
|
||||
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>
|
||||
* Five thread creation are attempted from a pool containing only four
|
||||
* elements.<br> The test expects the first four threads to
|
||||
* successfully start and the last one to fail.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_MEMPOOLS
|
||||
* .
|
||||
* The test dispatches three event flags and verifies that the
|
||||
* associated event handlers are invoked in LSb-first order.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [10.2.1] Adding four working areas to the pool.
|
||||
* - [10.2.2] Getting base priority for threads.
|
||||
* - [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.
|
||||
* - [10.2.1] Three evenf flag bits are raised then chEvtDispatch() is
|
||||
* invoked, the sequence of handlers calls is tested.
|
||||
* .
|
||||
*/
|
||||
|
||||
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) {
|
||||
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);
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
chPoolFree(&mp1, wa[i]);
|
||||
chEvtDispatch(evhndl, 7);
|
||||
test_assert_sequence("ABC", "invalid sequence");
|
||||
}
|
||||
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 = {
|
||||
"Threads creation from Memory Pool",
|
||||
"Event Flags dispatching",
|
||||
rt_test_010_002_setup,
|
||||
NULL,
|
||||
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.
|
||||
|
@ -284,21 +581,24 @@ static const testcase_t rt_test_010_002 = {
|
|||
* @brief Array of test cases.
|
||||
*/
|
||||
const testcase_t * const rt_test_sequence_010_array[] = {
|
||||
#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
&rt_test_010_001,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
||||
&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
|
||||
&rt_test_010_007,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Dynamic threads.
|
||||
* @brief Event Sources and Event Flags.
|
||||
*/
|
||||
const testsequence_t rt_test_sequence_010 = {
|
||||
"Dynamic threads",
|
||||
"Event Sources and Event Flags",
|
||||
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