Improved test suite for Nil.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@12652 110e8d01-0319-4d1e-a829-52ad28d1bb01
This commit is contained in:
Giovanni Di Sirio 2019-02-10 12:16:27 +00:00
parent f901c9d9d6
commit a3f7f78983
14 changed files with 1471 additions and 220 deletions

View File

@ -47,7 +47,7 @@
* @note This values also defines the number of available priorities
* (0..CH_CFG_MAX_THREADS-1).
*/
#define CH_CFG_MAX_THREADS 4
#define CH_CFG_MAX_THREADS 5
/**
* @brief Auto starts threads when @p chSysInit() is invoked.

View File

@ -110,7 +110,6 @@ THD_FUNCTION(Thread3, arg) {
THD_TABLE_BEGIN
THD_TABLE_THREAD(0, "blinker1", waThread1, Thread1, NULL)
THD_TABLE_THREAD(1, "blinker2", waThread2, Thread2, NULL)
THD_TABLE_THREAD(2, "test_support", wa_test_support, test_support, (void *)&nil.threads[3])
THD_TABLE_THREAD(3, "tester", waThread3, Thread3, NULL)
THD_TABLE_END

View File

@ -582,7 +582,7 @@ struct nil_system {
*/
#define THD_TABLE_THREAD(prio, name, wap, funcp, arg) \
{prio, name, \
wap, ((stkalign_t *)(wap)) + (sizeof (wap) / sizeof(stkalign_t)), \
wap, THD_WORKING_AREA_END(wap), \
funcp, arg},
/**
@ -665,6 +665,18 @@ struct nil_system {
#define THD_WORKING_AREA(s, n) PORT_WORKING_AREA(s, n)
/** @} */
/**
* @brief Returns the top address of a working area.
* @note The parameter is assumed to be an array of @p stkalign_t. The
* macros is invalid for anything else.
*
* @param[in] wa working area array
*
* @api
*/
#define THD_WORKING_AREA_END(wa) \
((wa) + ((sizeof wa) / sizeof (stkalign_t)))
/**
* @name Threads abstraction macros
*/

View File

@ -214,6 +214,70 @@ typedef void (*evhandler_t)(eventid_t id);
* @api
*/
#define chEvtGetEventsX(void) (nil.current->epmask)
/**
* @brief Waits for exactly one of the specified events.
* @details The function waits for one event among those specified in
* @p events to become pending then the event is cleared and returned.
* @note One and only one event is served in the function, the one with the
* lowest event id. The function is meant to be invoked into a loop
* in order to serve all the pending events.<br>
* This means that Event Listeners with a lower event identifier have
* an higher priority.
*
* @param[in] events events that the function should wait
* for, @p ALL_EVENTS enables all the events
* @param[in] timeout the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
* .
* @return The mask of the lowest event id served and cleared.
* @retval 0 if the operation has timed out.
*
* @api
*/
#define chEvtWaitOne(events) chEvtWaitOneTimeout(events, TIME_INFINITE)
/**
* @brief Waits for any of the specified events.
* @details The function waits for any event among those specified in
* @p mask to become pending then the events are cleared and
* returned.
*
* @param[in] mask mask of the event flags that the function should wait
* for, @p ALL_EVENTS enables all the events
* @param[in] timeout the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
* .
* @return The mask of the served and cleared events.
* @retval 0 if the operation has timed out.
*
* @api
*/
#define chEvtWaitAny(events) chEvtWaitAnyTimeout(events, TIME_INFINITE)
/**
* @brief Waits for all the specified events.
* @details The function waits for all the events specified in @p mask to
* become pending then the events are cleared and returned.
*
* @param[in] mask mask of the event flags that the function should wait
* for, @p ALL_EVENTS enables all the events
* @param[in] timeout the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
* .
* @return The mask of the served and cleared events.
* @retval 0 if the operation has timed out.
*
* @api
*/
#define chEvtWaitAll(events) chEvtWaitAllTimeout(events, TIME_INFINITE)
/** @} */
/*===========================================================================*/

View File

@ -749,7 +749,13 @@ msg_t chSchGoSleepTimeoutS(tstate_t newstate, sysinterval_t timeout) {
thread_t *chThdCreateI(const thread_config_t *tcp) {
thread_t *tp;
chDbgCheck(tcp->prio < CH_CFG_MAX_THREADS);
chDbgCheck((tcp->prio < CH_CFG_MAX_THREADS) &&
(tcp->wbase != NULL) &&
MEM_IS_ALIGNED(tcp->wbase, PORT_WORKING_AREA_ALIGN) &&
(tcp->wend > tcp->wbase) &&
MEM_IS_ALIGNED(tcp->wbase, PORT_STACK_ALIGN) &&
(tcp->funcp != NULL));
chDbgCheckClassI();
/* Pointer to the thread slot to be used.*/
@ -757,7 +763,10 @@ thread_t *chThdCreateI(const thread_config_t *tcp) {
chDbgAssert(NIL_THD_IS_WTSTART(tp) || NIL_THD_IS_FINAL(tp),
"priority slot taken");
#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__)
#if CH_CFG_USE_EVENTS == TRUE
tp->epmask = (eventmask_t)0;
#endif
#if CH_DBG_ENABLE_STACK_CHECK == TRUE
tp->wabase = (stkalign_t *)tcp->wbase;
#endif

View File

@ -340,6 +340,7 @@ void chEvtDispatch(const evhandler_t *handlers, eventmask_t events) {
eid++;
}
}
/**
* @brief Waits for exactly one of the specified events.
* @details The function waits for one event among those specified in

View File

@ -39,47 +39,22 @@
</code_prefix>
<global_definitions>
<value><![CDATA[#define TEST_SUITE_NAME "ChibiOS/NIL Test Suite"
extern semaphore_t gsem1, gsem2;
extern thread_reference_t gtr1;
extern THD_WORKING_AREA(wa_test_support, 128);
void test_print_port_info(void);
THD_FUNCTION(test_support, arg);]]></value>
/*
* Allowed delay in timeout checks.
*/
#define ALLOWED_DELAY TIME_MS2I(2)
systime_t test_wait_tick(void);]]></value>
</global_definitions>
<global_code>
<value><![CDATA[semaphore_t gsem1, gsem2;
thread_reference_t gtr1;
/*
* Support thread.
*/
THD_WORKING_AREA(wa_test_support, 128);
THD_FUNCTION(test_support, arg) {
#if CH_CFG_USE_EVENTS == TRUE
thread_t *tp = (thread_t *)arg;
#else
(void)arg;
#endif
/* Initializing global resources.*/
chSemObjectInit(&gsem1, 0);
chSemObjectInit(&gsem2, 0);
while (true) {
chSysLock();
if (chSemGetCounterI(&gsem1) < 0)
chSemSignalI(&gsem1);
chSemResetI(&gsem2, 0);
chThdResumeI(&gtr1, MSG_OK);
#if CH_CFG_USE_EVENTS == TRUE
chEvtSignalI(tp, 0x55);
#endif
chSchRescheduleS();
chSysUnlock();
chThdSleepMilliseconds(250);
}
<value><![CDATA[/*
* Delays execution until next system time tick.
*/
systime_t test_wait_tick(void) {
chThdSleep(1);
return chVTGetSystemTimeX();
}]]></value>
</global_code>
</global_data_and_code>
@ -466,8 +441,35 @@ test_assert_time_window(chTimeAddX(time, 100),
</condition>
<shared_code>
<value><![CDATA[#include "ch.h"
static semaphore_t sem1;]]></value>
static thread_t *tp1;
static bool terminate;
static semaphore_t sem1, sem2;
/*
* Signaler thread.
*/
static THD_WORKING_AREA(wa_signaler, 128);
static THD_FUNCTION(signaler, arg) {
(void)arg;
/* Initializing global resources.*/
terminate = false;
chSemObjectInit(&sem1, 0);
chSemObjectInit(&sem2, 0);
while (!terminate) {
chSysLock();
if (chSemGetCounterI(&sem1) < 0)
chSemSignalI(&sem1);
chSemResetI(&sem2, 0);
chSchRescheduleS();
chSysUnlock();
chThdSleepMilliseconds(250);
}
}]]></value>
</shared_code>
<cases>
<case>
@ -545,10 +547,19 @@ test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value");]]></value
</condition>
<various_code>
<setup_code>
<value><![CDATA[chSemObjectInit(&gsem1, 0);]]></value>
<value><![CDATA[thread_config_t tc = {
chThdGetPriorityX() - 1,
"signaler",
wa_signaler,
THD_WORKING_AREA_END(wa_signaler),
signaler,
NULL
};
tp1 = chThdCreate(&tc);]]></value>
</setup_code>
<teardown_code>
<value><![CDATA[chSemReset(&gsem1, 0);]]></value>
<value><![CDATA[terminate = true;
chThdWait(tp1);]]></value>
</teardown_code>
<local_variables>
<value />
@ -563,10 +574,10 @@ test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value");]]></value
<value />
</tags>
<code>
<value><![CDATA[msg_t msg;
msg = chSemWait(&gsem1);
test_assert_lock(chSemGetCounterI(&gsem1) == 0, "wrong counter value");
<value><![CDATA[msg_t msg;
msg = chSemWait(&sem1);
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
test_assert(MSG_OK == msg, "wrong returned message");]]></value>
</code>
</step>
@ -580,8 +591,8 @@ test_assert(MSG_OK == msg, "wrong returned message");]]></value>
<code>
<value><![CDATA[msg_t msg;
msg = chSemWait(&gsem2);
test_assert_lock(chSemGetCounterI(&gsem2) == 0,"wrong counter value");
msg = chSemWait(&sem2);
test_assert_lock(chSemGetCounterI(&sem2) == 0,"wrong counter value");
test_assert(MSG_RESET == msg, "wrong returned message");]]></value>
</code>
</step>
@ -653,16 +664,36 @@ test_assert(MSG_TIMEOUT == msg, "wrong timeout message");]]></value>
<value>Internal Tests</value>
</type>
<brief>
<value>Suspend/Resume and Event Flags.</value>
<value>Suspend/Resume.</value>
</brief>
<description>
<value>This sequence tests the ChibiOS/NIL functionalities related to threads suspend/resume and event flags.</value>
<value>This sequence tests the ChibiOS/NIL functionalities related to threads suspend/resume.</value>
</description>
<condition>
<value />
</condition>
<shared_code>
<value><![CDATA[static thread_reference_t tr1;]]></value>
<value><![CDATA[static thread_t *tp1;
static bool terminate;
static thread_reference_t tr1;
/*
* Resumer thread.
*/
static THD_WORKING_AREA(wa_resumer, 128);
static THD_FUNCTION(resumer, arg) {
(void)arg;
/* Initializing global resources.*/
terminate = false;
tr1 = NULL;
while (!terminate) {
chThdResume(&tr1, MSG_OK);
chThdSleepMilliseconds(250);
}
}]]></value>
</shared_code>
<cases>
<case>
@ -677,10 +708,19 @@ test_assert(MSG_TIMEOUT == msg, "wrong timeout message");]]></value>
</condition>
<various_code>
<setup_code>
<value><![CDATA[tr1 = NULL;]]></value>
<value><![CDATA[thread_config_t tc = {
chThdGetPriorityX() - 1,
"resumer",
wa_resumer,
THD_WORKING_AREA_END(wa_resumer),
resumer,
NULL
};
tp1 = chThdCreate(&tc);]]></value>
</setup_code>
<teardown_code>
<value />
<value><![CDATA[terminate = true;
chThdWait(tp1);]]></value>
</teardown_code>
<local_variables>
<value><![CDATA[systime_t time;
@ -697,9 +737,9 @@ msg_t msg;]]></value>
</tags>
<code>
<value><![CDATA[chSysLock();
msg = chThdSuspendTimeoutS(&gtr1, TIME_INFINITE);
msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE);
chSysUnlock();
test_assert(NULL == gtr1, "not NULL");
test_assert(NULL == tr1, "not NULL");
test_assert(MSG_OK == msg,"wrong returned message");]]></value>
</code>
</step>
@ -711,28 +751,78 @@ test_assert(MSG_OK == msg,"wrong returned message");]]></value>
<value />
</tags>
<code>
<value><![CDATA[chSysLock();
<value><![CDATA[thread_reference_t tr = NULL;
chSysLock();
time = chVTGetSystemTimeX();
msg = chThdSuspendTimeoutS(&tr1, TIME_MS2I(1000));
msg = chThdSuspendTimeoutS(&tr, TIME_MS2I(1000));
chSysUnlock();
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
chTimeAddX(time, TIME_MS2I(1000) + 1),
"out of time window");
test_assert(NULL == tr1, "not NULL");
test_assert(NULL == tr, "not NULL");
test_assert(MSG_TIMEOUT == msg, "wrong returned message");]]></value>
</code>
</step>
</steps>
</case>
</cases>
</sequence>
<sequence>
<type index="0">
<value>Internal Tests</value>
</type>
<brief>
<value>Event Sources and Event Flags.</value>
</brief>
<description>
<value>This module implements the test sequence for the Events subsystem.</value>
</description>
<condition>
<value>CH_CFG_USE_EVENTS</value>
</condition>
<shared_code>
<value><![CDATA[static EVENTSOURCE_DECL(es1);
static EVENTSOURCE_DECL(es2);
static void h1(eventid_t id) {(void)id;test_emit_token('A');}
static void h2(eventid_t id) {(void)id;test_emit_token('B');}
static void h3(eventid_t id) {(void)id;test_emit_token('C');}
static ROMCONST evhandler_t evhndl[] = {h1, h2, h3};
/*
* Direct events thread.
*/
static THD_WORKING_AREA(wa_evtthd1, 128);
static THD_FUNCTION(evtthd1, p) {
chThdSleepMilliseconds(50);
chEvtSignal((thread_t *)p, 1);
}
/*
* Broadcaster thread.
*/
static THD_WORKING_AREA(wa_evtthd2, 128);
static THD_FUNCTION(evtthd2, p) {
(void)p;
chEvtBroadcast(&es1);
chThdSleepMilliseconds(50);
chEvtBroadcast(&es2);
}]]></value>
</shared_code>
<cases>
<case>
<brief>
<value>Events Flags functionality.</value>
<value>Events registration.</value>
</brief>
<description>
<value>Event flags functionality is tested.</value>
<value>Two event listeners are registered on an event source and then unregistered in the same order.&lt;br&gt;&#xD;
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.</value>
</description>
<condition>
<value>CH_CFG_USE_EVENTS</value>
<value />
</condition>
<various_code>
<setup_code>
@ -742,55 +832,522 @@ test_assert(MSG_TIMEOUT == msg, "wrong returned message");]]></value>
<value />
</teardown_code>
<local_variables>
<value><![CDATA[systime_t time;
eventmask_t events;]]></value>
<value><![CDATA[event_listener_t el1, el2;]]></value>
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>A set of event flags are set on the current thread then the function chEvtWaitAnyTimeout() is invoked, the function is supposed to return immediately because the event flags are already pending, after return the events mask is tested.</value>
<value>An Event Source is initialized.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[time = chVTGetSystemTimeX();
chEvtSignal(chThdGetSelfX(), 0x55);
events = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_MS2I(1000));
test_assert((eventmask_t)0 != events, "timed out");
test_assert((eventmask_t)0x55 == events, "wrong events mask");]]></value>
<value><![CDATA[chEvtObjectInit(&es1);]]></value>
</code>
</step>
<step>
<description>
<value>The pending event flags mask is cleared then the function chEvtWaitAnyTimeout() is invoked, after return the events mask is tested. The thread is signaled by another thread.</value>
<value>Two Event Listeners are registered on the Event Source, the Event Source is tested to have listeners.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[time = chVTGetSystemTimeX();
chThdGetSelfX()->epmask = 0;
events = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_MS2I(1000));
test_assert((eventmask_t)0 != events, "timed out");
test_assert((eventmask_t)0x55 == events, "wrong events mask");]]></value>
<value><![CDATA[chEvtRegisterMask(&es1, &el1, 1);
chEvtRegisterMask(&es1, &el2, 2);
test_assert_lock(chEvtIsListeningI(&es1), "no listener");]]></value>
</code>
</step>
<step>
<description>
<value>The function chEvtWaitAnyTimeout() is invoked, no event can wakeup the thread, the function must return because timeout.</value>
<value>An Event Listener is unregistered, the Event Source must still have listeners.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[time = chVTGetSystemTimeX();
events = chEvtWaitAnyTimeout(0, TIME_MS2I(1000));
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
chTimeAddX(time, TIME_MS2I(1000) + 1),
"out of time window");
test_assert((eventmask_t)0 == events, "wrong events mask");]]></value>
<value><![CDATA[chEvtUnregister(&es1, &el1);
test_assert_lock(chEvtIsListeningI(&es1), "no listener");]]></value>
</code>
</step>
<step>
<description>
<value>An Event Listener is unregistered, the Event Source must not have listeners.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[chEvtUnregister(&es1, &el2);
test_assert_lock(!chEvtIsListeningI(&es1), "stuck listener");]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Event Flags dispatching.</value>
</brief>
<description>
<value>The test dispatches three event flags and verifies that the associated event handlers are invoked in LSb-first order.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value><![CDATA[chEvtGetAndClearEvents(ALL_EVENTS);]]></value>
</setup_code>
<teardown_code>
<value />
</teardown_code>
<local_variables>
<value />
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>Three evenf flag bits are raised then chEvtDispatch() is invoked, the sequence of handlers calls is tested.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[chEvtDispatch(evhndl, 7);
test_assert_sequence("ABC", "invalid sequence");]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Events Flags wait using chEvtWaitOne().</value>
</brief>
<description>
<value>Functionality of chEvtWaitOne() is tested under various scenarios.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value><![CDATA[chEvtGetAndClearEvents(ALL_EVENTS);]]></value>
</setup_code>
<teardown_code>
<value />
</teardown_code>
<local_variables>
<value><![CDATA[eventmask_t m;
systime_t target_time;
thread_t *tp;]]></value>
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>Setting three event flags.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[chEvtAddEvents(7);]]></value>
</code>
</step>
<step>
<description>
<value>Calling chEvtWaitOne() three times, each time a single flag must be returned in order of priority.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[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");]]></value>
</code>
</step>
<step>
<description>
<value>Getting current time and starting a signaler thread, the thread will set an event flag after 50mS.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[target_time = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
thread_config_t tc = {
chThdGetPriorityX() + 1,
"event1",
wa_evtthd1,
THD_WORKING_AREA_END(wa_evtthd1),
evtthd1,
chThdGetSelfX()
};
tp = chThdCreate(&tc);]]></value>
</code>
</step>
<step>
<description>
<value>Calling chEvtWaitOne() then verifying that the event has been received after 50mS and that the event flags mask has been emptied.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[m = chEvtWaitOne(ALL_EVENTS);
test_assert_time_window(target_time,
chTimeAddX(target_time, ALLOWED_DELAY),
"out of time window");
test_assert(m == 1, "event flag error");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(m == 0, "stuck event");
chThdWait(tp);]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Events Flags wait using chEvtWaitAny().</value>
</brief>
<description>
<value>Functionality of chEvtWaitAny() is tested under various scenarios.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value><![CDATA[chEvtGetAndClearEvents(ALL_EVENTS);]]></value>
</setup_code>
<teardown_code>
<value />
</teardown_code>
<local_variables>
<value><![CDATA[eventmask_t m;
systime_t target_time;
thread_t *tp;]]></value>
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>Setting two, non contiguous, event flags.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[chEvtAddEvents(5);]]></value>
</code>
</step>
<step>
<description>
<value>Calling chEvtWaitAny() one time, the two flags must be returned.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[m = chEvtWaitAny(ALL_EVENTS);
test_assert(m == 5, "unexpected pending bit");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(m == 0, "stuck event");]]></value>
</code>
</step>
<step>
<description>
<value>Getting current time and starting a signaler thread, the thread will set an event flag after 50mS.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[target_time = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
thread_config_t tc = {
chThdGetPriorityX() + 1,
"event1",
wa_evtthd1,
THD_WORKING_AREA_END(wa_evtthd1),
evtthd1,
chThdGetSelfX()
};
tp = chThdCreate(&tc);]]></value>
</code>
</step>
<step>
<description>
<value>Calling chEvtWaitAny() then verifying that the event has been received after 50mS and that the event flags mask has been emptied.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[m = chEvtWaitAny(ALL_EVENTS);
test_assert_time_window(target_time,
chTimeAddX(target_time, ALLOWED_DELAY),
"out of time window");
test_assert(m == 1, "event flag error");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(m == 0, "stuck event");
chThdWait(tp);]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Events Flags wait using chEvtWaitAll().</value>
</brief>
<description>
<value>Functionality of chEvtWaitAll() is tested under various scenarios.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value><![CDATA[chEvtGetAndClearEvents(ALL_EVENTS);]]></value>
</setup_code>
<teardown_code>
<value />
</teardown_code>
<local_variables>
<value><![CDATA[eventmask_t m;
systime_t target_time;
thread_t *tp;]]></value>
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>Setting two, non contiguous, event flags.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[chEvtAddEvents(5);]]></value>
</code>
</step>
<step>
<description>
<value>Calling chEvtWaitAll() one time, the two flags must be returned.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[m = chEvtWaitAll(5);
test_assert(m == 5, "unexpected pending bit");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(m == 0, "stuck event");]]></value>
</code>
</step>
<step>
<description>
<value>Setting one event flag.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[chEvtAddEvents(4);]]></value>
</code>
</step>
<step>
<description>
<value>Getting current time and starting a signaler thread, the thread will set another event flag after 50mS.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[target_time = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
thread_config_t tc = {
chThdGetPriorityX() + 1,
"event1",
wa_evtthd1,
THD_WORKING_AREA_END(wa_evtthd1),
evtthd1,
chThdGetSelfX()
};
tp = chThdCreate(&tc);]]></value>
</code>
</step>
<step>
<description>
<value>Calling chEvtWaitAll() then verifying that both event flags have been received after 50mS and that the event flags mask has been emptied.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[m = chEvtWaitAll(5);
test_assert_time_window(target_time,
chTimeAddX(target_time, ALLOWED_DELAY),
"out of time window");
test_assert(m == 5, "event flags error");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(m == 0, "stuck event");
chThdWait(tp);]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Events Flags wait timeouts.</value>
</brief>
<description>
<value>Timeout functionality is tested for chEvtWaitOneTimeout(), chEvtWaitAnyTimeout() and chEvtWaitAllTimeout().</value>
</description>
<condition>
<value></value>
</condition>
<various_code>
<setup_code>
<value><![CDATA[chEvtGetAndClearEvents(ALL_EVENTS);]]></value>
</setup_code>
<teardown_code>
<value />
</teardown_code>F
<local_variables>
<value><![CDATA[eventmask_t m;]]></value>
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>The functions are invoked first with TIME_IMMEDIATE timeout, the timeout condition is tested.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[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");]]></value>
</code>
</step>
<step>
<description>
<value>The functions are invoked first with a 50mS timeout, the timeout condition is tested.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[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");]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Broadcasting using chEvtBroadcast().</value>
</brief>
<description>
<value>Functionality of chEvtBroadcast() is tested.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value><![CDATA[chEvtGetAndClearEvents(ALL_EVENTS);
chEvtObjectInit(&es1);
chEvtObjectInit(&es2);]]></value>
</setup_code>
<teardown_code>
<value />
</teardown_code>
<local_variables>
<value><![CDATA[eventmask_t m;
event_listener_t el1, el2;
systime_t target_time;
thread_t *tp;]]></value>
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>Registering on two event sources associating them with flags 1 and 4.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[chEvtRegisterMask(&es1, &el1, 1);
chEvtRegisterMask(&es2, &el2, 4);]]></value>
</code>
</step>
<step>
<description>
<value>Getting current time and starting a broadcaster thread, the thread broadcast the first Event Source immediately and the other after 50mS.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[target_time = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
thread_config_t tc = {
chThdGetPriorityX() + 1,
"event2",
wa_evtthd2,
THD_WORKING_AREA_END(wa_evtthd2),
evtthd2,
NULL
};
tp = chThdCreate(&tc);]]></value>
</code>
</step>
<step>
<description>
<value>Calling chEvtWaitAll() then verifying that both event flags have been received after 50mS and that the event flags mask has been emptied.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[m = chEvtWaitAll(5);
test_assert_time_window(target_time,
chTimeAddX(target_time, ALLOWED_DELAY),
"out of time window");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(m == 0, "stuck event");
chThdWait(tp);]]></value>
</code>
</step>
<step>
<description>
<value>Unregistering from the Event Sources.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[chEvtUnregister(&es1, &el1);
chEvtUnregister(&es2, &el2);
test_assert(!chEvtIsListeningI(&es1), "stuck listener");
test_assert(!chEvtIsListeningI(&es2), "stuck listener");]]></value>
</code>
</step>
</steps>

View File

@ -3,7 +3,8 @@ TESTSRC += ${CHIBIOS}/test/nil/source/test/nil_test_root.c \
${CHIBIOS}/test/nil/source/test/nil_test_sequence_001.c \
${CHIBIOS}/test/nil/source/test/nil_test_sequence_002.c \
${CHIBIOS}/test/nil/source/test/nil_test_sequence_003.c \
${CHIBIOS}/test/nil/source/test/nil_test_sequence_004.c
${CHIBIOS}/test/nil/source/test/nil_test_sequence_004.c \
${CHIBIOS}/test/nil/source/test/nil_test_sequence_005.c
# Required include directories
TESTINC += ${CHIBIOS}/test/nil/source/test

View File

@ -25,6 +25,7 @@
* - @subpage nil_test_sequence_002
* - @subpage nil_test_sequence_003
* - @subpage nil_test_sequence_004
* - @subpage nil_test_sequence_005
* .
*/
@ -52,6 +53,9 @@ const testsequence_t * const nil_test_suite_array[] = {
&nil_test_sequence_003,
#endif
&nil_test_sequence_004,
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
&nil_test_sequence_005,
#endif
NULL
};
@ -67,38 +71,13 @@ const testsuite_t nil_test_suite = {
/* Shared code. */
/*===========================================================================*/
semaphore_t gsem1, gsem2;
thread_reference_t gtr1;
/*
* Support thread.
* Delays execution until next system time tick.
*/
THD_WORKING_AREA(wa_test_support, 128);
THD_FUNCTION(test_support, arg) {
#if CH_CFG_USE_EVENTS == TRUE
thread_t *tp = (thread_t *)arg;
#else
(void)arg;
#endif
systime_t test_wait_tick(void) {
/* Initializing global resources.*/
chSemObjectInit(&gsem1, 0);
chSemObjectInit(&gsem2, 0);
while (true) {
chSysLock();
if (chSemGetCounterI(&gsem1) < 0)
chSemSignalI(&gsem1);
chSemResetI(&gsem2, 0);
chThdResumeI(&gtr1, MSG_OK);
#if CH_CFG_USE_EVENTS == TRUE
chEvtSignalI(tp, 0x55);
#endif
chSchRescheduleS();
chSysUnlock();
chThdSleepMilliseconds(250);
}
chThdSleep(1);
return chVTGetSystemTimeX();
}
#endif /* !defined(__DOXYGEN__) */

View File

@ -28,6 +28,7 @@
#include "nil_test_sequence_002.h"
#include "nil_test_sequence_003.h"
#include "nil_test_sequence_004.h"
#include "nil_test_sequence_005.h"
#if !defined(__DOXYGEN__)
@ -50,12 +51,12 @@ extern "C" {
#define TEST_SUITE_NAME "ChibiOS/NIL Test Suite"
extern semaphore_t gsem1, gsem2;
extern thread_reference_t gtr1;
extern THD_WORKING_AREA(wa_test_support, 128);
/*
* Allowed delay in timeout checks.
*/
#define ALLOWED_DELAY TIME_MS2I(2)
void test_print_port_info(void);
THD_FUNCTION(test_support, arg);
systime_t test_wait_tick(void);
#endif /* !defined(__DOXYGEN__) */

View File

@ -50,7 +50,34 @@
#include "ch.h"
static semaphore_t sem1;
static thread_t *tp1;
static bool terminate;
static semaphore_t sem1, sem2;
/*
* Signaler thread.
*/
static THD_WORKING_AREA(wa_signaler, 128);
static THD_FUNCTION(signaler, arg) {
(void)arg;
/* Initializing global resources.*/
terminate = false;
chSemObjectInit(&sem1, 0);
chSemObjectInit(&sem2, 0);
while (!terminate) {
chSysLock();
if (chSemGetCounterI(&sem1) < 0)
chSemSignalI(&sem1);
chSemResetI(&sem2, 0);
chSchRescheduleS();
chSysUnlock();
chThdSleepMilliseconds(250);
}
}
/****************************************************************************
* Test cases.
@ -136,11 +163,20 @@ static const testcase_t nil_test_003_001 = {
*/
static void nil_test_003_002_setup(void) {
chSemObjectInit(&gsem1, 0);
thread_config_t tc = {
chThdGetPriorityX() - 1,
"signaler",
wa_signaler,
THD_WORKING_AREA_END(wa_signaler),
signaler,
NULL
};
tp1 = chThdCreate(&tc);
}
static void nil_test_003_002_teardown(void) {
chSemReset(&gsem1, 0);
terminate = true;
chThdWait(tp1);
}
static void nil_test_003_002_execute(void) {
@ -152,8 +188,8 @@ static void nil_test_003_002_execute(void) {
{
msg_t msg;
msg = chSemWait(&gsem1);
test_assert_lock(chSemGetCounterI(&gsem1) == 0, "wrong counter value");
msg = chSemWait(&sem1);
test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value");
test_assert(MSG_OK == msg, "wrong returned message");
}
@ -164,8 +200,8 @@ static void nil_test_003_002_execute(void) {
{
msg_t msg;
msg = chSemWait(&gsem2);
test_assert_lock(chSemGetCounterI(&gsem2) == 0,"wrong counter value");
msg = chSemWait(&sem2);
test_assert_lock(chSemGetCounterI(&sem2) == 0,"wrong counter value");
test_assert(MSG_RESET == msg, "wrong returned message");
}
}

View File

@ -21,17 +21,16 @@
* @file nil_test_sequence_004.c
* @brief Test Sequence 004 code.
*
* @page nil_test_sequence_004 [4] Suspend/Resume and Event Flags
* @page nil_test_sequence_004 [4] Suspend/Resume
*
* File: @ref nil_test_sequence_004.c
*
* <h2>Description</h2>
* This sequence tests the ChibiOS/NIL functionalities related to
* threads suspend/resume and event flags.
* threads suspend/resume.
*
* <h2>Test Cases</h2>
* - @subpage nil_test_004_001
* - @subpage nil_test_004_002
* .
*/
@ -39,8 +38,28 @@
* Shared code.
****************************************************************************/
static thread_t *tp1;
static bool terminate;
static thread_reference_t tr1;
/*
* Resumer thread.
*/
static THD_WORKING_AREA(wa_resumer, 128);
static THD_FUNCTION(resumer, arg) {
(void)arg;
/* Initializing global resources.*/
terminate = false;
tr1 = NULL;
while (!terminate) {
chThdResume(&tr1, MSG_OK);
chThdSleepMilliseconds(250);
}
}
/****************************************************************************
* Test cases.
****************************************************************************/
@ -63,7 +82,20 @@ static thread_reference_t tr1;
*/
static void nil_test_004_001_setup(void) {
tr1 = NULL;
thread_config_t tc = {
chThdGetPriorityX() - 1,
"resumer",
wa_resumer,
THD_WORKING_AREA_END(wa_resumer),
resumer,
NULL
};
tp1 = chThdCreate(&tc);
}
static void nil_test_004_001_teardown(void) {
terminate = true;
chThdWait(tp1);
}
static void nil_test_004_001_execute(void) {
@ -76,9 +108,9 @@ static void nil_test_004_001_execute(void) {
test_set_step(1);
{
chSysLock();
msg = chThdSuspendTimeoutS(&gtr1, TIME_INFINITE);
msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE);
chSysUnlock();
test_assert(NULL == gtr1, "not NULL");
test_assert(NULL == tr1, "not NULL");
test_assert(MSG_OK == msg,"wrong returned message");
}
@ -87,14 +119,16 @@ static void nil_test_004_001_execute(void) {
the state of the reference are tested.*/
test_set_step(2);
{
thread_reference_t tr = NULL;
chSysLock();
time = chVTGetSystemTimeX();
msg = chThdSuspendTimeoutS(&tr1, TIME_MS2I(1000));
msg = chThdSuspendTimeoutS(&tr, TIME_MS2I(1000));
chSysUnlock();
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
chTimeAddX(time, TIME_MS2I(1000) + 1),
"out of time window");
test_assert(NULL == tr1, "not NULL");
test_assert(NULL == tr, "not NULL");
test_assert(MSG_TIMEOUT == msg, "wrong returned message");
}
}
@ -102,86 +136,10 @@ static void nil_test_004_001_execute(void) {
static const testcase_t nil_test_004_001 = {
"Suspend and Resume functionality",
nil_test_004_001_setup,
NULL,
nil_test_004_001_teardown,
nil_test_004_001_execute
};
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
/**
* @page nil_test_004_002 [4.2] Events Flags functionality
*
* <h2>Description</h2>
* Event flags functionality is tested.
*
* <h2>Conditions</h2>
* This test is only executed if the following preprocessor condition
* evaluates to true:
* - CH_CFG_USE_EVENTS
* .
*
* <h2>Test Steps</h2>
* - [4.2.1] A set of event flags are set on the current thread then
* the function chEvtWaitAnyTimeout() is invoked, the function is
* supposed to return immediately because the event flags are already
* pending, after return the events mask is tested.
* - [4.2.2] The pending event flags mask is cleared then the function
* chEvtWaitAnyTimeout() is invoked, after return the events mask is
* tested. The thread is signaled by another thread.
* - [4.2.3] The function chEvtWaitAnyTimeout() is invoked, no event
* can wakeup the thread, the function must return because timeout.
* .
*/
static void nil_test_004_002_execute(void) {
systime_t time;
eventmask_t events;
/* [4.2.1] A set of event flags are set on the current thread then
the function chEvtWaitAnyTimeout() is invoked, the function is
supposed to return immediately because the event flags are already
pending, after return the events mask is tested.*/
test_set_step(1);
{
time = chVTGetSystemTimeX();
chEvtSignal(chThdGetSelfX(), 0x55);
events = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_MS2I(1000));
test_assert((eventmask_t)0 != events, "timed out");
test_assert((eventmask_t)0x55 == events, "wrong events mask");
}
/* [4.2.2] The pending event flags mask is cleared then the function
chEvtWaitAnyTimeout() is invoked, after return the events mask is
tested. The thread is signaled by another thread.*/
test_set_step(2);
{
time = chVTGetSystemTimeX();
chThdGetSelfX()->epmask = 0;
events = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_MS2I(1000));
test_assert((eventmask_t)0 != events, "timed out");
test_assert((eventmask_t)0x55 == events, "wrong events mask");
}
/* [4.2.3] The function chEvtWaitAnyTimeout() is invoked, no event
can wakeup the thread, the function must return because timeout.*/
test_set_step(3);
{
time = chVTGetSystemTimeX();
events = chEvtWaitAnyTimeout(0, TIME_MS2I(1000));
test_assert_time_window(chTimeAddX(time, TIME_MS2I(1000)),
chTimeAddX(time, TIME_MS2I(1000) + 1),
"out of time window");
test_assert((eventmask_t)0 == events, "wrong events mask");
}
}
static const testcase_t nil_test_004_002 = {
"Events Flags functionality",
NULL,
NULL,
nil_test_004_002_execute
};
#endif /* CH_CFG_USE_EVENTS */
/****************************************************************************
* Exported data.
****************************************************************************/
@ -191,16 +149,13 @@ static const testcase_t nil_test_004_002 = {
*/
const testcase_t * const nil_test_sequence_004_array[] = {
&nil_test_004_001,
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
&nil_test_004_002,
#endif
NULL
};
/**
* @brief Suspend/Resume and Event Flags.
* @brief Suspend/Resume.
*/
const testsequence_t nil_test_sequence_004 = {
"Suspend/Resume and Event Flags",
"Suspend/Resume",
nil_test_sequence_004_array
};

View File

@ -0,0 +1,610 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "hal.h"
#include "nil_test_root.h"
/**
* @file nil_test_sequence_005.c
* @brief Test Sequence 005 code.
*
* @page nil_test_sequence_005 [5] Event Sources and Event Flags
*
* File: @ref nil_test_sequence_005.c
*
* <h2>Description</h2>
* This module implements the test sequence for the Events subsystem.
*
* <h2>Conditions</h2>
* This sequence is only executed if the following preprocessor condition
* evaluates to true:
* - CH_CFG_USE_EVENTS
* .
*
* <h2>Test Cases</h2>
* - @subpage nil_test_005_001
* - @subpage nil_test_005_002
* - @subpage nil_test_005_003
* - @subpage nil_test_005_004
* - @subpage nil_test_005_005
* - @subpage nil_test_005_006
* - @subpage nil_test_005_007
* .
*/
#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
/****************************************************************************
* Shared code.
****************************************************************************/
static EVENTSOURCE_DECL(es1);
static EVENTSOURCE_DECL(es2);
static void h1(eventid_t id) {(void)id;test_emit_token('A');}
static void h2(eventid_t id) {(void)id;test_emit_token('B');}
static void h3(eventid_t id) {(void)id;test_emit_token('C');}
static ROMCONST evhandler_t evhndl[] = {h1, h2, h3};
/*
* Direct events thread.
*/
static THD_WORKING_AREA(wa_evtthd1, 128);
static THD_FUNCTION(evtthd1, p) {
chThdSleepMilliseconds(50);
chEvtSignal((thread_t *)p, 1);
}
/*
* Broadcaster thread.
*/
static THD_WORKING_AREA(wa_evtthd2, 128);
static THD_FUNCTION(evtthd2, p) {
(void)p;
chEvtBroadcast(&es1);
chThdSleepMilliseconds(50);
chEvtBroadcast(&es2);
}
/****************************************************************************
* Test cases.
****************************************************************************/
/**
* @page nil_test_005_001 [5.1] Events registration
*
* <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.
*
* <h2>Test Steps</h2>
* - [5.1.1] An Event Source is initialized.
* - [5.1.2] Two Event Listeners are registered on the Event Source,
* the Event Source is tested to have listeners.
* - [5.1.3] An Event Listener is unregistered, the Event Source must
* still have listeners.
* - [5.1.4] An Event Listener is unregistered, the Event Source must
* not have listeners.
* .
*/
static void nil_test_005_001_execute(void) {
event_listener_t el1, el2;
/* [5.1.1] An Event Source is initialized.*/
test_set_step(1);
{
chEvtObjectInit(&es1);
}
/* [5.1.2] Two Event Listeners are registered on the Event Source,
the Event Source is tested to have listeners.*/
test_set_step(2);
{
chEvtRegisterMask(&es1, &el1, 1);
chEvtRegisterMask(&es1, &el2, 2);
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
}
/* [5.1.3] An Event Listener is unregistered, the Event Source must
still have listeners.*/
test_set_step(3);
{
chEvtUnregister(&es1, &el1);
test_assert_lock(chEvtIsListeningI(&es1), "no listener");
}
/* [5.1.4] An Event Listener is unregistered, the Event Source must
not have listeners.*/
test_set_step(4);
{
chEvtUnregister(&es1, &el2);
test_assert_lock(!chEvtIsListeningI(&es1), "stuck listener");
}
}
static const testcase_t nil_test_005_001 = {
"Events registration",
NULL,
NULL,
nil_test_005_001_execute
};
/**
* @page nil_test_005_002 [5.2] Event Flags dispatching
*
* <h2>Description</h2>
* The test dispatches three event flags and verifies that the
* associated event handlers are invoked in LSb-first order.
*
* <h2>Test Steps</h2>
* - [5.2.1] Three evenf flag bits are raised then chEvtDispatch() is
* invoked, the sequence of handlers calls is tested.
* .
*/
static void nil_test_005_002_setup(void) {
chEvtGetAndClearEvents(ALL_EVENTS);
}
static void nil_test_005_002_execute(void) {
/* [5.2.1] Three evenf flag bits are raised then chEvtDispatch() is
invoked, the sequence of handlers calls is tested.*/
test_set_step(1);
{
chEvtDispatch(evhndl, 7);
test_assert_sequence("ABC", "invalid sequence");
}
}
static const testcase_t nil_test_005_002 = {
"Event Flags dispatching",
nil_test_005_002_setup,
NULL,
nil_test_005_002_execute
};
/**
* @page nil_test_005_003 [5.3] Events Flags wait using chEvtWaitOne()
*
* <h2>Description</h2>
* Functionality of chEvtWaitOne() is tested under various scenarios.
*
* <h2>Test Steps</h2>
* - [5.3.1] Setting three event flags.
* - [5.3.2] Calling chEvtWaitOne() three times, each time a single
* flag must be returned in order of priority.
* - [5.3.3] Getting current time and starting a signaler thread, the
* thread will set an event flag after 50mS.
* - [5.3.4] Calling chEvtWaitOne() then verifying that the event has
* been received after 50mS and that the event flags mask has been
* emptied.
* .
*/
static void nil_test_005_003_setup(void) {
chEvtGetAndClearEvents(ALL_EVENTS);
}
static void nil_test_005_003_execute(void) {
eventmask_t m;
systime_t target_time;
thread_t *tp;
/* [5.3.1] Setting three event flags.*/
test_set_step(1);
{
chEvtAddEvents(7);
}
/* [5.3.2] Calling chEvtWaitOne() three times, each time a single
flag must be returned in order of priority.*/
test_set_step(2);
{
m = chEvtWaitOne(ALL_EVENTS);
test_assert(m == 1, "single event error");
m = chEvtWaitOne(ALL_EVENTS);
test_assert(m == 2, "single event error");
m = chEvtWaitOne(ALL_EVENTS);
test_assert(m == 4, "single event error");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(m == 0, "stuck event");
}
/* [5.3.3] Getting current time and starting a signaler thread, the
thread will set an event flag after 50mS.*/
test_set_step(3);
{
target_time = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
thread_config_t tc = {
chThdGetPriorityX() + 1,
"event1",
wa_evtthd1,
THD_WORKING_AREA_END(wa_evtthd1),
evtthd1,
chThdGetSelfX()
};
tp = chThdCreate(&tc);
}
/* [5.3.4] Calling chEvtWaitOne() then verifying that the event has
been received after 50mS and that the event flags mask has been
emptied.*/
test_set_step(4);
{
m = chEvtWaitOne(ALL_EVENTS);
test_assert_time_window(target_time,
chTimeAddX(target_time, ALLOWED_DELAY),
"out of time window");
test_assert(m == 1, "event flag error");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(m == 0, "stuck event");
chThdWait(tp);
}
}
static const testcase_t nil_test_005_003 = {
"Events Flags wait using chEvtWaitOne()",
nil_test_005_003_setup,
NULL,
nil_test_005_003_execute
};
/**
* @page nil_test_005_004 [5.4] Events Flags wait using chEvtWaitAny()
*
* <h2>Description</h2>
* Functionality of chEvtWaitAny() is tested under various scenarios.
*
* <h2>Test Steps</h2>
* - [5.4.1] Setting two, non contiguous, event flags.
* - [5.4.2] Calling chEvtWaitAny() one time, the two flags must be
* returned.
* - [5.4.3] Getting current time and starting a signaler thread, the
* thread will set an event flag after 50mS.
* - [5.4.4] Calling chEvtWaitAny() then verifying that the event has
* been received after 50mS and that the event flags mask has been
* emptied.
* .
*/
static void nil_test_005_004_setup(void) {
chEvtGetAndClearEvents(ALL_EVENTS);
}
static void nil_test_005_004_execute(void) {
eventmask_t m;
systime_t target_time;
thread_t *tp;
/* [5.4.1] Setting two, non contiguous, event flags.*/
test_set_step(1);
{
chEvtAddEvents(5);
}
/* [5.4.2] Calling chEvtWaitAny() one time, the two flags must be
returned.*/
test_set_step(2);
{
m = chEvtWaitAny(ALL_EVENTS);
test_assert(m == 5, "unexpected pending bit");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(m == 0, "stuck event");
}
/* [5.4.3] Getting current time and starting a signaler thread, the
thread will set an event flag after 50mS.*/
test_set_step(3);
{
target_time = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
thread_config_t tc = {
chThdGetPriorityX() + 1,
"event1",
wa_evtthd1,
THD_WORKING_AREA_END(wa_evtthd1),
evtthd1,
chThdGetSelfX()
};
tp = chThdCreate(&tc);
}
/* [5.4.4] Calling chEvtWaitAny() then verifying that the event has
been received after 50mS and that the event flags mask has been
emptied.*/
test_set_step(4);
{
m = chEvtWaitAny(ALL_EVENTS);
test_assert_time_window(target_time,
chTimeAddX(target_time, ALLOWED_DELAY),
"out of time window");
test_assert(m == 1, "event flag error");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(m == 0, "stuck event");
chThdWait(tp);
}
}
static const testcase_t nil_test_005_004 = {
"Events Flags wait using chEvtWaitAny()",
nil_test_005_004_setup,
NULL,
nil_test_005_004_execute
};
/**
* @page nil_test_005_005 [5.5] Events Flags wait using chEvtWaitAll()
*
* <h2>Description</h2>
* Functionality of chEvtWaitAll() is tested under various scenarios.
*
* <h2>Test Steps</h2>
* - [5.5.1] Setting two, non contiguous, event flags.
* - [5.5.2] Calling chEvtWaitAll() one time, the two flags must be
* returned.
* - [5.5.3] Setting one event flag.
* - [5.5.4] Getting current time and starting a signaler thread, the
* thread will set another event flag after 50mS.
* - [5.5.5] Calling chEvtWaitAll() then verifying that both event
* flags have been received after 50mS and that the event flags mask
* has been emptied.
* .
*/
static void nil_test_005_005_setup(void) {
chEvtGetAndClearEvents(ALL_EVENTS);
}
static void nil_test_005_005_execute(void) {
eventmask_t m;
systime_t target_time;
thread_t *tp;
/* [5.5.1] Setting two, non contiguous, event flags.*/
test_set_step(1);
{
chEvtAddEvents(5);
}
/* [5.5.2] Calling chEvtWaitAll() one time, the two flags must be
returned.*/
test_set_step(2);
{
m = chEvtWaitAll(5);
test_assert(m == 5, "unexpected pending bit");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(m == 0, "stuck event");
}
/* [5.5.3] Setting one event flag.*/
test_set_step(3);
{
chEvtAddEvents(4);
}
/* [5.5.4] Getting current time and starting a signaler thread, the
thread will set another event flag after 50mS.*/
test_set_step(4);
{
target_time = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
thread_config_t tc = {
chThdGetPriorityX() + 1,
"event1",
wa_evtthd1,
THD_WORKING_AREA_END(wa_evtthd1),
evtthd1,
chThdGetSelfX()
};
tp = chThdCreate(&tc);
}
/* [5.5.5] Calling chEvtWaitAll() then verifying that both event
flags have been received after 50mS and that the event flags mask
has been emptied.*/
test_set_step(5);
{
m = chEvtWaitAll(5);
test_assert_time_window(target_time,
chTimeAddX(target_time, ALLOWED_DELAY),
"out of time window");
test_assert(m == 5, "event flags error");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(m == 0, "stuck event");
chThdWait(tp);
}
}
static const testcase_t nil_test_005_005 = {
"Events Flags wait using chEvtWaitAll()",
nil_test_005_005_setup,
NULL,
nil_test_005_005_execute
};
/**
* @page nil_test_005_006 [5.6] Events Flags wait timeouts
*
* <h2>Description</h2>
* Timeout functionality is tested for chEvtWaitOneTimeout(),
* chEvtWaitAnyTimeout() and chEvtWaitAllTimeout().
*
* <h2>Test Steps</h2>
* - [5.6.1] The functions are invoked first with TIME_IMMEDIATE
* timeout, the timeout condition is tested.
* - [5.6.2] The functions are invoked first with a 50mS timeout, the
* timeout condition is tested.
* .
*/
static void nil_test_005_006_setup(void) {
chEvtGetAndClearEvents(ALL_EVENTS);
}
static void nil_test_005_006_execute(void) {
eventmask_t m;
/* [5.6.1] The functions are invoked first with TIME_IMMEDIATE
timeout, the timeout condition is tested.*/
test_set_step(1);
{
m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_IMMEDIATE);
test_assert(m == 0, "spurious event");
m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_IMMEDIATE);
test_assert(m == 0, "spurious event");
m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_IMMEDIATE);
test_assert(m == 0, "spurious event");
}
/* [5.6.2] The functions are invoked first with a 50mS timeout, the
timeout condition is tested.*/
test_set_step(2);
{
m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_MS2I(50));
test_assert(m == 0, "spurious event");
m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_MS2I(50));
test_assert(m == 0, "spurious event");
m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_MS2I(50));
test_assert(m == 0, "spurious event");
}
}
static const testcase_t nil_test_005_006 = {
"Events Flags wait timeouts",
nil_test_005_006_setup,
NULL,
nil_test_005_006_execute
};
/**
* @page nil_test_005_007 [5.7] Broadcasting using chEvtBroadcast()
*
* <h2>Description</h2>
* Functionality of chEvtBroadcast() is tested.
*
* <h2>Test Steps</h2>
* - [5.7.1] Registering on two event sources associating them with
* flags 1 and 4.
* - [5.7.2] Getting current time and starting a broadcaster thread,
* the thread broadcast the first Event Source immediately and the
* other after 50mS.
* - [5.7.3] Calling chEvtWaitAll() then verifying that both event
* flags have been received after 50mS and that the event flags mask
* has been emptied.
* - [5.7.4] Unregistering from the Event Sources.
* .
*/
static void nil_test_005_007_setup(void) {
chEvtGetAndClearEvents(ALL_EVENTS);
chEvtObjectInit(&es1);
chEvtObjectInit(&es2);
}
static void nil_test_005_007_execute(void) {
eventmask_t m;
event_listener_t el1, el2;
systime_t target_time;
thread_t *tp;
/* [5.7.1] Registering on two event sources associating them with
flags 1 and 4.*/
test_set_step(1);
{
chEvtRegisterMask(&es1, &el1, 1);
chEvtRegisterMask(&es2, &el2, 4);
}
/* [5.7.2] Getting current time and starting a broadcaster thread,
the thread broadcast the first Event Source immediately and the
other after 50mS.*/
test_set_step(2);
{
target_time = chTimeAddX(test_wait_tick(), TIME_MS2I(50));
thread_config_t tc = {
chThdGetPriorityX() + 1,
"event2",
wa_evtthd2,
THD_WORKING_AREA_END(wa_evtthd2),
evtthd2,
NULL
};
tp = chThdCreate(&tc);
}
/* [5.7.3] Calling chEvtWaitAll() then verifying that both event
flags have been received after 50mS and that the event flags mask
has been emptied.*/
test_set_step(3);
{
m = chEvtWaitAll(5);
test_assert_time_window(target_time,
chTimeAddX(target_time, ALLOWED_DELAY),
"out of time window");
m = chEvtGetAndClearEvents(ALL_EVENTS);
test_assert(m == 0, "stuck event");
chThdWait(tp);
}
/* [5.7.4] Unregistering from the Event Sources.*/
test_set_step(4);
{
chEvtUnregister(&es1, &el1);
chEvtUnregister(&es2, &el2);
test_assert(!chEvtIsListeningI(&es1), "stuck listener");
test_assert(!chEvtIsListeningI(&es2), "stuck listener");
}
}
static const testcase_t nil_test_005_007 = {
"Broadcasting using chEvtBroadcast()",
nil_test_005_007_setup,
NULL,
nil_test_005_007_execute
};
/****************************************************************************
* Exported data.
****************************************************************************/
/**
* @brief Array of test cases.
*/
const testcase_t * const nil_test_sequence_005_array[] = {
&nil_test_005_001,
&nil_test_005_002,
&nil_test_005_003,
&nil_test_005_004,
&nil_test_005_005,
&nil_test_005_006,
&nil_test_005_007,
NULL
};
/**
* @brief Event Sources and Event Flags.
*/
const testsequence_t nil_test_sequence_005 = {
"Event Sources and Event Flags",
nil_test_sequence_005_array
};
#endif /* CH_CFG_USE_EVENTS */

View File

@ -0,0 +1,27 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file nil_test_sequence_005.h
* @brief Test Sequence 005 header.
*/
#ifndef NIL_TEST_SEQUENCE_005_H
#define NIL_TEST_SEQUENCE_005_H
extern const testsequence_t nil_test_sequence_005;
#endif /* NIL_TEST_SEQUENCE_005_H */