git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9194 35acf78f-673a-0410-8e92-d51de3d6d3f4
parent
b472786cd2
commit
7b1bf2a147
|
@ -106,7 +106,7 @@ void * ROMCONST wa[5] = {test.wa.T0, test.wa.T1, test.wa.T2,
|
|||
* Sets a termination request in all the test-spawned threads.
|
||||
*/
|
||||
void test_terminate_threads(void) {
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_THREADS; i++)
|
||||
if (threads[i])
|
||||
|
@ -117,7 +117,7 @@ void test_terminate_threads(void) {
|
|||
* Waits for the completion of all the test-spawned threads.
|
||||
*/
|
||||
void test_wait_threads(void) {
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_THREADS; i++)
|
||||
if (threads[i] != NULL) {
|
||||
|
@ -126,6 +126,9 @@ void test_wait_threads(void) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Delays execution until next system time tick.
|
||||
*/
|
||||
systime_t test_wait_tick(void) {
|
||||
|
||||
chThdSleep(1);
|
||||
|
@ -4058,8 +4061,8 @@ test_assert(chPoolAlloc(&mp1) == NULL, "pool list not empty");]]></value>
|
|||
</cases>
|
||||
</sequence>
|
||||
<sequence>
|
||||
<type index="0">
|
||||
<value>Internal Tests</value>
|
||||
<type index="2">
|
||||
<value>Benchmarks</value>
|
||||
</type>
|
||||
<brief>
|
||||
<value>Benchmarks.</value>
|
||||
|
@ -4079,6 +4082,8 @@ static semaphore_t sem1;
|
|||
static mutex_t mtx1;
|
||||
#endif
|
||||
|
||||
static void tmo(void *param) {(void)param;}
|
||||
|
||||
#if CH_CFG_USE_MESSAGES
|
||||
static THD_FUNCTION(bmk_thread1, p) {
|
||||
thread_t *tp;
|
||||
|
@ -4126,6 +4131,27 @@ static THD_FUNCTION(bmk_thread4, p) {
|
|||
msg = self->u.rdymsg;
|
||||
} while (msg == MSG_OK);
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
static THD_FUNCTION(bmk_thread7, p) {
|
||||
|
||||
(void)p;
|
||||
while (!chThdShouldTerminateX())
|
||||
chSemWait(&sem1);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(bmk_thread8, p) {
|
||||
|
||||
do {
|
||||
chThdYield();
|
||||
chThdYield();
|
||||
chThdYield();
|
||||
chThdYield();
|
||||
(*(uint32_t *)p) += 4;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while(!chThdShouldTerminateX());
|
||||
}]]></value>
|
||||
</shared_code>
|
||||
<cases>
|
||||
|
@ -4540,6 +4566,517 @@ test_println(" threads/S");]]></value>
|
|||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
<case>
|
||||
<brief>
|
||||
<value>Mass reschedule performance.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>Five threads are created and atomically rescheduled by resetting the semaphore where they are waiting on. The operation is performed into a continuous loop.<br>
|
||||
The performance is calculated by measuring the number of iterations after a second of continuous operations.</value>
|
||||
</description>
|
||||
<condition>
|
||||
<value>CH_CFG_USE_SEMAPHORES</value>
|
||||
</condition>
|
||||
<various_code>
|
||||
<setup_code>
|
||||
<value><![CDATA[chSemObjectInit(&sem1, 0);]]></value>
|
||||
</setup_code>
|
||||
<teardown_code>
|
||||
<value />
|
||||
</teardown_code>
|
||||
<local_variables>
|
||||
<value><![CDATA[uint32_t n;]]></value>
|
||||
</local_variables>
|
||||
</various_code>
|
||||
<steps>
|
||||
<step>
|
||||
<description>
|
||||
<value>Five threads are created at higher priority that immediately enqueue on a semaphore.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, bmk_thread7, NULL);
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+4, bmk_thread7, NULL);
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, bmk_thread7, NULL);
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+2, bmk_thread7, NULL);
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+1, bmk_thread7, NULL);]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The semaphore is reset waking up the five threads. The operation is repeated continuously in a one-second time window.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[systime_t start, end;
|
||||
|
||||
n = 0;
|
||||
start = test_wait_tick();
|
||||
end = start + MS2ST(1000);
|
||||
do {
|
||||
chSemReset(&sem1, 0);
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (chVTIsSystemTimeWithinX(start, end));]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The five threads are terminated.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[test_terminate_threads();
|
||||
chSemReset(&sem1, 0);
|
||||
test_wait_threads();]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The score is printed.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_print(" reschedules/S, ");
|
||||
test_printn(n * 6);
|
||||
test_println(" ctxswc/S");]]></value>
|
||||
</code>
|
||||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
<case>
|
||||
<brief>
|
||||
<value>Round-Robin voluntary reschedule.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>Five threads are created at equal priority, each thread just increases a variable and yields.<br>
|
||||
The performance is calculated by measuring the number of iterations after a second of continuous operations.</value>
|
||||
</description>
|
||||
<condition>
|
||||
<value />
|
||||
</condition>
|
||||
<various_code>
|
||||
<setup_code>
|
||||
<value />
|
||||
</setup_code>
|
||||
<teardown_code>
|
||||
<value />
|
||||
</teardown_code>
|
||||
<local_variables>
|
||||
<value><![CDATA[uint32_t n;]]></value>
|
||||
</local_variables>
|
||||
</various_code>
|
||||
<steps>
|
||||
<step>
|
||||
<description>
|
||||
<value>The five threads are created at lower priority. The threds have equal priority and start calling @p chThdYield() continuously.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[n = 0;
|
||||
test_wait_tick();threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
|
||||
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>Waiting one second then terminating the 5 threads.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[chThdSleepSeconds(1);
|
||||
test_terminate_threads();
|
||||
test_wait_threads();]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The score is printed.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_println(" ctxswc/S");]]></value>
|
||||
</code>
|
||||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
<case>
|
||||
<brief>
|
||||
<value>Virtual Timers set/reset performance.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>A virtual timer is set and immediately reset into a continuous loop.<br>
|
||||
The performance is calculated by measuring the number of iterations after a second of continuous operations.</value>
|
||||
</description>
|
||||
<condition>
|
||||
<value />
|
||||
</condition>
|
||||
<various_code>
|
||||
<setup_code>
|
||||
<value />
|
||||
</setup_code>
|
||||
<teardown_code>
|
||||
<value />
|
||||
</teardown_code>
|
||||
<local_variables>
|
||||
<value><![CDATA[static virtual_timer_t vt1, vt2;
|
||||
uint32_t n;]]></value>
|
||||
</local_variables>
|
||||
</various_code>
|
||||
<steps>
|
||||
<step>
|
||||
<description>
|
||||
<value>Two timers are set then reset without waiting for their counter to elapse. The operation is repeated continuously in a one-second time window.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[systime_t start, end;
|
||||
|
||||
n = 0;
|
||||
start = test_wait_tick();
|
||||
end = start + MS2ST(1000);
|
||||
do {
|
||||
chSysLock();
|
||||
chVTDoSetI(&vt1, 1, tmo, NULL);
|
||||
chVTDoSetI(&vt2, 10000, tmo, NULL);
|
||||
chVTDoResetI(&vt1);
|
||||
chVTDoResetI(&vt2);
|
||||
chSysUnlock();
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (chVTIsSystemTimeWithinX(start, end));]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The score is printed.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[test_print("--- Score : ");
|
||||
test_printn(n * 2);
|
||||
test_println(" timers/S");]]></value>
|
||||
</code>
|
||||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
<case>
|
||||
<brief>
|
||||
<value>Semaphores wait/signal performance</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>A counting semaphore is taken/released into a continuous loop, no Context Switch happens because the counter is always non negative.<br>
|
||||
The performance is calculated by measuring the number of iterations after a second of continuous operations.</value>
|
||||
</description>
|
||||
<condition>
|
||||
<value>CH_CFG_USE_SEMAPHORES</value>
|
||||
</condition>
|
||||
<various_code>
|
||||
<setup_code>
|
||||
<value><![CDATA[chSemObjectInit(&sem1, 1);]]></value>
|
||||
</setup_code>
|
||||
<teardown_code>
|
||||
<value />
|
||||
</teardown_code>
|
||||
<local_variables>
|
||||
<value><![CDATA[uint32_t n;]]></value>
|
||||
</local_variables>
|
||||
</various_code>
|
||||
<steps>
|
||||
<step>
|
||||
<description>
|
||||
<value>A semaphore is teken and released. The operation is repeated continuously in a one-second time window.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[systime_t start, end;
|
||||
|
||||
n = 0;
|
||||
start = test_wait_tick();
|
||||
end = start + MS2ST(1000);
|
||||
do {
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (chVTIsSystemTimeWithinX(start, end));]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The score is printed.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[test_print("--- Score : ");
|
||||
test_printn(n * 4);
|
||||
test_println(" wait+signal/S");]]></value>
|
||||
</code>
|
||||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
<case>
|
||||
<brief>
|
||||
<value>Mutexes lock/unlock performance</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>A mutex is locked/unlocked into a continuous loop, no Context Switch happens because there are no other threads asking for the mutex.<br>
|
||||
The performance is calculated by measuring the number of iterations after a second of continuous operations.</value>
|
||||
</description>
|
||||
<condition>
|
||||
<value>CH_CFG_USE_MUTEXES</value>
|
||||
</condition>
|
||||
<various_code>
|
||||
<setup_code>
|
||||
<value><![CDATA[chMtxObjectInit(&mtx1);]]></value>
|
||||
</setup_code>
|
||||
<teardown_code>
|
||||
<value />
|
||||
</teardown_code>
|
||||
<local_variables>
|
||||
<value><![CDATA[uint32_t n;]]></value>
|
||||
</local_variables>
|
||||
</various_code>
|
||||
<steps>
|
||||
<step>
|
||||
<description>
|
||||
<value>A mutex is locked and unlocked. The operation is repeated continuously in a one-second time window.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[systime_t start, end;
|
||||
|
||||
n = 0;
|
||||
start = test_wait_tick();
|
||||
end = start + MS2ST(1000);
|
||||
do {
|
||||
chMtxLock(&mtx1);
|
||||
chMtxUnlock(&mtx1);
|
||||
chMtxLock(&mtx1);
|
||||
chMtxUnlock(&mtx1);
|
||||
chMtxLock(&mtx1);
|
||||
chMtxUnlock(&mtx1);
|
||||
chMtxLock(&mtx1);
|
||||
chMtxUnlock(&mtx1);
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (chVTIsSystemTimeWithinX(start, end));]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The score is printed.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[test_print("--- Score : ");
|
||||
test_printn(n * 4);
|
||||
test_println(" lock+unlock/S");]]></value>
|
||||
</code>
|
||||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
<case>
|
||||
<brief>
|
||||
<value>RAM Footprint.</value>
|
||||
</brief>
|
||||
<description>
|
||||
<value>The memory size of the various kernel objects is printed.</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>The size of the system area is printed.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[test_print("--- System: ");
|
||||
test_printn(sizeof(ch_system_t));
|
||||
test_println(" bytes");]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The size of a thread structure is printed.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[test_print("--- Thread: ");
|
||||
test_printn(sizeof(thread_t));
|
||||
test_println(" bytes");]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The size of a virtual timer structure is printed.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[test_print("--- Timer : ");
|
||||
test_printn(sizeof(virtual_timer_t));
|
||||
test_println(" bytes");]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The size of a semaphore structure is printed.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
|
||||
test_print("--- Semaph: ");
|
||||
test_printn(sizeof(semaphore_t));
|
||||
test_println(" bytes");
|
||||
#endif]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The size of a mutex is printed.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
|
||||
test_print("--- Mutex : ");
|
||||
test_printn(sizeof(mutex_t));
|
||||
test_println(" bytes");
|
||||
#endif]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The size of a condition variable is printed.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__)
|
||||
test_print("--- CondV.: ");
|
||||
test_printn(sizeof(condition_variable_t));
|
||||
test_println(" bytes");
|
||||
#endif]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The size of an event source is printed.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
|
||||
test_print("--- EventS: ");
|
||||
test_printn(sizeof(event_source_t));
|
||||
test_println(" bytes");
|
||||
#endif]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The size of an event listener is printed.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
|
||||
test_print("--- EventL: ");
|
||||
test_printn(sizeof(event_listener_t));
|
||||
test_println(" bytes");
|
||||
#endif]]></value>
|
||||
</code>
|
||||
</step>
|
||||
<step>
|
||||
<description>
|
||||
<value>The size of a mailbox is printed.</value>
|
||||
</description>
|
||||
<tags>
|
||||
<value />
|
||||
</tags>
|
||||
<code>
|
||||
<value><![CDATA[#if CH_CFG_USE_MAILBOXES || defined(__DOXYGEN__)
|
||||
test_print("--- MailB.: ");
|
||||
test_printn(sizeof(mailbox_t));
|
||||
test_println(" bytes");
|
||||
#endif]]></value>
|
||||
</code>
|
||||
</step>
|
||||
</steps>
|
||||
</case>
|
||||
</cases>
|
||||
</sequence>
|
||||
</sequences>
|
||||
|
|
|
@ -95,7 +95,7 @@ void * ROMCONST wa[5] = {test.wa.T0, test.wa.T1, test.wa.T2,
|
|||
* Sets a termination request in all the test-spawned threads.
|
||||
*/
|
||||
void test_terminate_threads(void) {
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_THREADS; i++)
|
||||
if (threads[i])
|
||||
|
@ -106,7 +106,7 @@ void test_terminate_threads(void) {
|
|||
* Waits for the completion of all the test-spawned threads.
|
||||
*/
|
||||
void test_wait_threads(void) {
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_THREADS; i++)
|
||||
if (threads[i] != NULL) {
|
||||
|
@ -115,6 +115,9 @@ void test_wait_threads(void) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Delays execution until next system time tick.
|
||||
*/
|
||||
systime_t test_wait_tick(void) {
|
||||
|
||||
chThdSleep(1);
|
||||
|
|
|
@ -38,6 +38,12 @@
|
|||
* - @subpage test_012_004
|
||||
* - @subpage test_012_005
|
||||
* - @subpage test_012_006
|
||||
* - @subpage test_012_007
|
||||
* - @subpage test_012_008
|
||||
* - @subpage test_012_009
|
||||
* - @subpage test_012_010
|
||||
* - @subpage test_012_011
|
||||
* - @subpage test_012_012
|
||||
* .
|
||||
*/
|
||||
|
||||
|
@ -52,6 +58,8 @@ static semaphore_t sem1;
|
|||
static mutex_t mtx1;
|
||||
#endif
|
||||
|
||||
static void tmo(void *param) {(void)param;}
|
||||
|
||||
#if CH_CFG_USE_MESSAGES
|
||||
static THD_FUNCTION(bmk_thread1, p) {
|
||||
thread_t *tp;
|
||||
|
@ -99,6 +107,27 @@ static THD_FUNCTION(bmk_thread4, p) {
|
|||
msg = self->u.rdymsg;
|
||||
} while (msg == MSG_OK);
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
static THD_FUNCTION(bmk_thread7, p) {
|
||||
|
||||
(void)p;
|
||||
while (!chThdShouldTerminateX())
|
||||
chSemWait(&sem1);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(bmk_thread8, p) {
|
||||
|
||||
do {
|
||||
chThdYield();
|
||||
chThdYield();
|
||||
chThdYield();
|
||||
chThdYield();
|
||||
(*(uint32_t *)p) += 4;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while(!chThdShouldTerminateX());
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -492,6 +521,471 @@ static const testcase_t test_012_006 = {
|
|||
test_012_006_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_012_007 [12.7] Mass reschedule performance
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads are created and atomically rescheduled by resetting the
|
||||
* semaphore where they are waiting on. The operation is performed into
|
||||
* a continuous loop.<br> The performance is calculated by measuring
|
||||
* the number of iterations after a second of continuous operations.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [12.7.1] Five threads are created at higher priority that
|
||||
* immediately enqueue on a semaphore.
|
||||
* - [12.7.2] The semaphore is reset waking up the five threads. The
|
||||
* operation is repeated continuously in a one-second time window.
|
||||
* - [12.7.3] The five threads are terminated.
|
||||
* - [12.7.4] The score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_012_007_setup(void) {
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static void test_012_007_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
/* [12.7.1] Five threads are created at higher priority that
|
||||
immediately enqueue on a semaphore.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, bmk_thread7, NULL);
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+4, bmk_thread7, NULL);
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, bmk_thread7, NULL);
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+2, bmk_thread7, NULL);
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+1, bmk_thread7, NULL);
|
||||
}
|
||||
|
||||
/* [12.7.2] The semaphore is reset waking up the five threads. The
|
||||
operation is repeated continuously in a one-second time window.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
systime_t start, end;
|
||||
|
||||
n = 0;
|
||||
start = test_wait_tick();
|
||||
end = start + MS2ST(1000);
|
||||
do {
|
||||
chSemReset(&sem1, 0);
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (chVTIsSystemTimeWithinX(start, end));
|
||||
}
|
||||
|
||||
/* [12.7.3] The five threads are terminated.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
test_terminate_threads();
|
||||
chSemReset(&sem1, 0);
|
||||
test_wait_threads();
|
||||
}
|
||||
|
||||
/* [12.7.4] The score is printed.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_print(" reschedules/S, ");
|
||||
test_printn(n * 6);
|
||||
test_println(" ctxswc/S");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_012_007 = {
|
||||
"Mass reschedule performance",
|
||||
test_012_007_setup,
|
||||
NULL,
|
||||
test_012_007_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
||||
/**
|
||||
* @page test_012_008 [12.8] Round-Robin voluntary reschedule
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads are created at equal priority, each thread just
|
||||
* increases a variable and yields.<br> The performance is calculated
|
||||
* by measuring the number of iterations after a second of continuous
|
||||
* operations.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [12.8.1] The five threads are created at lower priority. The
|
||||
* threds have equal priority and start calling @p chThdYield()
|
||||
* continuously.
|
||||
* - [12.8.2] Waiting one second then terminating the 5 threads.
|
||||
* - [12.8.3] The score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_012_008_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
/* [12.8.1] The five threads are created at lower priority. The
|
||||
threds have equal priority and start calling @p chThdYield()
|
||||
continuously.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
n = 0;
|
||||
test_wait_tick();threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
|
||||
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, bmk_thread8, (void *)&n);
|
||||
}
|
||||
|
||||
/* [12.8.2] Waiting one second then terminating the 5 threads.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
chThdSleepSeconds(1);
|
||||
test_terminate_threads();
|
||||
test_wait_threads();
|
||||
}
|
||||
|
||||
/* [12.8.3] The score is printed.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_println(" ctxswc/S");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_012_008 = {
|
||||
"Round-Robin voluntary reschedule",
|
||||
NULL,
|
||||
NULL,
|
||||
test_012_008_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_012_009 [12.9] Virtual Timers set/reset performance
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A virtual timer is set and immediately reset into a continuous
|
||||
* loop.<br> The performance is calculated by measuring the number of
|
||||
* iterations after a second of continuous operations.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [12.9.1] Two timers are set then reset without waiting for their
|
||||
* counter to elapse. The operation is repeated continuously in a
|
||||
* one-second time window.
|
||||
* - [12.9.2] The score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_012_009_execute(void) {
|
||||
static virtual_timer_t vt1, vt2;
|
||||
uint32_t n;
|
||||
|
||||
/* [12.9.1] Two timers are set then reset without waiting for their
|
||||
counter to elapse. The operation is repeated continuously in a
|
||||
one-second time window.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
systime_t start, end;
|
||||
|
||||
n = 0;
|
||||
start = test_wait_tick();
|
||||
end = start + MS2ST(1000);
|
||||
do {
|
||||
chSysLock();
|
||||
chVTDoSetI(&vt1, 1, tmo, NULL);
|
||||
chVTDoSetI(&vt2, 10000, tmo, NULL);
|
||||
chVTDoResetI(&vt1);
|
||||
chVTDoResetI(&vt2);
|
||||
chSysUnlock();
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (chVTIsSystemTimeWithinX(start, end));
|
||||
}
|
||||
|
||||
/* [12.9.2] The score is printed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
test_print("--- Score : ");
|
||||
test_printn(n * 2);
|
||||
test_println(" timers/S");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_012_009 = {
|
||||
"Virtual Timers set/reset performance",
|
||||
NULL,
|
||||
NULL,
|
||||
test_012_009_execute
|
||||
};
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_012_010 [12.10] Semaphores wait/signal performance
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A counting semaphore is taken/released into a continuous loop, no
|
||||
* Context Switch happens because the counter is always non
|
||||
* negative.<br> The performance is calculated by measuring the number
|
||||
* of iterations after a second of continuous operations.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [12.10.1] A semaphore is teken and released. The operation is
|
||||
* repeated continuously in a one-second time window.
|
||||
* - [12.10.2] The score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_012_010_setup(void) {
|
||||
chSemObjectInit(&sem1, 1);
|
||||
}
|
||||
|
||||
static void test_012_010_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
/* [12.10.1] A semaphore is teken and released. The operation is
|
||||
repeated continuously in a one-second time window.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
systime_t start, end;
|
||||
|
||||
n = 0;
|
||||
start = test_wait_tick();
|
||||
end = start + MS2ST(1000);
|
||||
do {
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (chVTIsSystemTimeWithinX(start, end));
|
||||
}
|
||||
|
||||
/* [12.10.2] The score is printed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
test_print("--- Score : ");
|
||||
test_printn(n * 4);
|
||||
test_println(" wait+signal/S");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_012_010 = {
|
||||
"Semaphores wait/signal performance",
|
||||
test_012_010_setup,
|
||||
NULL,
|
||||
test_012_010_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_012_011 [12.11] Mutexes lock/unlock performance
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A mutex is locked/unlocked into a continuous loop, no Context Switch
|
||||
* happens because there are no other threads asking for the mutex.<br>
|
||||
* The performance is calculated by measuring the number of iterations
|
||||
* after a second of continuous operations.
|
||||
*
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - CH_CFG_USE_MUTEXES
|
||||
* .
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [12.11.1] A mutex is locked and unlocked. The operation is
|
||||
* repeated continuously in a one-second time window.
|
||||
* - [12.11.2] The score is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_012_011_setup(void) {
|
||||
chMtxObjectInit(&mtx1);
|
||||
}
|
||||
|
||||
static void test_012_011_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
/* [12.11.1] A mutex is locked and unlocked. The operation is
|
||||
repeated continuously in a one-second time window.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
systime_t start, end;
|
||||
|
||||
n = 0;
|
||||
start = test_wait_tick();
|
||||
end = start + MS2ST(1000);
|
||||
do {
|
||||
chMtxLock(&mtx1);
|
||||
chMtxUnlock(&mtx1);
|
||||
chMtxLock(&mtx1);
|
||||
chMtxUnlock(&mtx1);
|
||||
chMtxLock(&mtx1);
|
||||
chMtxUnlock(&mtx1);
|
||||
chMtxLock(&mtx1);
|
||||
chMtxUnlock(&mtx1);
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (chVTIsSystemTimeWithinX(start, end));
|
||||
}
|
||||
|
||||
/* [12.11.2] The score is printed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
test_print("--- Score : ");
|
||||
test_printn(n * 4);
|
||||
test_println(" lock+unlock/S");
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_012_011 = {
|
||||
"Mutexes lock/unlock performance",
|
||||
test_012_011_setup,
|
||||
NULL,
|
||||
test_012_011_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_MUTEXES */
|
||||
|
||||
/**
|
||||
* @page test_012_012 [12.12] RAM Footprint
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The memory size of the various kernel objects is printed.
|
||||
*
|
||||
* <h2>Test Steps</h2>
|
||||
* - [12.12.1] The size of the system area is printed.
|
||||
* - [12.12.2] The size of a thread structure is printed.
|
||||
* - [12.12.3] The size of a virtual timer structure is printed.
|
||||
* - [12.12.4] The size of a semaphore structure is printed.
|
||||
* - [12.12.5] The size of a mutex is printed.
|
||||
* - [12.12.6] The size of a condition variable is printed.
|
||||
* - [12.12.7] The size of an event source is printed.
|
||||
* - [12.12.8] The size of an event listener is printed.
|
||||
* - [12.12.9] The size of a mailbox is printed.
|
||||
* .
|
||||
*/
|
||||
|
||||
static void test_012_012_execute(void) {
|
||||
|
||||
/* [12.12.1] The size of the system area is printed.*/
|
||||
test_set_step(1);
|
||||
{
|
||||
test_print("--- System: ");
|
||||
test_printn(sizeof(ch_system_t));
|
||||
test_println(" bytes");
|
||||
}
|
||||
|
||||
/* [12.12.2] The size of a thread structure is printed.*/
|
||||
test_set_step(2);
|
||||
{
|
||||
test_print("--- Thread: ");
|
||||
test_printn(sizeof(thread_t));
|
||||
test_println(" bytes");
|
||||
}
|
||||
|
||||
/* [12.12.3] The size of a virtual timer structure is printed.*/
|
||||
test_set_step(3);
|
||||
{
|
||||
test_print("--- Timer : ");
|
||||
test_printn(sizeof(virtual_timer_t));
|
||||
test_println(" bytes");
|
||||
}
|
||||
|
||||
/* [12.12.4] The size of a semaphore structure is printed.*/
|
||||
test_set_step(4);
|
||||
{
|
||||
#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
|
||||
test_print("--- Semaph: ");
|
||||
test_printn(sizeof(semaphore_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* [12.12.5] The size of a mutex is printed.*/
|
||||
test_set_step(5);
|
||||
{
|
||||
#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
|
||||
test_print("--- Mutex : ");
|
||||
test_printn(sizeof(mutex_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* [12.12.6] The size of a condition variable is printed.*/
|
||||
test_set_step(6);
|
||||
{
|
||||
#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__)
|
||||
test_print("--- CondV.: ");
|
||||
test_printn(sizeof(condition_variable_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* [12.12.7] The size of an event source is printed.*/
|
||||
test_set_step(7);
|
||||
{
|
||||
#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
|
||||
test_print("--- EventS: ");
|
||||
test_printn(sizeof(event_source_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* [12.12.8] The size of an event listener is printed.*/
|
||||
test_set_step(8);
|
||||
{
|
||||
#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
|
||||
test_print("--- EventL: ");
|
||||
test_printn(sizeof(event_listener_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* [12.12.9] The size of a mailbox is printed.*/
|
||||
test_set_step(9);
|
||||
{
|
||||
#if CH_CFG_USE_MAILBOXES || defined(__DOXYGEN__)
|
||||
test_print("--- MailB.: ");
|
||||
test_printn(sizeof(mailbox_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static const testcase_t test_012_012 = {
|
||||
"RAM Footprint",
|
||||
NULL,
|
||||
NULL,
|
||||
test_012_012_execute
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
@ -512,5 +1006,17 @@ const testcase_t * const test_sequence_012[] = {
|
|||
&test_012_004,
|
||||
&test_012_005,
|
||||
&test_012_006,
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&test_012_007,
|
||||
#endif
|
||||
&test_012_008,
|
||||
&test_012_009,
|
||||
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
&test_012_010,
|
||||
#endif
|
||||
#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
&test_012_011,
|
||||
#endif
|
||||
&test_012_012,
|
||||
NULL
|
||||
};
|
||||
|
|
388
test/rt/test.c
388
test/rt/test.c
|
@ -1,388 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file test.c
|
||||
* @brief Tests support code.
|
||||
*
|
||||
* @addtogroup test
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#include "test.h"
|
||||
#include "testsys.h"
|
||||
#include "testthd.h"
|
||||
#include "testsem.h"
|
||||
#include "testmtx.h"
|
||||
#include "testmsg.h"
|
||||
#include "testmbox.h"
|
||||
#include "testevt.h"
|
||||
#include "testheap.h"
|
||||
#include "testpools.h"
|
||||
#include "testdyn.h"
|
||||
#include "testbmk.h"
|
||||
|
||||
/*
|
||||
* Array of all the test patterns.
|
||||
*/
|
||||
static ROMCONST struct testcase * ROMCONST *patterns[] = {
|
||||
patternsys,
|
||||
patternthd,
|
||||
patternsem,
|
||||
patternmtx,
|
||||
patternmsg,
|
||||
patternmbox,
|
||||
patternevt,
|
||||
patternheap,
|
||||
patternpools,
|
||||
patterndyn,
|
||||
patternbmk,
|
||||
NULL
|
||||
};
|
||||
|
||||
bool test_global_fail;
|
||||
static bool local_fail;
|
||||
static unsigned failpoint;
|
||||
static char tokens_buffer[MAX_TOKENS];
|
||||
static char *tokp;
|
||||
|
||||
/*
|
||||
* Static working areas, the following areas can be used for threads or
|
||||
* used as temporary buffers.
|
||||
*/
|
||||
union test_buffers test;
|
||||
|
||||
/*
|
||||
* Pointers to the spawned threads.
|
||||
*/
|
||||
thread_t *threads[MAX_THREADS];
|
||||
|
||||
/*
|
||||
* Pointers to the working areas.
|
||||
*/
|
||||
void * ROMCONST wa[5] = {test.wa.T0, test.wa.T1, test.wa.T2,
|
||||
test.wa.T3, test.wa.T4};
|
||||
|
||||
/*
|
||||
* Console output.
|
||||
*/
|
||||
static BaseSequentialStream *chp;
|
||||
|
||||
/**
|
||||
* @brief Prints a decimal unsigned number.
|
||||
*
|
||||
* @param[in] n the number to be printed
|
||||
*/
|
||||
void test_printn(uint32_t n) {
|
||||
char buf[16], *p;
|
||||
|
||||
if (!n)
|
||||
streamPut(chp, '0');
|
||||
else {
|
||||
p = buf;
|
||||
while (n)
|
||||
*p++ = (n % 10) + '0', n /= 10;
|
||||
while (p > buf)
|
||||
streamPut(chp, *--p);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prints a line without final end-of-line.
|
||||
*
|
||||
* @param[in] msgp the message
|
||||
*/
|
||||
void test_print(const char *msgp) {
|
||||
|
||||
while (*msgp)
|
||||
streamPut(chp, *msgp++);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prints a line.
|
||||
*
|
||||
* @param[in] msgp the message
|
||||
*/
|
||||
void test_println(const char *msgp) {
|
||||
|
||||
test_print(msgp);
|
||||
streamWrite(chp, (const uint8_t *)"\r\n", 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tokens.
|
||||
*/
|
||||
static void clear_tokens(void) {
|
||||
|
||||
tokp = tokens_buffer;
|
||||
}
|
||||
|
||||
static void print_tokens(void) {
|
||||
char *cp = tokens_buffer;
|
||||
|
||||
while (cp < tokp)
|
||||
streamPut(chp, *cp++);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Emits a token into the tokens buffer.
|
||||
*
|
||||
* @param[in] token the token as a char
|
||||
*/
|
||||
void test_emit_token(char token) {
|
||||
|
||||
chSysLock();
|
||||
*tokp++ = token;
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Assertions.
|
||||
*/
|
||||
bool _test_fail(unsigned point) {
|
||||
|
||||
test_global_fail = TRUE;
|
||||
local_fail = TRUE;
|
||||
failpoint = point;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool _test_assert(unsigned point, bool condition) {
|
||||
|
||||
if (!condition)
|
||||
return _test_fail(point);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool _test_assert_sequence(unsigned point, char *expected) {
|
||||
char *cp = tokens_buffer;
|
||||
while (cp < tokp) {
|
||||
if (*cp++ != *expected++)
|
||||
return _test_fail(point);
|
||||
}
|
||||
if (*expected)
|
||||
return _test_fail(point);
|
||||
clear_tokens();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool _test_assert_time_window(unsigned point, systime_t start, systime_t end) {
|
||||
|
||||
return _test_assert(point, chVTIsSystemTimeWithin(start, end));
|
||||
}
|
||||
|
||||
/*
|
||||
* Threads utils.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Sets a termination request in all the test-spawned threads.
|
||||
*/
|
||||
void test_terminate_threads(void) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_THREADS; i++)
|
||||
if (threads[i])
|
||||
chThdTerminate(threads[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits for the completion of all the test-spawned threads.
|
||||
*/
|
||||
void test_wait_threads(void) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_THREADS; i++)
|
||||
if (threads[i] != NULL) {
|
||||
chThdWait(threads[i]);
|
||||
threads[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if CH_DBG_THREADS_PROFILING
|
||||
/**
|
||||
* @brief CPU pulse.
|
||||
* @note The current implementation is not totally reliable.
|
||||
*
|
||||
* @param[in] duration CPU pulse duration in milliseconds
|
||||
*/
|
||||
void test_cpu_pulse(unsigned duration) {
|
||||
systime_t start, end, now;
|
||||
|
||||
start = chThdGetTicksX(chThdGetSelfX());
|
||||
end = start + MS2ST(duration);
|
||||
do {
|
||||
now = chThdGetTicksX(chThdGetSelfX());
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
}
|
||||
while (end > start ? (now >= start) && (now < end) :
|
||||
(now >= start) || (now < end));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Delays execution until next system time tick.
|
||||
*
|
||||
* @return The system time.
|
||||
*/
|
||||
systime_t test_wait_tick(void) {
|
||||
|
||||
chThdSleep(1);
|
||||
return chVTGetSystemTime();
|
||||
}
|
||||
|
||||
/*
|
||||
* Timer utils.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set to @p TRUE when the test timer reaches its deadline.
|
||||
*/
|
||||
bool test_timer_done;
|
||||
|
||||
static virtual_timer_t vt;
|
||||
static void tmr(void *p) {
|
||||
(void)p;
|
||||
|
||||
test_timer_done = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the test timer.
|
||||
*
|
||||
* @param[in] ms time in milliseconds
|
||||
*/
|
||||
void test_start_timer(unsigned ms) {
|
||||
|
||||
systime_t duration = MS2ST(ms);
|
||||
test_timer_done = FALSE;
|
||||
chVTSet(&vt, duration, tmr, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test suite execution.
|
||||
*/
|
||||
static void execute_test(const struct testcase *tcp) {
|
||||
int i;
|
||||
|
||||
/* Initialization */
|
||||
clear_tokens();
|
||||
local_fail = FALSE;
|
||||
for (i = 0; i < MAX_THREADS; i++)
|
||||
threads[i] = NULL;
|
||||
|
||||
if (tcp->setup != NULL)
|
||||
tcp->setup();
|
||||
tcp->execute();
|
||||
if (tcp->teardown != NULL)
|
||||
tcp->teardown();
|
||||
|
||||
test_wait_threads();
|
||||
}
|
||||
|
||||
static void print_line(void) {
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < 76; i++)
|
||||
streamPut(chp, '-');
|
||||
streamWrite(chp, (const uint8_t *)"\r\n", 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test execution thread function.
|
||||
*
|
||||
* @param[in] p pointer to a @p BaseChannel object for test output
|
||||
*/
|
||||
void TestThread(void *p) {
|
||||
int i, j;
|
||||
|
||||
chp = p;
|
||||
test_println("");
|
||||
test_println("*** ChibiOS/RT test suite");
|
||||
test_println("***");
|
||||
test_print("*** Kernel: ");
|
||||
test_println(CH_KERNEL_VERSION);
|
||||
test_print("*** Compiled: ");
|
||||
test_println(__DATE__ " - " __TIME__);
|
||||
#ifdef PORT_COMPILER_NAME
|
||||
test_print("*** Compiler: ");
|
||||
test_println(PORT_COMPILER_NAME);
|
||||
#endif
|
||||
test_print("*** Architecture: ");
|
||||
test_println(PORT_ARCHITECTURE_NAME);
|
||||
#ifdef PORT_CORE_VARIANT_NAME
|
||||
test_print("*** Core Variant: ");
|
||||
test_println(PORT_CORE_VARIANT_NAME);
|
||||
#endif
|
||||
#ifdef PORT_INFO
|
||||
test_print("*** Port Info: ");
|
||||
test_println(PORT_INFO);
|
||||
#endif
|
||||
#ifdef PLATFORM_NAME
|
||||
test_print("*** Platform: ");
|
||||
test_println(PLATFORM_NAME);
|
||||
#endif
|
||||
#ifdef BOARD_NAME
|
||||
test_print("*** Test Board: ");
|
||||
test_println(BOARD_NAME);
|
||||
#endif
|
||||
test_println("");
|
||||
|
||||
test_global_fail = FALSE;
|
||||
i = 0;
|
||||
while (patterns[i]) {
|
||||
j = 0;
|
||||
while (patterns[i][j]) {
|
||||
print_line();
|
||||
test_print("--- Test Case ");
|
||||
test_printn(i + 1);
|
||||
test_print(".");
|
||||
test_printn(j + 1);
|
||||
test_print(" (");
|
||||
test_print(patterns[i][j]->name);
|
||||
test_println(")");
|
||||
#if DELAY_BETWEEN_TESTS > 0
|
||||
chThdSleepMilliseconds(DELAY_BETWEEN_TESTS);
|
||||
#endif
|
||||
execute_test(patterns[i][j]);
|
||||
if (local_fail) {
|
||||
test_print("--- Result: FAILURE (#");
|
||||
test_printn(failpoint);
|
||||
test_print(" [");
|
||||
print_tokens();
|
||||
test_println("])");
|
||||
}
|
||||
else
|
||||
test_println("--- Result: SUCCESS");
|
||||
j++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
print_line();
|
||||
test_println("");
|
||||
test_print("Final result: ");
|
||||
if (test_global_fail)
|
||||
test_println("FAILURE");
|
||||
else
|
||||
test_println("SUCCESS");
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup test Test Runtime
|
||||
* @details Runtime code for the test suite execution, this code is not part
|
||||
* of the OS and should not be included in user applications.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page testsuite Testing Strategy
|
||||
* <h2>Description</h2>
|
||||
* Most of the ChibiOS/RT demos link a set of software modules (test suite) in
|
||||
* order to verify the proper working of the kernel, the port and the demo
|
||||
* itself.
|
||||
*
|
||||
* <h2>Kernel Test Suite</h2>
|
||||
* The kernel test suite is divided in modules or test sequences. Each Test
|
||||
* Module performs a series of tests on a specified kernel subsystem or
|
||||
* subsystems and can report a failure/success status and/or a performance
|
||||
* index as the test suite output.<br>
|
||||
* The test suite is usually activated in the demo applications by pressing a
|
||||
* button on the target board, see the readme file into the various demos
|
||||
* directories. The test suite output is usually sent through a serial port
|
||||
* and can be examined by using a terminal emulator program.
|
||||
*
|
||||
* <h2>Kernel Test Modules</h2>
|
||||
*
|
||||
* - @subpage test_threads
|
||||
* - @subpage test_dynamic
|
||||
* - @subpage test_msg
|
||||
* - @subpage test_sem
|
||||
* - @subpage test_mtx
|
||||
* - @subpage test_events
|
||||
* - @subpage test_mbox
|
||||
* - @subpage test_queues
|
||||
* - @subpage test_heap
|
||||
* - @subpage test_pools
|
||||
* - @subpage test_sys
|
||||
* - @subpage test_benchmarks
|
||||
* .
|
||||
*/
|
175
test/rt/test.h
175
test/rt/test.h
|
@ -1,175 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file test.h
|
||||
* @brief Tests support header.
|
||||
*
|
||||
* @addtogroup test
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _TEST_H_
|
||||
#define _TEST_H_
|
||||
|
||||
/**
|
||||
* @brief Delay inserted between test cases.
|
||||
*/
|
||||
#if !defined(DELAY_BETWEEN_TESTS) || defined(__DOXYGEN__)
|
||||
#define DELAY_BETWEEN_TESTS 200
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief If @p TRUE then benchmarks are not included.
|
||||
*/
|
||||
#if !defined(TEST_NO_BENCHMARKS) || defined(__DOXYGEN__)
|
||||
#define TEST_NO_BENCHMARKS FALSE
|
||||
#endif
|
||||
|
||||
#define MAX_THREADS 5
|
||||
#define MAX_TOKENS 16
|
||||
|
||||
#if defined(CH_ARCHITECTURE_AVR) || defined(CH_ARCHITECTURE_MSP430)
|
||||
#define THREADS_STACK_SIZE 48
|
||||
#elif defined(CH_ARCHITECTURE_STM8)
|
||||
#define THREADS_STACK_SIZE 64
|
||||
#elif defined(CH_ARCHITECTURE_SIMIA32)
|
||||
#define THREADS_STACK_SIZE 512
|
||||
#else
|
||||
#define THREADS_STACK_SIZE 128
|
||||
#endif
|
||||
#define WA_SIZE THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE)
|
||||
|
||||
/**
|
||||
* @brief Structure representing a test case.
|
||||
*/
|
||||
struct testcase {
|
||||
const char *name; /**< @brief Test case name. */
|
||||
void (*setup)(void); /**< @brief Test case preparation function. */
|
||||
void (*teardown)(void); /**< @brief Test case clean up function. */
|
||||
void (*execute)(void); /**< @brief Test case execution function. */
|
||||
};
|
||||
|
||||
#ifndef __DOXYGEN__
|
||||
union test_buffers {
|
||||
struct {
|
||||
THD_WORKING_AREA(T0, THREADS_STACK_SIZE);
|
||||
THD_WORKING_AREA(T1, THREADS_STACK_SIZE);
|
||||
THD_WORKING_AREA(T2, THREADS_STACK_SIZE);
|
||||
THD_WORKING_AREA(T3, THREADS_STACK_SIZE);
|
||||
THD_WORKING_AREA(T4, THREADS_STACK_SIZE);
|
||||
} wa;
|
||||
uint8_t buffer[WA_SIZE * 5];
|
||||
};
|
||||
#endif
|
||||
|
||||
extern bool test_global_fail;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void TestThread(void *p);
|
||||
void test_printn(uint32_t n);
|
||||
void test_print(const char *msgp);
|
||||
void test_println(const char *msgp);
|
||||
void test_emit_token(char token);
|
||||
bool _test_fail(unsigned point);
|
||||
bool _test_assert(unsigned point, bool condition);
|
||||
bool _test_assert_sequence(unsigned point, char *expected);
|
||||
bool _test_assert_time_window(unsigned point, systime_t start, systime_t end);
|
||||
void test_terminate_threads(void);
|
||||
void test_wait_threads(void);
|
||||
systime_t test_wait_tick(void);
|
||||
void test_start_timer(unsigned ms);
|
||||
#if CH_DBG_THREADS_PROFILING
|
||||
void test_cpu_pulse(unsigned duration);
|
||||
#endif
|
||||
#if defined(WIN32)
|
||||
void ChkIntSources(void);
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Test failure enforcement.
|
||||
*/
|
||||
#define test_fail(point) { \
|
||||
_test_fail(point); \
|
||||
return; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test assertion.
|
||||
*
|
||||
* @param[in] point numeric assertion identifier
|
||||
* @param[in] condition a boolean expression that must be verified to be true
|
||||
* @param[in] msg failure message
|
||||
*/
|
||||
#define test_assert(point, condition, msg) { \
|
||||
if (_test_assert(point, condition)) \
|
||||
return; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test assertion with lock.
|
||||
*
|
||||
* @param[in] point numeric assertion identifier
|
||||
* @param[in] condition a boolean expression that must be verified to be true
|
||||
* @param[in] msg failure message
|
||||
*/
|
||||
#define test_assert_lock(point, condition, msg) { \
|
||||
chSysLock(); \
|
||||
if (_test_assert(point, condition)) { \
|
||||
chSysUnlock(); \
|
||||
return; \
|
||||
} \
|
||||
chSysUnlock(); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test sequence assertion.
|
||||
*
|
||||
* @param[in] point numeric assertion identifier
|
||||
* @param[in] expected string to be matched with the tokens buffer
|
||||
*/
|
||||
#define test_assert_sequence(point, expected) { \
|
||||
if (_test_assert_sequence(point, expected)) \
|
||||
return; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test time window assertion.
|
||||
*
|
||||
* @param[in] point numeric assertion identifier
|
||||
* @param[in] start initial time in the window (included)
|
||||
* @param[in] end final time in the window (not included)
|
||||
*/
|
||||
#define test_assert_time_window(point, start, end) { \
|
||||
if (_test_assert_time_window(point, start, end)) \
|
||||
return; \
|
||||
}
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
extern thread_t *threads[MAX_THREADS];
|
||||
extern union test_buffers test;
|
||||
extern void * ROMCONST wa[];
|
||||
extern bool test_timer_done;
|
||||
#endif
|
||||
|
||||
#endif /* _TEST_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,674 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "test.h"
|
||||
|
||||
/**
|
||||
* @page test_benchmarks Kernel Benchmarks
|
||||
*
|
||||
* File: @ref testbmk.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements a series of system benchmarks. The benchmarks are
|
||||
* useful as a stress test and as a reference when comparing ChibiOS/RT
|
||||
* with similar systems.
|
||||
*
|
||||
* <h2>Objective</h2>
|
||||
* Objective of the test module is to provide a performance index for the
|
||||
* most critical system subsystems. The performance numbers allow to
|
||||
* discover performance regressions between successive ChibiOS/RT releases.
|
||||
*
|
||||
* <h2>Preconditions</h2>
|
||||
* None.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_benchmarks_001
|
||||
* - @subpage test_benchmarks_002
|
||||
* - @subpage test_benchmarks_003
|
||||
* - @subpage test_benchmarks_004
|
||||
* - @subpage test_benchmarks_005
|
||||
* - @subpage test_benchmarks_006
|
||||
* - @subpage test_benchmarks_007
|
||||
* - @subpage test_benchmarks_008
|
||||
* - @subpage test_benchmarks_009
|
||||
* - @subpage test_benchmarks_010
|
||||
* - @subpage test_benchmarks_011
|
||||
* - @subpage test_benchmarks_012
|
||||
* .
|
||||
* @file testbmk.c Kernel Benchmarks
|
||||
* @brief Kernel Benchmarks source file
|
||||
* @file testbmk.h
|
||||
* @brief Kernel Benchmarks header file
|
||||
*/
|
||||
|
||||
#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
|
||||
static semaphore_t sem1;
|
||||
#endif
|
||||
#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
|
||||
static mutex_t mtx1;
|
||||
#endif
|
||||
|
||||
static THD_FUNCTION(thread1, p) {
|
||||
|
||||
chThdExit((msg_t)p);
|
||||
}
|
||||
|
||||
#if CH_CFG_USE_MESSAGES || defined(__DOXYGEN__)
|
||||
static THD_FUNCTION(thread2, p) {
|
||||
thread_t *tp;
|
||||
msg_t msg;
|
||||
|
||||
(void)p;
|
||||
do {
|
||||
tp = chMsgWait();
|
||||
msg = chMsgGet(tp);
|
||||
chMsgRelease(tp, msg);
|
||||
} while (msg);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
__attribute__((noinline))
|
||||
#endif
|
||||
static unsigned int msg_loop_test(thread_t *tp) {
|
||||
|
||||
uint32_t n = 0;
|
||||
test_wait_tick();
|
||||
test_start_timer(1000);
|
||||
do {
|
||||
(void)chMsgSend(tp, 1);
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (!test_timer_done);
|
||||
(void)chMsgSend(tp, 0);
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @page test_benchmarks_001 Messages performance #1
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A message server thread is created with a lower priority than the client
|
||||
* thread, the messages throughput per second is measured and the result
|
||||
* printed in the output log.
|
||||
*/
|
||||
|
||||
static void bmk1_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread2, NULL);
|
||||
n = msg_loop_test(threads[0]);
|
||||
test_wait_threads();
|
||||
test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_print(" msgs/S, ");
|
||||
test_printn(n << 1);
|
||||
test_println(" ctxswc/S");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testbmk1 = {
|
||||
"Benchmark, messages #1",
|
||||
NULL,
|
||||
NULL,
|
||||
bmk1_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_benchmarks_002 Messages performance #2
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A message server thread is created with an higher priority than the client
|
||||
* thread, the messages throughput per second is measured and the result
|
||||
* printed in the output log.
|
||||
*/
|
||||
|
||||
static void bmk2_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread2, NULL);
|
||||
n = msg_loop_test(threads[0]);
|
||||
test_wait_threads();
|
||||
test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_print(" msgs/S, ");
|
||||
test_printn(n << 1);
|
||||
test_println(" ctxswc/S");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testbmk2 = {
|
||||
"Benchmark, messages #2",
|
||||
NULL,
|
||||
NULL,
|
||||
bmk2_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_benchmarks_003 Messages performance #3
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A message server thread is created with an higher priority than the client
|
||||
* thread, four lower priority threads crowd the ready list, the messages
|
||||
* throughput per second is measured while the ready list and the result
|
||||
* printed in the output log.
|
||||
*/
|
||||
|
||||
static void bmk3_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread2, NULL);
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-2, thread1, NULL);
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread1, NULL);
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-4, thread1, NULL);
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-5, thread1, NULL);
|
||||
n = msg_loop_test(threads[0]);
|
||||
test_wait_threads();
|
||||
test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_print(" msgs/S, ");
|
||||
test_printn(n << 1);
|
||||
test_println(" ctxswc/S");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testbmk3 = {
|
||||
"Benchmark, messages #3",
|
||||
NULL,
|
||||
NULL,
|
||||
bmk3_execute
|
||||
};
|
||||
#endif /* if CH_CFG_USE_MESSAGES */
|
||||
|
||||
/**
|
||||
* @page test_benchmarks_004 Context Switch performance
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A thread is created that just performs a @p chSchGoSleepS() into a loop,
|
||||
* the thread is awakened as fast is possible by the tester thread.<br>
|
||||
* The Context Switch performance is calculated by measuring the number of
|
||||
* iterations after a second of continuous operations.
|
||||
*/
|
||||
|
||||
static THD_FUNCTION(thread4, p) {
|
||||
msg_t msg;
|
||||
thread_t *self = chThdGetSelfX();
|
||||
|
||||
(void)p;
|
||||
chSysLock();
|
||||
do {
|
||||
chSchGoSleepS(CH_STATE_SUSPENDED);
|
||||
msg = self->u.rdymsg;
|
||||
} while (msg == MSG_OK);
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
static void bmk4_execute(void) {
|
||||
thread_t *tp;
|
||||
uint32_t n;
|
||||
|
||||
tp = threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1,
|
||||
thread4, NULL);
|
||||
n = 0;
|
||||
test_wait_tick();
|
||||
test_start_timer(1000);
|
||||
do {
|
||||
chSysLock();
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSysUnlock();
|
||||
n += 4;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (!test_timer_done);
|
||||
chSysLock();
|
||||
chSchWakeupS(tp, MSG_TIMEOUT);
|
||||
chSysUnlock();
|
||||
|
||||
test_wait_threads();
|
||||
test_print("--- Score : ");
|
||||
test_printn(n * 2);
|
||||
test_println(" ctxswc/S");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testbmk4 = {
|
||||
"Benchmark, context switch",
|
||||
NULL,
|
||||
NULL,
|
||||
bmk4_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_benchmarks_005 Threads performance, full cycle
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Threads are continuously created and terminated into a loop. A full
|
||||
* @p chThdCreateStatic() / @p chThdExit() / @p chThdWait() cycle is performed
|
||||
* in each iteration.<br>
|
||||
* The performance is calculated by measuring the number of iterations after
|
||||
* a second of continuous operations.
|
||||
*/
|
||||
|
||||
static void bmk5_execute(void) {
|
||||
|
||||
uint32_t n = 0;
|
||||
void *wap = wa[0];
|
||||
tprio_t prio = chThdGetPriorityX() - 1;
|
||||
test_wait_tick();
|
||||
test_start_timer(1000);
|
||||
do {
|
||||
chThdWait(chThdCreateStatic(wap, WA_SIZE, prio, thread1, NULL));
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (!test_timer_done);
|
||||
test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_println(" threads/S");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testbmk5 = {
|
||||
"Benchmark, threads, full cycle",
|
||||
NULL,
|
||||
NULL,
|
||||
bmk5_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_benchmarks_006 Threads performance, create/exit only
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Threads are continuously created and terminated into a loop. A partial
|
||||
* @p chThdCreateStatic() / @p chThdExit() cycle is performed in each
|
||||
* iteration, the @p chThdWait() is not necessary because the thread is
|
||||
* created at an higher priority so there is no need to wait for it to
|
||||
* terminate.<br>
|
||||
* The performance is calculated by measuring the number of iterations after
|
||||
* a second of continuous operations.
|
||||
*/
|
||||
|
||||
static void bmk6_execute(void) {
|
||||
|
||||
uint32_t n = 0;
|
||||
void *wap = wa[0];
|
||||
tprio_t prio = chThdGetPriorityX() + 1;
|
||||
test_wait_tick();
|
||||
test_start_timer(1000);
|
||||
do {
|
||||
#if CH_CFG_USE_REGISTRY
|
||||
chThdRelease(chThdCreateStatic(wap, WA_SIZE, prio, thread1, NULL));
|
||||
#else
|
||||
chThdCreateStatic(wap, WA_SIZE, prio, thread1, NULL);
|
||||
#endif
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (!test_timer_done);
|
||||
test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_println(" threads/S");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testbmk6 = {
|
||||
"Benchmark, threads, create only",
|
||||
NULL,
|
||||
NULL,
|
||||
bmk6_execute
|
||||
};
|
||||
|
||||
#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_benchmarks_007 Mass reschedule performance
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads are created and atomically rescheduled by resetting the
|
||||
* semaphore where they are waiting on. The operation is performed into a
|
||||
* continuous loop.<br>
|
||||
* The performance is calculated by measuring the number of iterations after
|
||||
* a second of continuous operations.
|
||||
*/
|
||||
|
||||
static THD_FUNCTION(thread3, p) {
|
||||
|
||||
(void)p;
|
||||
while (!chThdShouldTerminateX())
|
||||
chSemWait(&sem1);
|
||||
}
|
||||
|
||||
static void bmk7_setup(void) {
|
||||
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static void bmk7_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, thread3, NULL);
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+4, thread3, NULL);
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, thread3, NULL);
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+2, thread3, NULL);
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+1, thread3, NULL);
|
||||
|
||||
n = 0;
|
||||
test_wait_tick();
|
||||
test_start_timer(1000);
|
||||
do {
|
||||
chSemReset(&sem1, 0);
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (!test_timer_done);
|
||||
test_terminate_threads();
|
||||
chSemReset(&sem1, 0);
|
||||
test_wait_threads();
|
||||
|
||||
test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_print(" reschedules/S, ");
|
||||
test_printn(n * 6);
|
||||
test_println(" ctxswc/S");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testbmk7 = {
|
||||
"Benchmark, mass reschedule, 5 threads",
|
||||
bmk7_setup,
|
||||
NULL,
|
||||
bmk7_execute
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @page test_benchmarks_008 I/O Round-Robin voluntary reschedule.
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads are created at equal priority, each thread just increases a
|
||||
* variable and yields.<br>
|
||||
* The performance is calculated by measuring the number of iterations after
|
||||
* a second of continuous operations.
|
||||
*/
|
||||
|
||||
static THD_FUNCTION(thread8, p) {
|
||||
|
||||
do {
|
||||
chThdYield();
|
||||
chThdYield();
|
||||
chThdYield();
|
||||
chThdYield();
|
||||
(*(uint32_t *)p) += 4;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while(!chThdShouldTerminateX());
|
||||
}
|
||||
|
||||
static void bmk8_execute(void) {
|
||||
uint32_t n;
|
||||
|
||||
n = 0;
|
||||
test_wait_tick();
|
||||
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n);
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n);
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n);
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n);
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n);
|
||||
|
||||
chThdSleepSeconds(1);
|
||||
test_terminate_threads();
|
||||
test_wait_threads();
|
||||
|
||||
test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_println(" ctxswc/S");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testbmk8 = {
|
||||
"Benchmark, round robin context switching",
|
||||
NULL,
|
||||
NULL,
|
||||
bmk8_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_benchmarks_009 Virtual Timers set/reset performance
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A virtual timer is set and immediately reset into a continuous loop.<br>
|
||||
* The performance is calculated by measuring the number of iterations after
|
||||
* a second of continuous operations.
|
||||
*/
|
||||
|
||||
static void tmo(void *param) {(void)param;}
|
||||
|
||||
static void bmk09_execute(void) {
|
||||
static virtual_timer_t vt1, vt2;
|
||||
uint32_t n = 0;
|
||||
|
||||
test_wait_tick();
|
||||
test_start_timer(1000);
|
||||
do {
|
||||
chSysLock();
|
||||
chVTDoSetI(&vt1, 1, tmo, NULL);
|
||||
chVTDoSetI(&vt2, 10000, tmo, NULL);
|
||||
chVTDoResetI(&vt1);
|
||||
chVTDoResetI(&vt2);
|
||||
chSysUnlock();
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (!test_timer_done);
|
||||
test_print("--- Score : ");
|
||||
test_printn(n * 2);
|
||||
test_println(" timers/S");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testbmk9 = {
|
||||
"Benchmark, virtual timers set/reset",
|
||||
NULL,
|
||||
NULL,
|
||||
bmk09_execute
|
||||
};
|
||||
|
||||
#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_benchmarks_010 Semaphores wait/signal performance
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A counting semaphore is taken/released into a continuous loop, no Context
|
||||
* Switch happens because the counter is always non negative.<br>
|
||||
* The performance is calculated by measuring the number of iterations after
|
||||
* a second of continuous operations.
|
||||
*/
|
||||
|
||||
static void bmk10_setup(void) {
|
||||
|
||||
chSemObjectInit(&sem1, 1);
|
||||
}
|
||||
|
||||
static void bmk10_execute(void) {
|
||||
uint32_t n = 0;
|
||||
|
||||
test_wait_tick();
|
||||
test_start_timer(1000);
|
||||
do {
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (!test_timer_done);
|
||||
test_print("--- Score : ");
|
||||
test_printn(n * 4);
|
||||
test_println(" wait+signal/S");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testbmk10 = {
|
||||
"Benchmark, semaphores wait/signal",
|
||||
bmk10_setup,
|
||||
NULL,
|
||||
bmk10_execute
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_benchmarks_011 Mutexes lock/unlock performance
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A mutex is locked/unlocked into a continuous loop, no Context Switch happens
|
||||
* because there are no other threads asking for the mutex.<br>
|
||||
* The performance is calculated by measuring the number of iterations after
|
||||
* a second of continuous operations.
|
||||
*/
|
||||
|
||||
static void bmk11_setup(void) {
|
||||
|
||||
chMtxObjectInit(&mtx1);
|
||||
}
|
||||
|
||||
static void bmk11_execute(void) {
|
||||
uint32_t n = 0;
|
||||
|
||||
test_wait_tick();
|
||||
test_start_timer(1000);
|
||||
do {
|
||||
chMtxLock(&mtx1);
|
||||
chMtxUnlock(&mtx1);
|
||||
chMtxLock(&mtx1);
|
||||
chMtxUnlock(&mtx1);
|
||||
chMtxLock(&mtx1);
|
||||
chMtxUnlock(&mtx1);
|
||||
chMtxLock(&mtx1);
|
||||
chMtxUnlock(&mtx1);
|
||||
n++;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (!test_timer_done);
|
||||
test_print("--- Score : ");
|
||||
test_printn(n * 4);
|
||||
test_println(" lock+unlock/S");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testbmk11 = {
|
||||
"Benchmark, mutexes lock/unlock",
|
||||
bmk11_setup,
|
||||
NULL,
|
||||
bmk11_execute
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @page test_benchmarks_012 RAM Footprint
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The memory size of the various kernel objects is printed.
|
||||
*/
|
||||
|
||||
static void bmk12_execute(void) {
|
||||
|
||||
test_print("--- System: ");
|
||||
test_printn(sizeof(ch_system_t));
|
||||
test_println(" bytes");
|
||||
test_print("--- Thread: ");
|
||||
test_printn(sizeof(thread_t));
|
||||
test_println(" bytes");
|
||||
test_print("--- Timer : ");
|
||||
test_printn(sizeof(virtual_timer_t));
|
||||
test_println(" bytes");
|
||||
#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
|
||||
test_print("--- Semaph: ");
|
||||
test_printn(sizeof(semaphore_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
|
||||
test_print("--- EventS: ");
|
||||
test_printn(sizeof(event_source_t));
|
||||
test_println(" bytes");
|
||||
test_print("--- EventL: ");
|
||||
test_printn(sizeof(event_listener_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
|
||||
test_print("--- Mutex : ");
|
||||
test_printn(sizeof(mutex_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__)
|
||||
test_print("--- CondV.: ");
|
||||
test_printn(sizeof(condition_variable_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
#if 0
|
||||
test_print("--- Queue : ");
|
||||
test_printn(sizeof(io_queue_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
#if CH_CFG_USE_MAILBOXES || defined(__DOXYGEN__)
|
||||
test_print("--- MailB.: ");
|
||||
test_printn(sizeof(mailbox_t));
|
||||
test_println(" bytes");
|
||||
#endif
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testbmk12 = {
|
||||
"Benchmark, RAM footprint",
|
||||
NULL,
|
||||
NULL,
|
||||
bmk12_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Test sequence for benchmarks.
|
||||
*/
|
||||
ROMCONST struct testcase * ROMCONST patternbmk[] = {
|
||||
#if !TEST_NO_BENCHMARKS
|
||||
#if CH_CFG_USE_MESSAGES || defined(__DOXYGEN__)
|
||||
&testbmk1,
|
||||
&testbmk2,
|
||||
&testbmk3,
|
||||
#endif
|
||||
&testbmk4,
|
||||
&testbmk5,
|
||||
&testbmk6,
|
||||
#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
|
||||
&testbmk7,
|
||||
#endif
|
||||
&testbmk8,
|
||||
&testbmk9,
|
||||
#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
|
||||
&testbmk10,
|
||||
#endif
|
||||
#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
|
||||
&testbmk11,
|
||||
#endif
|
||||
&testbmk12,
|
||||
#endif
|
||||
NULL
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _TESTBMK_H_
|
||||
#define _TESTBMK_H_
|
||||
|
||||
extern ROMCONST struct testcase * ROMCONST patternbmk[];
|
||||
|
||||
#endif /* _TESTBMK_H_ */
|
|
@ -1,263 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "test.h"
|
||||
|
||||
/**
|
||||
* @page test_dynamic Dynamic APIs test
|
||||
*
|
||||
* File: @ref testdyn.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the dynamic thread creation
|
||||
* APIs.
|
||||
*
|
||||
* <h2>Objective</h2>
|
||||
* Objective of the test module is to cover 100% of the dynamic APIs code.
|
||||
*
|
||||
* <h2>Preconditions</h2>
|
||||
* The module requires the following kernel options:
|
||||
* - @p CH_CFG_USE_DYNAMIC
|
||||
* - @p CH_CFG_USE_HEAP
|
||||
* - @p CH_CFG_USE_MEMPOOLS
|
||||
* .
|
||||
* In case some of the required options are not enabled then some or all tests
|
||||
* may be skipped.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_dynamic_001
|
||||
* - @subpage test_dynamic_002
|
||||
* - @subpage test_dynamic_003
|
||||
* .
|
||||
* @file testdyn.c
|
||||
* @brief Dynamic thread APIs test source file
|
||||
* @file testdyn.h
|
||||
* @brief Dynamic thread APIs test header file
|
||||
*/
|
||||
|
||||
#if CH_CFG_USE_DYNAMIC || defined(__DOXYGEN__)
|
||||
#if CH_CFG_USE_HEAP || defined(__DOXYGEN__)
|
||||
static memory_heap_t heap1;
|
||||
#endif
|
||||
#if CH_CFG_USE_MEMPOOLS || defined(__DOXYGEN__)
|
||||
static memory_pool_t mp1;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @page test_dynamic_001 Threads creation from Memory Heap
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Two threads are started by allocating the memory from the Memory Heap then
|
||||
* the remaining heap space is arbitrarily allocated and a third tread startup
|
||||
* is attempted.<br>
|
||||
* The test expects the first two threads to successfully start and the last
|
||||
* one to fail.
|
||||
*/
|
||||
|
||||
static THD_FUNCTION(thread, p) {
|
||||
|
||||
test_emit_token(*(char *)p);
|
||||
}
|
||||
|
||||
#if CH_CFG_USE_HEAP || defined(__DOXYGEN__)
|
||||
static void dyn1_setup(void) {
|
||||
|
||||
chHeapObjectInit(&heap1, test.buffer, sizeof(union test_buffers));
|
||||
}
|
||||
|
||||
static void dyn1_execute(void) {
|
||||
size_t n, sz;
|
||||
tprio_t prio = chThdGetPriorityX();
|
||||
|
||||
(void)chHeapStatus(&heap1, &sz, NULL);
|
||||
/* Starting threads from the heap. */
|
||||
threads[0] = chThdCreateFromHeap(&heap1,
|
||||
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
|
||||
"dyn1",
|
||||
prio-1, thread, "A");
|
||||
threads[1] = chThdCreateFromHeap(&heap1,
|
||||
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
|
||||
"dyn2",
|
||||
prio-2, thread, "B");
|
||||
/* Large working area in order to make the thread creation fail.*/
|
||||
threads[2] = chThdCreateFromHeap(&heap1,
|
||||
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE * 16),
|
||||
"dyn3",
|
||||
prio-3, thread, "C");
|
||||
|
||||
test_assert(1, (threads[0] != NULL) &&
|
||||
(threads[1] != NULL) &&
|
||||
(threads[2] == NULL) &&
|
||||
(threads[3] == NULL) &&
|
||||
(threads[4] == NULL),
|
||||
"thread creation failed");
|
||||
|
||||
/* Claiming the memory from terminated threads. */
|
||||
test_wait_threads();
|
||||
test_assert_sequence(2, "AB");
|
||||
|
||||
/* Heap status checked again.*/
|
||||
test_assert(3, chHeapStatus(&heap1, &n, NULL) == 1, "heap fragmented");
|
||||
test_assert(4, n == sz, "heap size changed");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testdyn1 = {
|
||||
"Dynamic APIs, threads creation from heap",
|
||||
dyn1_setup,
|
||||
NULL,
|
||||
dyn1_execute
|
||||
};
|
||||
#endif /* (CH_CFG_USE_HEAP && !CH_CFG_USE_MALLOC_HEAP) */
|
||||
|
||||
#if CH_CFG_USE_MEMPOOLS || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_dynamic_002 Threads creation from Memory Pool
|
||||
*
|
||||
* <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.
|
||||
*/
|
||||
|
||||
static void dyn2_setup(void) {
|
||||
|
||||
chPoolObjectInit(&mp1, THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), NULL);
|
||||
}
|
||||
|
||||
static void dyn2_execute(void) {
|
||||
int i;
|
||||
tprio_t prio = chThdGetPriorityX();
|
||||
|
||||
/* Adding the WAs to the pool. */
|
||||
for (i = 0; i < 4; i++)
|
||||
chPoolFree(&mp1, wa[i]);
|
||||
|
||||
/* Starting threads from the memory pool. */
|
||||
threads[0] = chThdCreateFromMemoryPool(&mp1, "dyn1", prio-1, thread, "A");
|
||||
threads[1] = chThdCreateFromMemoryPool(&mp1, "dyn2", prio-2, thread, "B");
|
||||
threads[2] = chThdCreateFromMemoryPool(&mp1, "dyn3", prio-3, thread, "C");
|
||||
threads[3] = chThdCreateFromMemoryPool(&mp1, "dyn4", prio-4, thread, "D");
|
||||
threads[4] = chThdCreateFromMemoryPool(&mp1, "dyn5", prio-5, thread, "E");
|
||||
|
||||
test_assert(1, (threads[0] != NULL) &&
|
||||
(threads[1] != NULL) &&
|
||||
(threads[2] != NULL) &&
|
||||
(threads[3] != NULL) &&
|
||||
(threads[4] == NULL),
|
||||
"thread creation failed");
|
||||
|
||||
/* Claiming the memory from terminated threads. */
|
||||
test_wait_threads();
|
||||
test_assert_sequence(2, "ABCD");
|
||||
|
||||
/* Now the pool must be full again. */
|
||||
for (i = 0; i < 4; i++)
|
||||
test_assert(3, chPoolAlloc(&mp1) != NULL, "pool list empty");
|
||||
test_assert(4, chPoolAlloc(&mp1) == NULL, "pool list not empty");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testdyn2 = {
|
||||
"Dynamic APIs, threads creation from memory pool",
|
||||
dyn2_setup,
|
||||
NULL,
|
||||
dyn2_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_MEMPOOLS */
|
||||
|
||||
#if (CH_CFG_USE_HEAP && CH_CFG_USE_REGISTRY) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_dynamic_003 Registry and References test
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Registry and Thread References APIs are tested for functionality and
|
||||
* coverage.
|
||||
*/
|
||||
|
||||
static bool regfind(thread_t *tp) {
|
||||
thread_t *ftp;
|
||||
bool found = false;
|
||||
|
||||
ftp = chRegFirstThread();
|
||||
do {
|
||||
found |= ftp == tp;
|
||||
ftp = chRegNextThread(ftp);
|
||||
} while (ftp != NULL);
|
||||
return found;
|
||||
}
|
||||
|
||||
static void dyn3_setup(void) {
|
||||
|
||||
chHeapObjectInit(&heap1, test.buffer, sizeof(union test_buffers));
|
||||
}
|
||||
|
||||
static void dyn3_execute(void) {
|
||||
thread_t *tp;
|
||||
tprio_t prio = chThdGetPriorityX();
|
||||
|
||||
/* Testing references increase/decrease and final detach.*/
|
||||
tp = chThdCreateFromHeap(&heap1, WA_SIZE, "dyn1", prio-1, thread, "A");
|
||||
test_assert(1, tp->refs == 1, "wrong initial reference counter");
|
||||
chThdAddRef(tp);
|
||||
test_assert(2, tp->refs == 2, "references increase failure");
|
||||
chThdRelease(tp);
|
||||
test_assert(3, tp->refs == 1, "references decrease failure");
|
||||
|
||||
/* Verify the new threads count.*/
|
||||
test_assert(4, regfind(tp), "thread missing from registry");
|
||||
test_assert(5, regfind(tp), "thread disappeared");
|
||||
|
||||
/* Detach and let the thread execute and terminate.*/
|
||||
chThdRelease(tp);
|
||||
test_assert(6, tp->refs == 0, "detach failure");
|
||||
test_assert(7, tp->state == CH_STATE_READY, "invalid state");
|
||||
test_assert(8, regfind(tp), "thread disappeared");
|
||||
test_assert(9, regfind(tp), "thread disappeared");
|
||||
chThdSleepMilliseconds(50); /* The thread just terminates. */
|
||||
test_assert(10, tp->state == CH_STATE_FINAL, "invalid state");
|
||||
|
||||
/* Clearing the zombie by scanning the registry.*/
|
||||
test_assert(11, regfind(tp), "thread disappeared");
|
||||
test_assert(12, !regfind(tp), "thread still in registry");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testdyn3 = {
|
||||
"Dynamic APIs, registry and references",
|
||||
dyn3_setup,
|
||||
NULL,
|
||||
dyn3_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_HEAP && CH_CFG_USE_REGISTRY */
|
||||
#endif /* CH_CFG_USE_DYNAMIC */
|
||||
|
||||
/**
|
||||
* @brief Test sequence for dynamic APIs.
|
||||
*/
|
||||
ROMCONST struct testcase * ROMCONST patterndyn[] = {
|
||||
#if CH_CFG_USE_DYNAMIC || defined(__DOXYGEN__)
|
||||
#if CH_CFG_USE_HEAP || defined(__DOXYGEN__)
|
||||
&testdyn1,
|
||||
#endif
|
||||
#if CH_CFG_USE_MEMPOOLS || defined(__DOXYGEN__)
|
||||
&testdyn2,
|
||||
#endif
|
||||
#if (CH_CFG_USE_HEAP && CH_CFG_USE_REGISTRY) || defined(__DOXYGEN__)
|
||||
&testdyn3,
|
||||
#endif
|
||||
#endif
|
||||
NULL
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _TESTDYN_H_
|
||||
#define _TESTDYN_H_
|
||||
|
||||
extern ROMCONST struct testcase * ROMCONST patterndyn[];
|
||||
|
||||
#endif /* _TESTDYN_H_ */
|
|
@ -1,295 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "test.h"
|
||||
|
||||
/**
|
||||
* @page test_events Events test
|
||||
*
|
||||
* File: @ref testevt.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the @ref events subsystem.
|
||||
*
|
||||
* <h2>Objective</h2>
|
||||
* Objective of the test module is to cover 100% of the @ref events subsystem.
|
||||
*
|
||||
* <h2>Preconditions</h2>
|
||||
* The module requires the following kernel options:
|
||||
* - @p CH_CFG_USE_EVENTS
|
||||
* - @p CH_CFG_USE_EVENTS_TIMEOUT
|
||||
* .
|
||||
* In case some of the required options are not enabled then some or all tests
|
||||
* may be skipped.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_events_001
|
||||
* - @subpage test_events_002
|
||||
* - @subpage test_events_003
|
||||
* .
|
||||
* @file testevt.c
|
||||
* @brief Events test source file
|
||||
* @file testevt.h
|
||||
* @brief Events test header file
|
||||
*/
|
||||
|
||||
#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
|
||||
|
||||
#define ALLOWED_DELAY MS2ST(5)
|
||||
|
||||
/*
|
||||
* Note, the static initializers are not really required because the
|
||||
* variables are explicitly initialized in each test case. It is done in order
|
||||
* to test the macros.
|
||||
*/
|
||||
static EVENTSOURCE_DECL(es1);
|
||||
static EVENTSOURCE_DECL(es2);
|
||||
|
||||
/**
|
||||
* @page test_events_001 Events registration and dispatch
|
||||
*
|
||||
* <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.<br>
|
||||
* In the second part the test dispatches three event flags and verifies that
|
||||
* the associated event handlers are invoked in LSb-first order.
|
||||
*/
|
||||
|
||||
static void evt1_setup(void) {
|
||||
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
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 void evt1_execute(void) {
|
||||
event_listener_t el1, el2;
|
||||
|
||||
/*
|
||||
* Testing chEvtRegisterMask() and chEvtUnregister().
|
||||
*/
|
||||
chEvtObjectInit(&es1);
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es1, &el2, 2);
|
||||
test_assert(1, chEvtIsListeningI(&es1), "no listener");
|
||||
chEvtUnregister(&es1, &el1);
|
||||
test_assert(2, chEvtIsListeningI(&es1), "no listener");
|
||||
chEvtUnregister(&es1, &el2);
|
||||
test_assert(3, !chEvtIsListeningI(&es1), "stuck listener");
|
||||
|
||||
/*
|
||||
* Testing chEvtDispatch().
|
||||
*/
|
||||
chEvtDispatch(evhndl, 7);
|
||||
test_assert_sequence(4, "ABC");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testevt1 = {
|
||||
"Events, registration and dispatch",
|
||||
evt1_setup,
|
||||
NULL,
|
||||
evt1_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_events_002 Events wait and broadcast
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* In this test the following APIs are indipently tested by starting threads
|
||||
* that signal/broadcast events after fixed delays:
|
||||
* - @p chEvtWaitOne()
|
||||
* - @p chEvtWaitAny()
|
||||
* - @p chEvtWaitAll()
|
||||
* .
|
||||
* After each test phase the test verifies that the events have been served at
|
||||
* the expected time and that there are no stuck event flags.
|
||||
*/
|
||||
|
||||
static void evt2_setup(void) {
|
||||
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread1, p) {
|
||||
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtSignal((thread_t *)p, 1);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread2, p) {
|
||||
|
||||
(void)p;
|
||||
chEvtBroadcast(&es1);
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtBroadcast(&es2);
|
||||
}
|
||||
|
||||
static void evt2_execute(void) {
|
||||
eventmask_t m;
|
||||
event_listener_t el1, el2;
|
||||
systime_t target_time;
|
||||
|
||||
/*
|
||||
* Test on chEvtWaitOne() without wait.
|
||||
*/
|
||||
chEvtAddEvents(7);
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(1, m == 1, "single event error");
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(2, m == 2, "single event error");
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(3, m == 4, "single event error");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(4, m == 0, "stuck event");
|
||||
|
||||
/*
|
||||
* Test on chEvtWaitOne() with wait.
|
||||
*/
|
||||
test_wait_tick();
|
||||
target_time = chVTGetSystemTime() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
thread1, chThdGetSelfX());
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert_time_window(5, target_time, target_time + ALLOWED_DELAY);
|
||||
test_assert(6, m == 1, "single event error");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(7, m == 0, "stuck event");
|
||||
test_wait_threads();
|
||||
|
||||
/*
|
||||
* Test on chEvtWaitAny() without wait.
|
||||
*/
|
||||
chEvtAddEvents(5);
|
||||
m = chEvtWaitAny(ALL_EVENTS);
|
||||
test_assert(8, m == 5, "unexpected pending bit");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(9, m == 0, "stuck event");
|
||||
|
||||
/*
|
||||
* Test on chEvtWaitAny() with wait.
|
||||
*/
|
||||
test_wait_tick();
|
||||
target_time = chVTGetSystemTime() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
thread1, chThdGetSelfX());
|
||||
m = chEvtWaitAny(ALL_EVENTS);
|
||||
test_assert_time_window(10, target_time, target_time + ALLOWED_DELAY);
|
||||
test_assert(11, m == 1, "single event error");
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(12, m == 0, "stuck event");
|
||||
test_wait_threads();
|
||||
|
||||
/*
|
||||
* Test on chEvtWaitAll().
|
||||
*/
|
||||
chEvtObjectInit(&es1);
|
||||
chEvtObjectInit(&es2);
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es2, &el2, 4);
|
||||
test_wait_tick();
|
||||
target_time = chVTGetSystemTime() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
thread2, "A");
|
||||
m = chEvtWaitAll(5);
|
||||
test_assert_time_window(13, target_time, target_time + ALLOWED_DELAY);
|
||||
m = chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
test_assert(14, m == 0, "stuck event");
|
||||
test_wait_threads();
|
||||
chEvtUnregister(&es1, &el1);
|
||||
chEvtUnregister(&es2, &el2);
|
||||
test_assert(15, !chEvtIsListeningI(&es1), "stuck listener");
|
||||
test_assert(16, !chEvtIsListeningI(&es2), "stuck listener");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testevt2 = {
|
||||
"Events, wait and broadcast",
|
||||
evt2_setup,
|
||||
NULL,
|
||||
evt2_execute
|
||||
};
|
||||
|
||||
#if CH_CFG_USE_EVENTS_TIMEOUT || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_events_003 Events timeout
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* In this test the following APIs are let to timeout twice: immediatly and
|
||||
* after 10ms:
|
||||
* In this test the following APIs are indipently tested by starting threads
|
||||
* that broadcast events after fixed delays:
|
||||
* - @p chEvtWaitOneTimeout()
|
||||
* - @p chEvtWaitAnyTimeout()
|
||||
* - @p chEvtWaitAllTimeout()
|
||||
* .
|
||||
* After each test phase the test verifies that there are no stuck event flags.
|
||||
*/
|
||||
|
||||
static void evt3_setup(void) {
|
||||
|
||||
chEvtGetAndClearEvents(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void evt3_execute(void) {
|
||||
eventmask_t m;
|
||||
|
||||
/*
|
||||
* Tests various timeout situations.
|
||||
*/
|
||||
m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(1, m == 0, "spurious event");
|
||||
m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(2, m == 0, "spurious event");
|
||||
m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(3, m == 0, "spurious event");
|
||||
m = chEvtWaitOneTimeout(ALL_EVENTS, 10);
|
||||
test_assert(4, m == 0, "spurious event");
|
||||
m = chEvtWaitAnyTimeout(ALL_EVENTS, 10);
|
||||
test_assert(5, m == 0, "spurious event");
|
||||
m = chEvtWaitAllTimeout(ALL_EVENTS, 10);
|
||||
test_assert(6, m == 0, "spurious event");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testevt3 = {
|
||||
"Events, timeouts",
|
||||
evt3_setup,
|
||||
NULL,
|
||||
evt3_execute
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_EVENTS_TIMEOUT */
|
||||
|
||||
#endif /* CH_CFG_USE_EVENTS */
|
||||
|
||||
/**
|
||||
* @brief Test sequence for events.
|
||||
*/
|
||||
ROMCONST struct testcase * ROMCONST patternevt[] = {
|
||||
#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
|
||||
&testevt1,
|
||||
&testevt2,
|
||||
#if CH_CFG_USE_EVENTS_TIMEOUT || defined(__DOXYGEN__)
|
||||
&testevt3,
|
||||
#endif
|
||||
#endif
|
||||
NULL
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _TESTEVT_H_
|
||||
#define _TESTEVT_H_
|
||||
|
||||
extern ROMCONST struct testcase * ROMCONST patternevt[];
|
||||
|
||||
#endif /* _TESTEVT_H_ */
|
|
@ -1,159 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "test.h"
|
||||
|
||||
/**
|
||||
* @page test_heap Memory Heap test
|
||||
*
|
||||
* File: @ref testheap.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the @ref heaps subsystem.
|
||||
*
|
||||
* <h2>Objective</h2>
|
||||
* Objective of the test module is to cover 100% of the @ref heaps subsystem.
|
||||
*
|
||||
* <h2>Preconditions</h2>
|
||||
* The module requires the following kernel options:
|
||||
* - @p CH_CFG_USE_HEAP
|
||||
* .
|
||||
* In case some of the required options are not enabled then some or all tests
|
||||
* may be skipped.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_heap_001
|
||||
* .
|
||||
* @file testheap.c
|
||||
* @brief Heap test source file
|
||||
* @file testheap.h
|
||||
* @brief Heap header file
|
||||
*/
|
||||
|
||||
#if CH_CFG_USE_HEAP || defined(__DOXYGEN__)
|
||||
|
||||
#define SIZE 16
|
||||
|
||||
static memory_heap_t test_heap;
|
||||
|
||||
/**
|
||||
* @page test_heap_001 Allocation and fragmentation test
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Series of allocations/deallocations are performed in carefully designed
|
||||
* sequences in order to stimulate all the possible code paths inside the
|
||||
* allocator.<br>
|
||||
* The test expects to find the heap back to the initial status after each
|
||||
* sequence.
|
||||
*/
|
||||
|
||||
static void heap1_setup(void) {
|
||||
|
||||
chHeapObjectInit(&test_heap, test.buffer, sizeof(union test_buffers));
|
||||
}
|
||||
|
||||
static void heap1_execute(void) {
|
||||
void *p1, *p2, *p3;
|
||||
size_t n, sz;
|
||||
|
||||
/* Unrelated, for coverage only.*/
|
||||
(void)chCoreGetStatusX();
|
||||
|
||||
/*
|
||||
* Test on the default heap in order to cover the core allocator at
|
||||
* least one time.
|
||||
*/
|
||||
(void)chHeapStatus(NULL, &sz, NULL);
|
||||
p1 = chHeapAlloc(NULL, SIZE);
|
||||
test_assert(1, p1 != NULL, "allocation failed");
|
||||
chHeapFree(p1);
|
||||
p1 = chHeapAlloc(NULL, (size_t)-256);
|
||||
test_assert(2, p1 == NULL, "allocation not failed");
|
||||
|
||||
/* Initial local heap state.*/
|
||||
(void)chHeapStatus(&test_heap, &sz, NULL);
|
||||
|
||||
/* Same order.*/
|
||||
p1 = chHeapAlloc(&test_heap, SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, SIZE);
|
||||
p3 = chHeapAlloc(&test_heap, SIZE);
|
||||
chHeapFree(p1); /* Does not merge.*/
|
||||
chHeapFree(p2); /* Merges backward.*/
|
||||
chHeapFree(p3); /* Merges both sides.*/
|
||||
test_assert(3, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
|
||||
/* Reverse order.*/
|
||||
p1 = chHeapAlloc(&test_heap, SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, SIZE);
|
||||
p3 = chHeapAlloc(&test_heap, SIZE);
|
||||
chHeapFree(p3); /* Merges forward.*/
|
||||
chHeapFree(p2); /* Merges forward.*/
|
||||
chHeapFree(p1); /* Merges forward.*/
|
||||
test_assert(4, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
|
||||
/* Small fragments handling.*/
|
||||
p1 = chHeapAlloc(&test_heap, SIZE + 1);
|
||||
p2 = chHeapAlloc(&test_heap, SIZE);
|
||||
chHeapFree(p1);
|
||||
test_assert(5, chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
|
||||
p1 = chHeapAlloc(&test_heap, SIZE);
|
||||
/* Note, the first situation happens when the alignment size is smaller
|
||||
than the header size, the second in the other cases.*/
|
||||
test_assert(6, (chHeapStatus(&test_heap, &n, NULL) == 1) ||
|
||||
(chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
|
||||
chHeapFree(p2);
|
||||
chHeapFree(p1);
|
||||
test_assert(7, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
|
||||
/* Skip fragment handling.*/
|
||||
p1 = chHeapAlloc(&test_heap, SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, SIZE);
|
||||
chHeapFree(p1);
|
||||
test_assert(8, chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
|
||||
p1 = chHeapAlloc(&test_heap, SIZE * 2); /* Skips first fragment.*/
|
||||
chHeapFree(p1);
|
||||
chHeapFree(p2);
|
||||
test_assert(9, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
|
||||
/* Allocate all handling.*/
|
||||
(void)chHeapStatus(&test_heap, &n, NULL);
|
||||
p1 = chHeapAlloc(&test_heap, n);
|
||||
test_assert(10, chHeapStatus(&test_heap, &n, NULL) == 0, "not empty");
|
||||
chHeapFree(p1);
|
||||
|
||||
test_assert(11, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
test_assert(12, n == sz, "size changed");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testheap1 = {
|
||||
"Heap, allocation and fragmentation test",
|
||||
heap1_setup,
|
||||
NULL,
|
||||
heap1_execute
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_HEAP.*/
|
||||
|
||||
/**
|
||||
* @brief Test sequence for heap.
|
||||
*/
|
||||
ROMCONST struct testcase * ROMCONST patternheap[] = {
|
||||
#if CH_CFG_USE_HEAP || defined(__DOXYGEN__)
|
||||
&testheap1,
|
||||
#endif
|
||||
NULL
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _TESTHEAP_H_
|
||||
#define _TESTHEAP_H_
|
||||
|
||||
extern ROMCONST struct testcase * ROMCONST patternheap[];
|
||||
|
||||
#endif /* _TESTHEAP_H_ */
|
|
@ -1,239 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "test.h"
|
||||
|
||||
/**
|
||||
* @page test_mbox Mailboxes test
|
||||
*
|
||||
* File: @ref testmbox.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the @ref mailboxes subsystem.
|
||||
*
|
||||
* <h2>Objective</h2>
|
||||
* Objective of the test module is to cover 100% of the @ref mailboxes
|
||||
* subsystem code.<br>
|
||||
* Note that the @ref mailboxes subsystem depends on the @ref semaphores
|
||||
* subsystem that has to met its testing objectives as well.
|
||||
*
|
||||
* <h2>Preconditions</h2>
|
||||
* The module requires the following kernel options:
|
||||
* - @p CH_CFG_USE_MAILBOXES
|
||||
* .
|
||||
* In case some of the required options are not enabled then some or all tests
|
||||
* may be skipped.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_mbox_001
|
||||
* .
|
||||
* @file testmbox.c
|
||||
* @brief Mailboxes test source file
|
||||
* @file testmbox.h
|
||||
* @brief Mailboxes header file
|
||||
*/
|
||||
|
||||
#if CH_CFG_USE_MAILBOXES || defined(__DOXYGEN__)
|
||||
|
||||
#define ALLOWED_DELAY MS2ST(5)
|
||||
#define MB_SIZE 5
|
||||
|
||||
/*
|
||||
* Note, the static initializers are not really required because the
|
||||
* variables are explicitly initialized in each test case. It is done in order
|
||||
* to test the macros.
|
||||
*/
|
||||
static MAILBOX_DECL(mb1, test.wa.T0, MB_SIZE);
|
||||
|
||||
/**
|
||||
* @page test_mbox_001 Queuing and timeouts
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Messages are posted/fetched from a mailbox in carefully designed sequences
|
||||
* in order to stimulate all the possible code paths inside the mailbox.<br>
|
||||
* The test expects to find a consistent mailbox status after each operation.
|
||||
*/
|
||||
|
||||
static void mbox1_setup(void) {
|
||||
|
||||
chMBObjectInit(&mb1, (msg_t *)test.wa.T0, MB_SIZE);
|
||||
}
|
||||
|
||||
static void mbox1_execute(void) {
|
||||
msg_t msg1, msg2;
|
||||
unsigned i;
|
||||
|
||||
/*
|
||||
* Testing initial space.
|
||||
*/
|
||||
test_assert_lock(1, chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size");
|
||||
|
||||
/*
|
||||
* Testing enqueuing and backward circularity.
|
||||
*/
|
||||
for (i = 0; i < MB_SIZE - 1; i++) {
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(2, msg1 == MSG_OK, "wrong wake-up message");
|
||||
}
|
||||
msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE);
|
||||
test_assert(3, msg1 == MSG_OK, "wrong wake-up message");
|
||||
|
||||
/*
|
||||
* Testing post timeout.
|
||||
*/
|
||||
msg1 = chMBPost(&mb1, 'X', 1);
|
||||
test_assert(4, msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBPostI(&mb1, 'X');
|
||||
chSysUnlock();
|
||||
test_assert(5, msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
msg1 = chMBPostAhead(&mb1, 'X', 1);
|
||||
test_assert(6, msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBPostAheadI(&mb1, 'X');
|
||||
chSysUnlock();
|
||||
test_assert(7, msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
|
||||
/*
|
||||
* Testing final conditions.
|
||||
*/
|
||||
test_assert_lock(8, chMBGetFreeCountI(&mb1) == 0, "still empty");
|
||||
test_assert_lock(9, chMBGetUsedCountI(&mb1) == MB_SIZE, "not full");
|
||||
test_assert_lock(10, mb1.rdptr == mb1.wrptr, "pointers not aligned");
|
||||
|
||||
/*
|
||||
* Testing dequeuing.
|
||||
*/
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(11, msg1 == MSG_OK, "wrong wake-up message");
|
||||
test_emit_token(msg2);
|
||||
}
|
||||
test_assert_sequence(12, "ABCDE");
|
||||
|
||||
/*
|
||||
* Testing buffer circularity.
|
||||
*/
|
||||
msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE);
|
||||
test_assert(13, msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE);
|
||||
test_assert(14, msg1 == MSG_OK, "wrong wake-up message");
|
||||
test_assert(15, mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert(16, mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
|
||||
/*
|
||||
* Testing fetch timeout.
|
||||
*/
|
||||
msg1 = chMBFetch(&mb1, &msg2, 1);
|
||||
test_assert(17, msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
chSysLock();
|
||||
msg1 = chMBFetchI(&mb1, &msg2);
|
||||
chSysUnlock();
|
||||
test_assert(18, msg1 == MSG_TIMEOUT, "wrong wake-up message");
|
||||
|
||||
/*
|
||||
* Testing final conditions.
|
||||
*/
|
||||
test_assert_lock(19, chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(20, chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert_lock(21, mb1.rdptr == mb1.wrptr, "pointers not aligned");
|
||||
|
||||
/*
|
||||
* Testing I-Class.
|
||||
*/
|
||||
chSysLock();
|
||||
msg1 = chMBPostI(&mb1, 'A');
|
||||
test_assert(22, msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBPostI(&mb1, 'B');
|
||||
test_assert(23, msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBPostI(&mb1, 'C');
|
||||
test_assert(24, msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBPostI(&mb1, 'D');
|
||||
test_assert(25, msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBPostI(&mb1, 'E');
|
||||
chSysUnlock();
|
||||
test_assert(26, msg1 == MSG_OK, "wrong wake-up message");
|
||||
test_assert(27, mb1.rdptr == mb1.wrptr, "pointers not aligned");
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
chSysLock();
|
||||
msg1 = chMBFetchI(&mb1, &msg2);
|
||||
chSysUnlock();
|
||||
test_assert(28, msg1 == MSG_OK, "wrong wake-up message");
|
||||
test_emit_token(msg2);
|
||||
}
|
||||
test_assert_sequence(29, "ABCDE");
|
||||
test_assert_lock(30, chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(31, chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert(32, mb1.rdptr == mb1.wrptr, "pointers not aligned");
|
||||
|
||||
chSysLock();
|
||||
msg1 = chMBPostAheadI(&mb1, 'E');
|
||||
test_assert(33, msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBPostAheadI(&mb1, 'D');
|
||||
test_assert(34, msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBPostAheadI(&mb1, 'C');
|
||||
test_assert(35, msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBPostAheadI(&mb1, 'B');
|
||||
test_assert(36, msg1 == MSG_OK, "wrong wake-up message");
|
||||
msg1 = chMBPostAheadI(&mb1, 'A');
|
||||
chSysUnlock();
|
||||
test_assert(37, msg1 == MSG_OK, "wrong wake-up message");
|
||||
test_assert(38, mb1.rdptr == mb1.wrptr, "pointers not aligned");
|
||||
for (i = 0; i < MB_SIZE; i++) {
|
||||
chSysLock();
|
||||
msg1 = chMBFetchI(&mb1, &msg2);
|
||||
chSysUnlock();
|
||||
test_assert(39, msg1 == MSG_OK, "wrong wake-up message");
|
||||
test_emit_token(msg2);
|
||||
}
|
||||
test_assert_sequence(40, "ABCDE");
|
||||
test_assert_lock(41, chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(42, chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert(43, mb1.rdptr == mb1.wrptr, "pointers not aligned");
|
||||
|
||||
/*
|
||||
* Testing reset.
|
||||
*/
|
||||
chMBReset(&mb1);
|
||||
|
||||
/*
|
||||
* Re-testing final conditions.
|
||||
*/
|
||||
test_assert_lock(44, chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty");
|
||||
test_assert_lock(45, chMBGetUsedCountI(&mb1) == 0, "still full");
|
||||
test_assert_lock(46, mb1.buffer == mb1.wrptr, "write pointer not aligned to base");
|
||||
test_assert_lock(47, mb1.buffer == mb1.rdptr, "read pointer not aligned to base");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testmbox1 = {
|
||||
"Mailboxes, queuing and timeouts",
|
||||
mbox1_setup,
|
||||
NULL,
|
||||
mbox1_execute
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_MAILBOXES */
|
||||
|
||||
/**
|
||||
* @brief Test sequence for mailboxes.
|
||||
*/
|
||||
ROMCONST struct testcase * ROMCONST patternmbox[] = {
|
||||
#if CH_CFG_USE_MAILBOXES || defined(__DOXYGEN__)
|
||||
&testmbox1,
|
||||
#endif
|
||||
NULL
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _TESTMBOX_H_
|
||||
#define _TESTMBOX_H_
|
||||
|
||||
extern ROMCONST struct testcase * ROMCONST patternmbox[];
|
||||
|
||||
#endif /* _TESTMBOX_H_ */
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "test.h"
|
||||
|
||||
/**
|
||||
* @page test_msg Messages test
|
||||
*
|
||||
* File: @ref testmsg.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the @ref messages subsystem.
|
||||
*
|
||||
* <h2>Objective</h2>
|
||||
* Objective of the test module is to cover 100% of the @ref messages
|
||||
* subsystem code.
|
||||
*
|
||||
* <h2>Preconditions</h2>
|
||||
* The module requires the following kernel options:
|
||||
* - @p CH_CFG_USE_MESSAGES
|
||||
* .
|
||||
* In case some of the required options are not enabled then some or all tests
|
||||
* may be skipped.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_msg_001
|
||||
* .
|
||||
* @file testmsg.c
|
||||
* @brief Messages test source file
|
||||
* @file testmsg.h
|
||||
* @brief Messages header file
|
||||
*/
|
||||
|
||||
#if CH_CFG_USE_MESSAGES || defined(__DOXYGEN__)
|
||||
|
||||
/**
|
||||
* @page test_msg_001 Messages Server loop
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* A 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.
|
||||
*/
|
||||
|
||||
static THD_FUNCTION(thread, p) {
|
||||
|
||||
chMsgSend(p, 'A');
|
||||
chMsgSend(p, 'B');
|
||||
chMsgSend(p, 'C');
|
||||
}
|
||||
|
||||
static void msg1_execute(void) {
|
||||
thread_t *tp;
|
||||
msg_t msg;
|
||||
|
||||
/*
|
||||
* Testing the whole messages loop.
|
||||
*/
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() + 1,
|
||||
thread, chThdGetSelfX());
|
||||
tp = chMsgWait();
|
||||
msg = chMsgGet(tp);
|
||||
chMsgRelease(tp, msg);
|
||||
test_emit_token(msg);
|
||||
tp = chMsgWait();
|
||||
msg = chMsgGet(tp);
|
||||
chMsgRelease(tp, msg);
|
||||
test_emit_token(msg);
|
||||
tp = chMsgWait();
|
||||
msg = chMsgGet(tp);
|
||||
chMsgRelease(tp, msg);
|
||||
test_emit_token(msg);
|
||||
test_assert_sequence(1, "ABC");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testmsg1 = {
|
||||
"Messages, loop",
|
||||
NULL,
|
||||
NULL,
|
||||
msg1_execute
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_MESSAGES */
|
||||
|
||||
/**
|
||||
* @brief Test sequence for messages.
|
||||
*/
|
||||
ROMCONST struct testcase * ROMCONST patternmsg[] = {
|
||||
#if CH_CFG_USE_MESSAGES || defined(__DOXYGEN__)
|
||||
&testmsg1,
|
||||
#endif
|
||||
NULL
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _TESTMSG_H_
|
||||
#define _TESTMSG_H_
|
||||
|
||||
extern ROMCONST struct testcase * ROMCONST patternmsg[];
|
||||
|
||||
#endif /* _TESTMSG_H_ */
|
|
@ -1,623 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "test.h"
|
||||
|
||||
/**
|
||||
* @page test_mtx Mutexes test
|
||||
*
|
||||
* File: @ref testmtx.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the @ref mutexes and
|
||||
* @ref condvars subsystems.<br>
|
||||
* Tests on those subsystems are particularly critical because the system-wide
|
||||
* implications of the Priority Inheritance mechanism.
|
||||
*
|
||||
* <h2>Objective</h2>
|
||||
* Objective of the test module is to cover 100% of the subsystems code.
|
||||
*
|
||||
* <h2>Preconditions</h2>
|
||||
* The module requires the following kernel options:
|
||||
* - @p CH_CFG_USE_MUTEXES
|
||||
* - @p CH_CFG_USE_CONDVARS
|
||||
* - @p CH_DBG_THREADS_PROFILING
|
||||
* .
|
||||
* In case some of the required options are not enabled then some or all tests
|
||||
* may be skipped.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_mtx_001
|
||||
* - @subpage test_mtx_002
|
||||
* - @subpage test_mtx_003
|
||||
* - @subpage test_mtx_004
|
||||
* - @subpage test_mtx_005
|
||||
* - @subpage test_mtx_006
|
||||
* - @subpage test_mtx_007
|
||||
* - @subpage test_mtx_008
|
||||
* .
|
||||
* @file testmtx.c
|
||||
* @brief Mutexes and CondVars test source file
|
||||
* @file testmtx.h
|
||||
* @brief Mutexes and CondVars test header file
|
||||
*/
|
||||
|
||||
#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
|
||||
|
||||
#define ALLOWED_DELAY 5
|
||||
|
||||
/*
|
||||
* Note, the static initializers are not really required because the
|
||||
* variables are explicitly initialized in each test case. It is done in order
|
||||
* to test the macros.
|
||||
*/
|
||||
static MUTEX_DECL(m1);
|
||||
static MUTEX_DECL(m2);
|
||||
#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__)
|
||||
static CONDVAR_DECL(c1);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @page test_mtx_001 Priority enqueuing test
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads, with increasing priority, are enqueued on a locked mutex then
|
||||
* the mutex is unlocked.<br>
|
||||
* The test expects the threads to perform their operations in increasing
|
||||
* priority order regardless of the initial order.
|
||||
*/
|
||||
|
||||
static void mtx1_setup(void) {
|
||||
|
||||
chMtxObjectInit(&m1);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread1, p) {
|
||||
|
||||
chMtxLock(&m1);
|
||||
test_emit_token(*(char *)p);
|
||||
chMtxUnlock(&m1);
|
||||
}
|
||||
|
||||
static void mtx1_execute(void) {
|
||||
|
||||
tprio_t prio = chThdGetPriorityX(); /* Because priority inheritance.*/
|
||||
chMtxLock(&m1);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread1, "E");
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread1, "D");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread1, "C");
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread1, "B");
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread1, "A");
|
||||
chMtxUnlock(&m1);
|
||||
test_wait_threads();
|
||||
test_assert(1, prio == chThdGetPriorityX(), "wrong priority level");
|
||||
test_assert_sequence(2, "ABCDE");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testmtx1 = {
|
||||
"Mutexes, priority enqueuing test",
|
||||
mtx1_setup,
|
||||
NULL,
|
||||
mtx1_execute
|
||||
};
|
||||
|
||||
#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_mtx_002 Priority inheritance, simple case
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Three threads are involved in the classic priority inversion scenario, a
|
||||
* medium priority thread tries to starve an high priority thread by
|
||||
* blocking a low priority thread into a mutex lock zone.<br>
|
||||
* The test expects the threads to reach their goal in increasing priority
|
||||
* order by rearranging their priorities in order to avoid the priority
|
||||
* inversion trap.
|
||||
*
|
||||
* <h2>Scenario</h2>
|
||||
* This weird looking diagram should explain what happens in the test case:
|
||||
* @code
|
||||
* Time ----> 0 10 20 30 40 50 60 70 80 90 100
|
||||
* 0 ......AL++++++++++............2+++++++++++AU0---------------++++++G...
|
||||
* 1 ..................++++++++++++------------------++++++++++++G.........
|
||||
* 2 .............................AL..........++++++AUG...................
|
||||
* ^ ^
|
||||
* Legend:
|
||||
* 0..2 - Priority levels
|
||||
* +++ - Running
|
||||
* --- - Ready
|
||||
* ... - Waiting or Terminated
|
||||
* xL - Lock operation on mutex 'x'
|
||||
* xUn - Unlock operation on mutex 'x' with priority returning to level 'n'
|
||||
* G - Goal
|
||||
* ^ - Priority transition (boost or return).
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
static void mtx2_setup(void) {
|
||||
|
||||
chMtxObjectInit(&m1);
|
||||
}
|
||||
|
||||
/* Low priority thread */
|
||||
static THD_FUNCTION(thread2L, p) {
|
||||
|
||||
(void)p;
|
||||
chMtxLock(&m1);
|
||||
test_cpu_pulse(40);
|
||||
chMtxUnlock(&m1);
|
||||
test_cpu_pulse(10);
|
||||
test_emit_token('C');
|
||||
}
|
||||
|
||||
/* Medium priority thread */
|
||||
static THD_FUNCTION(thread2M, p) {
|
||||
|
||||
(void)p;
|
||||
chThdSleepMilliseconds(20);
|
||||
test_cpu_pulse(40);
|
||||
test_emit_token('B');
|
||||
}
|
||||
|
||||
/* High priority thread */
|
||||
static THD_FUNCTION(thread2H, p) {
|
||||
|
||||
(void)p;
|
||||
chThdSleepMilliseconds(40);
|
||||
chMtxLock(&m1);
|
||||
test_cpu_pulse(10);
|
||||
chMtxUnlock(&m1);
|
||||
test_emit_token('A');
|
||||
}
|
||||
|
||||
static void mtx2_execute(void) {
|
||||
systime_t time;
|
||||
|
||||
test_wait_tick();
|
||||
time = chVTGetSystemTime();
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread2H, 0);
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-2, thread2M, 0);
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread2L, 0);
|
||||
test_wait_threads();
|
||||
test_assert_sequence(1, "ABC");
|
||||
test_assert_time_window(2, time + MS2ST(100), time + MS2ST(100) + ALLOWED_DELAY);
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testmtx2 = {
|
||||
"Mutexes, priority inheritance, simple case",
|
||||
mtx2_setup,
|
||||
NULL,
|
||||
mtx2_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_mtx_003 Priority inheritance, complex case
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads are involved in the complex priority inversion scenario,
|
||||
* please refer to the diagram below for the complete scenario.<br>
|
||||
* The test expects the threads to perform their operations in increasing
|
||||
* priority order by rearranging their priorities in order to avoid the
|
||||
* priority inversion trap.
|
||||
*
|
||||
* <h2>Scenario</h2>
|
||||
* This weird looking diagram should explain what happens in the test case:
|
||||
* @code
|
||||
* Time ----> 0 10 20 30 40 50 60 70 80 90 100 110
|
||||
* 0 ......BL++++------------2+++++------4+++++BU0---------------------------G.....
|
||||
* 1 ............AL++++2+++++BL----------4-----++++++BU4+++AU1---------------G.....
|
||||
* 2 ..................AL----------------------------------------------++++++AUG...
|
||||
* 3 ..............................+++++++-----------------------++++++G...........
|
||||
* 4 ....................................AL................++++++AUG...............
|
||||
* ^ ^ ^ ^ ^ ^
|
||||
* Legend:
|
||||
* 0..4 - Priority levels
|
||||
* +++ - Running
|
||||
* --- - Ready
|
||||
* ... - Waiting or Terminated
|
||||
* xL - Lock operation on mutex 'x'
|
||||
* xUn - Unlock operation on mutex 'x' with priority returning to level 'n'
|
||||
* ^ - Priority transition (boost or return).
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
static void mtx3_setup(void) {
|
||||
|
||||
chMtxObjectInit(&m1); /* Mutex B.*/
|
||||
chMtxObjectInit(&m2); /* Mutex A.*/
|
||||
}
|
||||
|
||||
/* Lowest priority thread */
|
||||
static THD_FUNCTION(thread3LL, p) {
|
||||
|
||||
(void)p;
|
||||
chMtxLock(&m1);
|
||||
test_cpu_pulse(30);
|
||||
chMtxUnlock(&m1);
|
||||
test_emit_token('E');
|
||||
}
|
||||
|
||||
/* Low priority thread */
|
||||
static THD_FUNCTION(thread3L, p) {
|
||||
|
||||
(void)p;
|
||||
chThdSleepMilliseconds(10);
|
||||
chMtxLock(&m2);
|
||||
test_cpu_pulse(20);
|
||||
chMtxLock(&m1);
|
||||
test_cpu_pulse(10);
|
||||
chMtxUnlock(&m1);
|
||||
test_cpu_pulse(10);
|
||||
chMtxUnlock(&m2);
|
||||
test_emit_token('D');
|
||||
}
|
||||
|
||||
/* Medium priority thread */
|
||||
static THD_FUNCTION(thread3M, p) {
|
||||
|
||||
(void)p;
|
||||
chThdSleepMilliseconds(20);
|
||||
chMtxLock(&m2);
|
||||
test_cpu_pulse(10);
|
||||
chMtxUnlock(&m2);
|
||||
test_emit_token('C');
|
||||
}
|
||||
|
||||
/* High priority thread */
|
||||
static THD_FUNCTION(thread3H, p) {
|
||||
|
||||
(void)p;
|
||||
chThdSleepMilliseconds(40);
|
||||
test_cpu_pulse(20);
|
||||
test_emit_token('B');
|
||||
}
|
||||
|
||||
/* Highest priority thread */
|
||||
static THD_FUNCTION(thread3HH, p) {
|
||||
|
||||
(void)p;
|
||||
chThdSleepMilliseconds(50);
|
||||
chMtxLock(&m2);
|
||||
test_cpu_pulse(10);
|
||||
chMtxUnlock(&m2);
|
||||
test_emit_token('A');
|
||||
}
|
||||
|
||||
static void mtx3_execute(void) {
|
||||
systime_t time;
|
||||
|
||||
test_wait_tick();
|
||||
time = chVTGetSystemTime();
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread3LL, 0);
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread3L, 0);
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread3M, 0);
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread3H, 0);
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread3HH, 0);
|
||||
test_wait_threads();
|
||||
test_assert_sequence(1, "ABCDE");
|
||||
test_assert_time_window(2, time + MS2ST(110), time + MS2ST(110) + ALLOWED_DELAY);
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testmtx3 = {
|
||||
"Mutexes, priority inheritance, complex case",
|
||||
mtx3_setup,
|
||||
NULL,
|
||||
mtx3_execute
|
||||
};
|
||||
#endif /* CH_DBG_THREADS_PROFILING */
|
||||
|
||||
/**
|
||||
* @page test_mtx_004 Priority return verification
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Two threads are spawned that try to lock the mutexes locked by the tester
|
||||
* thread with precise timing.<br>
|
||||
* The test expects that the priority changes caused by the priority
|
||||
* inheritance algorithm happen at the right moment and with the right values.
|
||||
*/
|
||||
|
||||
static void mtx4_setup(void) {
|
||||
|
||||
chMtxObjectInit(&m1);
|
||||
chMtxObjectInit(&m2);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread4a, p) {
|
||||
|
||||
(void)p;
|
||||
chThdSleepMilliseconds(50);
|
||||
chMtxLock(&m2);
|
||||
chMtxUnlock(&m2);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread4b, p) {
|
||||
|
||||
(void)p;
|
||||
chThdSleepMilliseconds(150);
|
||||
chMtxLock(&m1);
|
||||
chMtxUnlock(&m1);
|
||||
}
|
||||
|
||||
static void mtx4_execute(void) {
|
||||
tprio_t p, p1, p2;
|
||||
|
||||
p = chThdGetPriorityX();
|
||||
p1 = p + 1;
|
||||
p2 = p + 2;
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, p1, thread4a, "B");
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, p2, thread4b, "A");
|
||||
chMtxLock(&m2);
|
||||
test_assert(1, chThdGetPriorityX() == p, "wrong priority level");
|
||||
chThdSleepMilliseconds(100);
|
||||
test_assert(2, chThdGetPriorityX() == p1, "wrong priority level");
|
||||
chMtxLock(&m1);
|
||||
test_assert(3, chThdGetPriorityX() == p1, "wrong priority level");
|
||||
chThdSleepMilliseconds(100);
|
||||
test_assert(4, chThdGetPriorityX() == p2, "wrong priority level");
|
||||
chMtxUnlock(&m1);
|
||||
test_assert(5, chThdGetPriorityX() == p1, "wrong priority level");
|
||||
chThdSleepMilliseconds(100);
|
||||
test_assert(6, chThdGetPriorityX() == p1, "wrong priority level");
|
||||
chMtxUnlockAll();
|
||||
test_assert(7, chThdGetPriorityX() == p, "wrong priority level");
|
||||
test_wait_threads();
|
||||
|
||||
/* Test repeated in order to cover chMtxUnlockS().*/
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, p1, thread4a, "D");
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, p2, thread4b, "C");
|
||||
chMtxLock(&m2);
|
||||
test_assert(8, chThdGetPriorityX() == p, "wrong priority level");
|
||||
chThdSleepMilliseconds(100);
|
||||
test_assert(9, chThdGetPriorityX() == p1, "wrong priority level");
|
||||
chMtxLock(&m1);
|
||||
test_assert(10, chThdGetPriorityX() == p1, "wrong priority level");
|
||||
chThdSleepMilliseconds(100);
|
||||
test_assert(11, chThdGetPriorityX() == p2, "wrong priority level");
|
||||
chSysLock();
|
||||
chMtxUnlockS(&m1);
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
test_assert(12, chThdGetPriorityX() == p1, "wrong priority level");
|
||||
chThdSleepMilliseconds(100);
|
||||
test_assert(13, chThdGetPriorityX() == p1, "wrong priority level");
|
||||
chMtxUnlockAll();
|
||||
test_assert(14, chThdGetPriorityX() == p, "wrong priority level");
|
||||
test_wait_threads();
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testmtx4 = {
|
||||
"Mutexes, priority return",
|
||||
mtx4_setup,
|
||||
NULL,
|
||||
mtx4_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_mtx_005 Mutex status
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Various tests on the mutex structure status after performing some lock and
|
||||
* unlock operations.<br>
|
||||
* The test expects that the internal mutex status is consistent after each
|
||||
* operation.
|
||||
*/
|
||||
|
||||
static void mtx5_setup(void) {
|
||||
|
||||
chMtxObjectInit(&m1);
|
||||
}
|
||||
|
||||
static void mtx5_execute(void) {
|
||||
|
||||
#if !CH_CFG_USE_MUTEXES_RECURSIVE
|
||||
bool b;
|
||||
tprio_t prio = chThdGetPriorityX();
|
||||
|
||||
b = chMtxTryLock(&m1);
|
||||
test_assert(1, b, "already locked");
|
||||
|
||||
b = chMtxTryLock(&m1);
|
||||
test_assert(2, !b, "not locked");
|
||||
|
||||
chSysLock();
|
||||
chMtxUnlockS(&m1);
|
||||
chSysUnlock();
|
||||
|
||||
test_assert(3, queue_isempty(&m1.queue), "queue not empty");
|
||||
test_assert(4, m1.owner == NULL, "still owned");
|
||||
test_assert(5, chThdGetPriorityX() == prio, "wrong priority level");
|
||||
#endif /* !CH_CFG_USE_MUTEXES_RECURSIVE */
|
||||
|
||||
chMtxLock(&m1);
|
||||
chMtxUnlockAll();
|
||||
test_assert(6, queue_isempty(&m1.queue), "queue not empty");
|
||||
test_assert(7, m1.owner == NULL, "still owned");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testmtx5 = {
|
||||
"Mutexes, status",
|
||||
mtx5_setup,
|
||||
NULL,
|
||||
mtx5_execute
|
||||
};
|
||||
|
||||
#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_mtx_006 Condition Variable signal test
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads take a mutex and then enter a conditional variable queue, the
|
||||
* tester thread then proceeds to signal the conditional variable five times
|
||||
* atomically.<br>
|
||||
* The test expects the threads to reach their goal in increasing priority
|
||||
* order regardless of the initial order.
|
||||
*/
|
||||
|
||||
static void mtx6_setup(void) {
|
||||
|
||||
chCondObjectInit(&c1);
|
||||
chMtxObjectInit(&m1);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread10, p) {
|
||||
|
||||
chMtxLock(&m1);
|
||||
chCondWait(&c1);
|
||||
test_emit_token(*(char *)p);
|
||||
chMtxUnlock(&m1);
|
||||
}
|
||||
|
||||
static void mtx6_execute(void) {
|
||||
|
||||
tprio_t prio = chThdGetPriorityX();
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread10, "E");
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread10, "D");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread10, "C");
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread10, "B");
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread10, "A");
|
||||
chSysLock();
|
||||
chCondSignalI(&c1);
|
||||
chCondSignalI(&c1);
|
||||
chCondSignalI(&c1);
|
||||
chCondSignalI(&c1);
|
||||
chCondSignalI(&c1);
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
test_wait_threads();
|
||||
test_assert_sequence(1, "ABCDE");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testmtx6 = {
|
||||
"CondVar, signal test",
|
||||
mtx6_setup,
|
||||
NULL,
|
||||
mtx6_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_mtx_007 Condition Variable broadcast test
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads take a mutex and then enter a conditional variable queue, the
|
||||
* tester thread then proceeds to broadcast the conditional variable.<br>
|
||||
* The test expects the threads to reach their goal in increasing priority
|
||||
* order regardless of the initial order.
|
||||
*/
|
||||
|
||||
static void mtx7_setup(void) {
|
||||
|
||||
chCondObjectInit(&c1);
|
||||
chMtxObjectInit(&m1);
|
||||
}
|
||||
|
||||
static void mtx7_execute(void) {
|
||||
|
||||
tprio_t prio = chThdGetPriorityX();
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread10, "E");
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread10, "D");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread10, "C");
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, prio+4, thread10, "B");
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread10, "A");
|
||||
chCondBroadcast(&c1);
|
||||
test_wait_threads();
|
||||
test_assert_sequence(1, "ABCDE");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testmtx7 = {
|
||||
"CondVar, broadcast test",
|
||||
mtx7_setup,
|
||||
NULL,
|
||||
mtx7_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_mtx_008 Condition Variable priority boost test
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This test case verifies the priority boost of a thread waiting on a
|
||||
* conditional variable queue. It tests this very specific situation in order
|
||||
* to complete the code coverage.
|
||||
*/
|
||||
|
||||
static void mtx8_setup(void) {
|
||||
|
||||
chCondObjectInit(&c1);
|
||||
chMtxObjectInit(&m1);
|
||||
chMtxObjectInit(&m2);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread11, p) {
|
||||
|
||||
chMtxLock(&m2);
|
||||
chMtxLock(&m1);
|
||||
#if CH_CFG_USE_CONDVARS_TIMEOUT || defined(__DOXYGEN__)
|
||||
chCondWaitTimeout(&c1, TIME_INFINITE);
|
||||
#else
|
||||
chCondWait(&c1);
|
||||
#endif
|
||||
test_emit_token(*(char *)p);
|
||||
chMtxUnlock(&m1);
|
||||
chMtxUnlock(&m2);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread12, p) {
|
||||
|
||||
chMtxLock(&m2);
|
||||
test_emit_token(*(char *)p);
|
||||
chMtxUnlock(&m2);
|
||||
}
|
||||
|
||||
static void mtx8_execute(void) {
|
||||
|
||||
tprio_t prio = chThdGetPriorityX();
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, prio+1, thread11, "A");
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, prio+2, thread10, "C");
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, prio+3, thread12, "B");
|
||||
chCondSignal(&c1);
|
||||
chCondSignal(&c1);
|
||||
test_wait_threads();
|
||||
test_assert_sequence(1, "ABC");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testmtx8 = {
|
||||
"CondVar, boost test",
|
||||
mtx8_setup,
|
||||
NULL,
|
||||
mtx8_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_CONDVARS */
|
||||
#endif /* CH_CFG_USE_MUTEXES */
|
||||
|
||||
/**
|
||||
* @brief Test sequence for mutexes.
|
||||
*/
|
||||
ROMCONST struct testcase * ROMCONST patternmtx[] = {
|
||||
#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
|
||||
&testmtx1,
|
||||
#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__)
|
||||
&testmtx2,
|
||||
&testmtx3,
|
||||
#endif
|
||||
&testmtx4,
|
||||
&testmtx5,
|
||||
#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__)
|
||||
&testmtx6,
|
||||
&testmtx7,
|
||||
&testmtx8,
|
||||
#endif
|
||||
#endif
|
||||
NULL
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _TESTMTX_H_
|
||||
#define _TESTMTX_H_
|
||||
|
||||
extern ROMCONST struct testcase * ROMCONST patternmtx[];
|
||||
|
||||
#endif /* _TESTMTX_H_ */
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "test.h"
|
||||
|
||||
/**
|
||||
* @page test_pools Memory Pools test
|
||||
*
|
||||
* File: @ref testpools.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the @ref pools subsystem.
|
||||
*
|
||||
* <h2>Objective</h2>
|
||||
* Objective of the test module is to cover 100% of the @ref pools code.
|
||||
*
|
||||
* <h2>Preconditions</h2>
|
||||
* The module requires the following kernel options:
|
||||
* - @p CH_CFG_USE_MEMPOOLS
|
||||
* .
|
||||
* In case some of the required options are not enabled then some or all tests
|
||||
* may be skipped.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_pools_001
|
||||
* .
|
||||
* @file testpools.c
|
||||
* @brief Memory Pools test source file
|
||||
* @file testpools.h
|
||||
* @brief Memory Pools test header file
|
||||
*/
|
||||
|
||||
#if CH_CFG_USE_MEMPOOLS || defined(__DOXYGEN__)
|
||||
|
||||
static MEMORYPOOL_DECL(mp1, THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), NULL);
|
||||
|
||||
/**
|
||||
* @page test_pools_001 Allocation and enqueuing test
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five memory blocks are added to a memory pool then removed.<br>
|
||||
* The test expects to find the pool queue in the proper status after each
|
||||
* operation.
|
||||
*/
|
||||
|
||||
static void *null_provider(size_t size, unsigned align) {
|
||||
|
||||
(void)size;
|
||||
(void)align;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void pools1_setup(void) {
|
||||
|
||||
chPoolObjectInit(&mp1, THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), NULL);
|
||||
}
|
||||
|
||||
static void pools1_execute(void) {
|
||||
int i;
|
||||
|
||||
/* Adding the WAs to the pool.*/
|
||||
chPoolLoadArray(&mp1, wa[0], MAX_THREADS);
|
||||
|
||||
/* Emptying the pool.*/
|
||||
for (i = 0; i < MAX_THREADS; i++)
|
||||
test_assert(1, chPoolAlloc(&mp1) != NULL, "list empty");
|
||||
|
||||
/* Now must be empty.*/
|
||||
test_assert(2, chPoolAlloc(&mp1) == NULL, "list not empty");
|
||||
|
||||
/* Adding the WAs to the pool, one by one this time.*/
|
||||
for (i = 0; i < MAX_THREADS; i++)
|
||||
chPoolFree(&mp1, wa[i]);
|
||||
|
||||
/* Emptying the pool again.*/
|
||||
for (i = 0; i < MAX_THREADS; i++)
|
||||
test_assert(3, chPoolAlloc(&mp1) != NULL, "list empty");
|
||||
|
||||
/* Now must be empty again.*/
|
||||
test_assert(4, chPoolAlloc(&mp1) == NULL, "list not empty");
|
||||
|
||||
/* Covering the case where a provider is unable to return more memory.*/
|
||||
chPoolObjectInit(&mp1, 16, null_provider);
|
||||
test_assert(5, chPoolAlloc(&mp1) == NULL, "provider returned memory");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testpools1 = {
|
||||
"Memory Pools, queue/dequeue",
|
||||
pools1_setup,
|
||||
NULL,
|
||||
pools1_execute
|
||||
};
|
||||
|
||||
#endif /* CH_CFG_USE_MEMPOOLS */
|
||||
|
||||
/*
|
||||
* @brief Test sequence for pools.
|
||||
*/
|
||||
ROMCONST struct testcase * ROMCONST patternpools[] = {
|
||||
#if CH_CFG_USE_MEMPOOLS || defined(__DOXYGEN__)
|
||||
&testpools1,
|
||||
#endif
|
||||
NULL
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _TESTPOOLS_H_
|
||||
#define _TESTPOOLS_H_
|
||||
|
||||
extern ROMCONST struct testcase * ROMCONST patternpools[];
|
||||
|
||||
#endif /* _TESTPOOLS_H_ */
|
|
@ -1,242 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "test.h"
|
||||
|
||||
/**
|
||||
* @page test_queues I/O Queues test
|
||||
*
|
||||
* File: @ref testqueues.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the @ref io_queues subsystem.
|
||||
* The tests are performed by inserting and removing data from queues and by
|
||||
* checking both the queues status and the correct sequence of the extracted
|
||||
* data.
|
||||
*
|
||||
* <h2>Objective</h2>
|
||||
* Objective of the test module is to cover 100% of the @ref io_queues code.<br>
|
||||
* Note that the @ref io_queues subsystem depends on the @ref semaphores
|
||||
* subsystem that has to met its testing objectives as well.
|
||||
*
|
||||
* <h2>Preconditions</h2>
|
||||
* The module requires the following kernel options:
|
||||
* - @p CH_CFG_USE_QUEUES (and dependent options)
|
||||
* .
|
||||
* In case some of the required options are not enabled then some or all tests
|
||||
* may be skipped.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_queues_001
|
||||
* - @subpage test_queues_002
|
||||
* .
|
||||
* @file testqueues.c
|
||||
* @brief I/O Queues test source file
|
||||
* @file testqueues.h
|
||||
* @brief I/O Queues test header file
|
||||
*/
|
||||
|
||||
#if CH_CFG_USE_QUEUES || defined(__DOXYGEN__)
|
||||
|
||||
#define TEST_QUEUES_SIZE 4
|
||||
|
||||
static void notify(io_queue_t *qp) {
|
||||
(void)qp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note, the static initializers are not really required because the
|
||||
* variables are explicitly initialized in each test case. It is done in order
|
||||
* to test the macros.
|
||||
*/
|
||||
static INPUTQUEUE_DECL(iq, test.wa.T0, TEST_QUEUES_SIZE, notify, NULL);
|
||||
static OUTPUTQUEUE_DECL(oq, test.wa.T1, TEST_QUEUES_SIZE, notify, NULL);
|
||||
|
||||
/**
|
||||
* @page test_queues_001 Input Queues functionality and APIs
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This test case tests synchronous and asynchronous operations on an
|
||||
* @p InputQueue object including timeouts. The queue state must remain
|
||||
* consistent through the whole test.
|
||||
*/
|
||||
|
||||
static void queues1_setup(void) {
|
||||
|
||||
chIQObjectInit(&iq, wa[0], TEST_QUEUES_SIZE, notify, NULL);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread1, p) {
|
||||
|
||||
(void)p;
|
||||
chIQGetTimeout(&iq, MS2ST(200));
|
||||
}
|
||||
|
||||
static void queues1_execute(void) {
|
||||
unsigned i;
|
||||
size_t n;
|
||||
|
||||
/* Initial empty state */
|
||||
test_assert_lock(1, chIQIsEmptyI(&iq), "not empty");
|
||||
|
||||
/* Queue filling */
|
||||
chSysLock();
|
||||
for (i = 0; i < TEST_QUEUES_SIZE; i++)
|
||||
chIQPutI(&iq, 'A' + i);
|
||||
chSysUnlock();
|
||||
test_assert_lock(2, chIQIsFullI(&iq), "still has space");
|
||||
test_assert_lock(3, chIQPutI(&iq, 0) == Q_FULL, "failed to report Q_FULL");
|
||||
|
||||
/* Queue emptying */
|
||||
for (i = 0; i < TEST_QUEUES_SIZE; i++)
|
||||
test_emit_token(chIQGet(&iq));
|
||||
test_assert_lock(4, chIQIsEmptyI(&iq), "still full");
|
||||
test_assert_sequence(5, "ABCD");
|
||||
|
||||
/* Queue filling again */
|
||||
chSysLock();
|
||||
for (i = 0; i < TEST_QUEUES_SIZE; i++)
|
||||
chIQPutI(&iq, 'A' + i);
|
||||
chSysUnlock();
|
||||
|
||||
/* Reading the whole thing */
|
||||
n = chIQReadTimeout(&iq, wa[1], TEST_QUEUES_SIZE * 2, TIME_IMMEDIATE);
|
||||
test_assert(6, n == TEST_QUEUES_SIZE, "wrong returned size");
|
||||
test_assert_lock(7, chIQIsEmptyI(&iq), "still full");
|
||||
|
||||
/* Queue filling again */
|
||||
chSysLock();
|
||||
for (i = 0; i < TEST_QUEUES_SIZE; i++)
|
||||
chIQPutI(&iq, 'A' + i);
|
||||
chSysUnlock();
|
||||
|
||||
/* Partial reads */
|
||||
n = chIQReadTimeout(&iq, wa[1], TEST_QUEUES_SIZE / 2, TIME_IMMEDIATE);
|
||||
test_assert(8, n == TEST_QUEUES_SIZE / 2, "wrong returned size");
|
||||
n = chIQReadTimeout(&iq, wa[1], TEST_QUEUES_SIZE / 2, TIME_IMMEDIATE);
|
||||
test_assert(9, n == TEST_QUEUES_SIZE / 2, "wrong returned size");
|
||||
test_assert_lock(10, chIQIsEmptyI(&iq), "still full");
|
||||
|
||||
/* Testing reset */
|
||||
chSysLock();
|
||||
chIQPutI(&iq, 0);
|
||||
chIQResetI(&iq);
|
||||
chSysUnlock();
|
||||
test_assert_lock(11, chIQGetFullI(&iq) == 0, "still full");
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread1, NULL);
|
||||
test_assert_lock(12, chIQGetFullI(&iq) == 0, "not empty");
|
||||
test_wait_threads();
|
||||
|
||||
/* Timeout */
|
||||
test_assert(13, chIQGetTimeout(&iq, 10) == Q_TIMEOUT, "wrong timeout return");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testqueues1 = {
|
||||
"Queues, input queues",
|
||||
queues1_setup,
|
||||
NULL,
|
||||
queues1_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_queues_002 Output Queues functionality and APIs
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This test case tests synchronous and asynchronous operations on an
|
||||
* @p OutputQueue object including timeouts. The queue state must remain
|
||||
* consistent through the whole test.
|
||||
*/
|
||||
|
||||
static void queues2_setup(void) {
|
||||
|
||||
chOQObjectInit(&oq, wa[0], TEST_QUEUES_SIZE, notify, NULL);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread2, p) {
|
||||
|
||||
(void)p;
|
||||
chOQPutTimeout(&oq, 0, MS2ST(200));
|
||||
}
|
||||
|
||||
static void queues2_execute(void) {
|
||||
unsigned i;
|
||||
size_t n;
|
||||
|
||||
/* Initial empty state */
|
||||
test_assert_lock(1, chOQIsEmptyI(&oq), "not empty");
|
||||
|
||||
/* Queue filling */
|
||||
for (i = 0; i < TEST_QUEUES_SIZE; i++)
|
||||
chOQPut(&oq, 'A' + i);
|
||||
test_assert_lock(2, chOQIsFullI(&oq), "still has space");
|
||||
|
||||
/* Queue emptying */
|
||||
for (i = 0; i < TEST_QUEUES_SIZE; i++) {
|
||||
char c;
|
||||
|
||||
chSysLock();
|
||||
c = chOQGetI(&oq);
|
||||
chSysUnlock();
|
||||
test_emit_token(c);
|
||||
}
|
||||
test_assert_lock(3, chOQIsEmptyI(&oq), "still full");
|
||||
test_assert_sequence(4, "ABCD");
|
||||
test_assert_lock(5, chOQGetI(&oq) == Q_EMPTY, "failed to report Q_EMPTY");
|
||||
|
||||
/* Writing the whole thing */
|
||||
n = chOQWriteTimeout(&oq, wa[1], TEST_QUEUES_SIZE * 2, TIME_IMMEDIATE);
|
||||
test_assert(6, n == TEST_QUEUES_SIZE, "wrong returned size");
|
||||
test_assert_lock(7, chOQIsFullI(&oq), "not full");
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread2, NULL);
|
||||
test_assert_lock(8, chOQGetFullI(&oq) == TEST_QUEUES_SIZE, "not empty");
|
||||
test_wait_threads();
|
||||
|
||||
/* Testing reset */
|
||||
chSysLock();
|
||||
chOQResetI(&oq);
|
||||
chSysUnlock();
|
||||
test_assert_lock(9, chOQGetFullI(&oq) == 0, "still full");
|
||||
|
||||
/* Partial writes */
|
||||
n = chOQWriteTimeout(&oq, wa[1], TEST_QUEUES_SIZE / 2, TIME_IMMEDIATE);
|
||||
test_assert(10, n == TEST_QUEUES_SIZE / 2, "wrong returned size");
|
||||
n = chOQWriteTimeout(&oq, wa[1], TEST_QUEUES_SIZE / 2, TIME_IMMEDIATE);
|
||||
test_assert(11, n == TEST_QUEUES_SIZE / 2, "wrong returned size");
|
||||
test_assert_lock(12, chOQIsFullI(&oq), "not full");
|
||||
|
||||
/* Timeout */
|
||||
test_assert(13, chOQPutTimeout(&oq, 0, 10) == Q_TIMEOUT, "wrong timeout return");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testqueues2 = {
|
||||
"Queues, output queues",
|
||||
queues2_setup,
|
||||
NULL,
|
||||
queues2_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_QUEUES */
|
||||
|
||||
/**
|
||||
* @brief Test sequence for queues.
|
||||
*/
|
||||
ROMCONST struct testcase * ROMCONST patternqueues[] = {
|
||||
#if CH_CFG_USE_QUEUES || defined(__DOXYGEN__)
|
||||
&testqueues1,
|
||||
&testqueues2,
|
||||
#endif
|
||||
NULL
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _TESTQUEUES_H_
|
||||
#define _TESTQUEUES_H_
|
||||
|
||||
extern ROMCONST struct testcase * ROMCONST patternqueues[];
|
||||
|
||||
#endif /* _TESTQUEUES_H_ */
|
|
@ -1,295 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "test.h"
|
||||
|
||||
/**
|
||||
* @page test_sem Semaphores test
|
||||
*
|
||||
* File: @ref testsem.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the @ref semaphores subsystem.
|
||||
*
|
||||
* <h2>Objective</h2>
|
||||
* Objective of the test module is to cover 100% of the @ref semaphores code.
|
||||
*
|
||||
* <h2>Preconditions</h2>
|
||||
* The module requires the following kernel options:
|
||||
* - @p CH_CFG_USE_SEMAPHORES
|
||||
* .
|
||||
* In case some of the required options are not enabled then some or all tests
|
||||
* may be skipped.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_sem_001
|
||||
* - @subpage test_sem_002
|
||||
* - @subpage test_sem_003
|
||||
* - @subpage test_sem_004
|
||||
* .
|
||||
* @file testsem.c
|
||||
* @brief Semaphores test source file
|
||||
* @file testsem.h
|
||||
* @brief Semaphores test header file
|
||||
*/
|
||||
|
||||
#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
|
||||
|
||||
#define ALLOWED_DELAY MS2ST(2)
|
||||
|
||||
/*
|
||||
* Note, the static initializers are not really required because the
|
||||
* variables are explicitly initialized in each test case. It is done in order
|
||||
* to test the macros.
|
||||
*/
|
||||
static SEMAPHORE_DECL(sem1, 0);
|
||||
|
||||
/**
|
||||
* @page test_sem_001 Enqueuing test
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads with randomized priorities are enqueued to a semaphore then
|
||||
* awakened one at time.<br>
|
||||
* The test expects that the threads reach their goal in FIFO order or
|
||||
* priority order depending on the CH_CFG_USE_SEMAPHORES_PRIORITY configuration
|
||||
* setting.
|
||||
*/
|
||||
|
||||
static void sem1_setup(void) {
|
||||
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread1, p) {
|
||||
|
||||
chSemWait(&sem1);
|
||||
test_emit_token(*(char *)p);
|
||||
}
|
||||
|
||||
static void sem1_execute(void) {
|
||||
|
||||
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");
|
||||
chSemSignal(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
test_wait_threads();
|
||||
#if CH_CFG_USE_SEMAPHORES_PRIORITY
|
||||
test_assert_sequence(1, "ADCEB");
|
||||
#else
|
||||
test_assert_sequence(1, "ABCDE");
|
||||
#endif
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, thread1, "A");
|
||||
chSysLock();
|
||||
chSemAddCounterI(&sem1, 2);
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
test_wait_threads();
|
||||
test_assert_lock(2, chSemGetCounterI(&sem1) == 1, "invalid counter");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testsem1 = {
|
||||
"Semaphores, enqueuing",
|
||||
sem1_setup,
|
||||
NULL,
|
||||
sem1_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_sem_002 Timeout test
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The three possible semaphore waiting modes (do not wait, wait with timeout,
|
||||
* wait without timeout) are explored.<br>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
static void sem2_setup(void) {
|
||||
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread2, p) {
|
||||
|
||||
(void)p;
|
||||
chThdSleepMilliseconds(50);
|
||||
chSysLock();
|
||||
chSemSignalI(&sem1); /* For coverage reasons */
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
static void sem2_execute(void) {
|
||||
int i;
|
||||
systime_t target_time;
|
||||
msg_t msg;
|
||||
|
||||
/*
|
||||
* Testing special case TIME_IMMEDIATE.
|
||||
*/
|
||||
msg = chSemWaitTimeout(&sem1, TIME_IMMEDIATE);
|
||||
test_assert(1, msg == MSG_TIMEOUT, "wrong wake-up message");
|
||||
test_assert(2, queue_isempty(&sem1.queue), "queue not empty");
|
||||
test_assert(3, sem1.cnt == 0, "counter not zero");
|
||||
|
||||
/*
|
||||
* Testing not timeout condition.
|
||||
*/
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1,
|
||||
thread2, 0);
|
||||
msg = chSemWaitTimeout(&sem1, MS2ST(500));
|
||||
test_wait_threads();
|
||||
test_assert(4, msg == MSG_OK, "wrong wake-up message");
|
||||
test_assert(5, queue_isempty(&sem1.queue), "queue not empty");
|
||||
test_assert(6, sem1.cnt == 0, "counter not zero");
|
||||
|
||||
/*
|
||||
* Testing timeout condition.
|
||||
*/
|
||||
test_wait_tick();
|
||||
target_time = chVTGetSystemTime() + MS2ST(5 * 50);
|
||||
for (i = 0; i < 5; i++) {
|
||||
test_emit_token('A' + i);
|
||||
msg = chSemWaitTimeout(&sem1, MS2ST(50));
|
||||
test_assert(7, msg == MSG_TIMEOUT, "wrong wake-up message");
|
||||
test_assert(8, queue_isempty(&sem1.queue), "queue not empty");
|
||||
test_assert(9, sem1.cnt == 0, "counter not zero");
|
||||
}
|
||||
test_assert_sequence(10, "ABCDE");
|
||||
test_assert_time_window(11, target_time, target_time + ALLOWED_DELAY);
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testsem2 = {
|
||||
"Semaphores, timeout",
|
||||
sem2_setup,
|
||||
NULL,
|
||||
sem2_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_sem_003 Atomic signal-wait test
|
||||
*
|
||||
* <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.<br>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
static void sem3_setup(void) {
|
||||
|
||||
chSemObjectInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static THD_FUNCTION(thread3, p) {
|
||||
|
||||
(void)p;
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
}
|
||||
|
||||
static void sem3_execute(void) {
|
||||
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread3, 0);
|
||||
chSemSignalWait(&sem1, &sem1);
|
||||
test_assert(1, queue_isempty(&sem1.queue), "queue not empty");
|
||||
test_assert(2, sem1.cnt == 0, "counter not zero");
|
||||
|
||||
chSemSignalWait(&sem1, &sem1);
|
||||
test_assert(3, queue_isempty(&sem1.queue), "queue not empty");
|
||||
test_assert(4, sem1.cnt == 0, "counter not zero");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testsem3 = {
|
||||
"Semaphores, atomic signal-wait",
|
||||
sem3_setup,
|
||||
NULL,
|
||||
sem3_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_sem_004 Binary Wait and Signal
|
||||
*
|
||||
* <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.
|
||||
*/
|
||||
static THD_FUNCTION(thread4, p) {
|
||||
|
||||
chBSemSignal((binary_semaphore_t *)p);
|
||||
}
|
||||
|
||||
static void sem4_execute(void) {
|
||||
binary_semaphore_t bsem;
|
||||
|
||||
/* Creates a taken binary semaphore.*/
|
||||
chBSemObjectInit(&bsem, TRUE);
|
||||
chBSemReset(&bsem, TRUE);
|
||||
test_assert_lock(1, chBSemGetStateI(&bsem) == TRUE, "not taken");
|
||||
|
||||
/* Starts a signaler thread at a lower priority.*/
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE,
|
||||
chThdGetPriorityX()-1, thread4, &bsem);
|
||||
|
||||
/* Waits to be signaled.*/
|
||||
chBSemWait(&bsem);
|
||||
|
||||
/* The binary semaphore is expected to be taken.*/
|
||||
test_assert_lock(2, chBSemGetStateI(&bsem) == TRUE, "not taken");
|
||||
|
||||
/* Releasing it, check both the binary semaphore state and the underlying
|
||||
counter semaphore state..*/
|
||||
chBSemSignal(&bsem);
|
||||
test_assert_lock(3, chBSemGetStateI(&bsem) == FALSE, "still taken");
|
||||
test_assert_lock(4, chSemGetCounterI(&bsem.sem) == 1, "unexpected counter");
|
||||
|
||||
/* Checking signaling overflow, the counter must not go beyond 1.*/
|
||||
chBSemSignal(&bsem);
|
||||
test_assert_lock(3, chBSemGetStateI(&bsem) == FALSE, "taken");
|
||||
test_assert_lock(5, chSemGetCounterI(&bsem.sem) == 1, "unexpected counter");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testsem4 = {
|
||||
"Binary Semaphores, functionality",
|
||||
NULL,
|
||||
NULL,
|
||||
sem4_execute
|
||||
};
|
||||
#endif /* CH_CFG_USE_SEMAPHORES */
|
||||
|
||||
/**
|
||||
* @brief Test sequence for semaphores.
|
||||
*/
|
||||
ROMCONST struct testcase * ROMCONST patternsem[] = {
|
||||
#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
|
||||
&testsem1,
|
||||
&testsem2,
|
||||
&testsem3,
|
||||
&testsem4,
|
||||
#endif
|
||||
NULL
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _TESTSEM_H_
|
||||
#define _TESTSEM_H_
|
||||
|
||||
extern ROMCONST struct testcase * ROMCONST patternsem[];
|
||||
|
||||
#endif /* _TESTSEM_H_ */
|
|
@ -1,177 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "test.h"
|
||||
|
||||
/**
|
||||
* @page test_sys System test
|
||||
*
|
||||
* File: @ref testsys.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the @ref system subsystem.
|
||||
*
|
||||
* <h2>Objective</h2>
|
||||
* Objective of the test module is to cover 100% of the @ref system
|
||||
* subsystem code.
|
||||
*
|
||||
* <h2>Preconditions</h2>
|
||||
* None.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_sys_001
|
||||
* - @subpage test_sys_002
|
||||
* - @subpage test_sys_003
|
||||
* .
|
||||
* @file testsys.c
|
||||
* @brief System test source file
|
||||
* @file testsys.h
|
||||
* @brief System header file
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page test_sys_001 Critical zones check
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The critical zones API is invoked for coverage.
|
||||
*/
|
||||
|
||||
static void vtcb(void *p) {
|
||||
syssts_t sts;
|
||||
|
||||
(void)p;
|
||||
|
||||
/* Testing normal case.*/
|
||||
chSysLockFromISR();
|
||||
chSysUnlockFromISR();
|
||||
|
||||
/* Reentrant case.*/
|
||||
chSysLockFromISR();
|
||||
sts = chSysGetStatusAndLockX();
|
||||
chSysRestoreStatusX(sts);
|
||||
chSysUnlockFromISR();
|
||||
}
|
||||
|
||||
static void sys1_execute(void) {
|
||||
syssts_t sts;
|
||||
virtual_timer_t vt;
|
||||
|
||||
/* Testing normal case.*/
|
||||
sts = chSysGetStatusAndLockX();
|
||||
chSysRestoreStatusX(sts);
|
||||
|
||||
/* Reentrant case.*/
|
||||
chSysLock();
|
||||
sts = chSysGetStatusAndLockX();
|
||||
chSysRestoreStatusX(sts);
|
||||
chSysUnlock();
|
||||
|
||||
/* Unconditional lock.*/
|
||||
chSysUnconditionalLock();
|
||||
chSysUnconditionalLock();
|
||||
chSysUnlock();
|
||||
|
||||
/* Unconditional unlock.*/
|
||||
chSysLock();
|
||||
chSysUnconditionalUnlock();
|
||||
chSysUnconditionalUnlock();
|
||||
|
||||
/*/Testing from ISR context using a virtual timer.*/
|
||||
chVTObjectInit(&vt);
|
||||
chVTSet(&vt, 1, vtcb, NULL);
|
||||
chThdSleep(10);
|
||||
|
||||
test_assert(1, chVTIsArmed(&vt) == false, "timer still armed");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testsys1 = {
|
||||
"System, critical zones",
|
||||
NULL,
|
||||
NULL,
|
||||
sys1_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_sys_002 Interrupts handling
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The interrupts handling API is invoked for coverage.
|
||||
*/
|
||||
|
||||
static void sys2_execute(void) {
|
||||
|
||||
chSysSuspend();
|
||||
chSysDisable();
|
||||
chSysSuspend();
|
||||
chSysEnable();
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testsys2 = {
|
||||
"System, interrupts handling",
|
||||
NULL,
|
||||
NULL,
|
||||
sys2_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_sys_003 System integrity check
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* The chSysIntegrityCheckI() API is invoked in order to asses the state of the
|
||||
* system data structures.
|
||||
*/
|
||||
|
||||
static void sys3_execute(void) {
|
||||
bool result;
|
||||
|
||||
chSysLock();
|
||||
result = chSysIntegrityCheckI(CH_INTEGRITY_RLIST);
|
||||
chSysUnlock();
|
||||
test_assert(1, result == false, "ready list check failed");
|
||||
|
||||
chSysLock();
|
||||
result = chSysIntegrityCheckI(CH_INTEGRITY_VTLIST);
|
||||
chSysUnlock();
|
||||
test_assert(2, result == false, "virtual timers list check failed");
|
||||
|
||||
chSysLock();
|
||||
result = chSysIntegrityCheckI(CH_INTEGRITY_REGISTRY);
|
||||
chSysUnlock();
|
||||
test_assert(3, result == false, "registry list check failed");
|
||||
|
||||
chSysLock();
|
||||
result = chSysIntegrityCheckI(CH_INTEGRITY_PORT);
|
||||
chSysUnlock();
|
||||
test_assert(4, result == false, "port layer check failed");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testsys3 = {
|
||||
"System, integrity",
|
||||
NULL,
|
||||
NULL,
|
||||
sys3_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Test sequence for messages.
|
||||
*/
|
||||
ROMCONST struct testcase * ROMCONST patternsys[] = {
|
||||
&testsys1,
|
||||
&testsys2,
|
||||
&testsys3,
|
||||
NULL
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _TESTSYS_H_
|
||||
#define _TESTSYS_H_
|
||||
|
||||
extern ROMCONST struct testcase * ROMCONST patternsys[];
|
||||
|
||||
#endif /* _TESTSYS_H_ */
|
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "test.h"
|
||||
|
||||
/**
|
||||
* @page test_threads Threads and Scheduler test
|
||||
*
|
||||
* File: @ref testthd.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* This module implements the test sequence for the @ref scheduler,
|
||||
* @ref threads and @ref time subsystems.<br>
|
||||
* Note that the tests on those subsystems are formally required but most of
|
||||
* their functionality is already demonstrated because the test suite itself
|
||||
* depends on them, anyway double check is good.
|
||||
*
|
||||
* <h2>Objective</h2>
|
||||
* Objective of the test module is to cover 100% of the subsystems code.
|
||||
*
|
||||
* <h2>Preconditions</h2>
|
||||
* None.
|
||||
*
|
||||
* <h2>Test Cases</h2>
|
||||
* - @subpage test_threads_001
|
||||
* - @subpage test_threads_002
|
||||
* - @subpage test_threads_003
|
||||
* - @subpage test_threads_004
|
||||
* .
|
||||
* @file testthd.c
|
||||
* @brief Threads and Scheduler test source file
|
||||
* @file testthd.h
|
||||
* @brief Threads and Scheduler test header file
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page test_threads_001 Ready List functionality #1
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads, with increasing priority, are enqueued in the ready list
|
||||
* and atomically executed.<br>
|
||||
* The test expects the threads to perform their operations in increasing
|
||||
* priority order regardless of the initial order.
|
||||
*/
|
||||
|
||||
static THD_FUNCTION(thread, p) {
|
||||
|
||||
test_emit_token(*(char *)p);
|
||||
}
|
||||
|
||||
static void thd1_execute(void) {
|
||||
|
||||
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(1, "ABCDE");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testthd1 = {
|
||||
"Threads, enqueuing test #1",
|
||||
NULL,
|
||||
NULL,
|
||||
thd1_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_threads_002 Ready List functionality #2
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Five threads, with pseudo-random priority, are enqueued in the ready list
|
||||
* and atomically executed.<br>
|
||||
* The test expects the threads to perform their operations in increasing
|
||||
* priority order regardless of the initial order.
|
||||
*/
|
||||
|
||||
static void thd2_execute(void) {
|
||||
|
||||
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(1, "ABCDE");
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testthd2 = {
|
||||
"Threads, enqueuing test #2",
|
||||
NULL,
|
||||
NULL,
|
||||
thd2_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_threads_003 Threads 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.<br>
|
||||
* If the @p CH_CFG_USE_MUTEXES option is enabled then the priority changes are
|
||||
* also tested under priority inheritance boosted priority state.
|
||||
*/
|
||||
|
||||
static void thd3_execute(void) {
|
||||
tprio_t prio, p1;
|
||||
|
||||
prio = chThdGetPriorityX();
|
||||
p1 = chThdSetPriority(prio + 1);
|
||||
test_assert(1, p1 == prio,
|
||||
"unexpected returned priority level");
|
||||
test_assert(2, chThdGetPriorityX() == prio + 1,
|
||||
"unexpected priority level");
|
||||
p1 = chThdSetPriority(p1);
|
||||
test_assert(3, p1 == prio + 1,
|
||||
"unexpected returned priority level");
|
||||
test_assert(4, chThdGetPriorityX() == prio,
|
||||
"unexpected priority level");
|
||||
|
||||
#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
|
||||
/* Simulates a priority boost situation (p_prio > p_realprio).*/
|
||||
chSysLock();
|
||||
chThdGetSelfX()->prio += 2;
|
||||
chSysUnlock();
|
||||
test_assert(5, chThdGetPriorityX() == prio + 2,
|
||||
"unexpected priority level");
|
||||
|
||||
/* Tries to raise but below the boost level. */
|
||||
p1 = chThdSetPriority(prio + 1);
|
||||
test_assert(6, p1 == prio,
|
||||
"unexpected returned priority level");
|
||||
test_assert(7, chThdGetSelfX()->prio == prio + 2,
|
||||
"unexpected priority level");
|
||||
test_assert(8, chThdGetSelfX()->realprio == prio + 1,
|
||||
"unexpected returned real priority level");
|
||||
|
||||
/* Tries to raise above the boost level. */
|
||||
p1 = chThdSetPriority(prio + 3);
|
||||
test_assert(9, p1 == prio + 1,
|
||||
"unexpected returned priority level");
|
||||
test_assert(10, chThdGetSelfX()->prio == prio + 3,
|
||||
"unexpected priority level");
|
||||
test_assert(11, chThdGetSelfX()->realprio == prio + 3,
|
||||
"unexpected real priority level");
|
||||
|
||||
chSysLock();
|
||||
chThdGetSelfX()->prio = prio;
|
||||
chThdGetSelfX()->realprio = prio;
|
||||
chSysUnlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testthd3 = {
|
||||
"Threads, priority change",
|
||||
NULL,
|
||||
NULL,
|
||||
thd3_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @page test_threads_004 Threads delays test
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
* Delay APIs and associated macros are tested, the invoking thread is verified
|
||||
* to wake up at the exact expected time.
|
||||
*/
|
||||
|
||||
static void thd4_execute(void) {
|
||||
systime_t time;
|
||||
|
||||
test_wait_tick();
|
||||
|
||||
/* Timeouts in microseconds.*/
|
||||
time = chVTGetSystemTime();
|
||||
chThdSleepMicroseconds(100000);
|
||||
test_assert_time_window(1,
|
||||
time + US2ST(100000),
|
||||
time + US2ST(100000) + CH_CFG_ST_TIMEDELTA + 1);
|
||||
|
||||
/* Timeouts in milliseconds.*/
|
||||
time = chVTGetSystemTime();
|
||||
chThdSleepMilliseconds(100);
|
||||
test_assert_time_window(2,
|
||||
time + MS2ST(100),
|
||||
time + MS2ST(100) + CH_CFG_ST_TIMEDELTA + 1);
|
||||
|
||||
/* Timeouts in seconds.*/
|
||||
time = chVTGetSystemTime();
|
||||
chThdSleepSeconds(1);
|
||||
test_assert_time_window(3,
|
||||
time + S2ST(1),
|
||||
time + S2ST(1) + CH_CFG_ST_TIMEDELTA + 1);
|
||||
|
||||
/* Absolute timelines.*/
|
||||
time = chVTGetSystemTime() + MS2ST(100);
|
||||
chThdSleepUntil(time);
|
||||
test_assert_time_window(4,
|
||||
time,
|
||||
time + CH_CFG_ST_TIMEDELTA + 1);
|
||||
}
|
||||
|
||||
ROMCONST struct testcase testthd4 = {
|
||||
"Threads, delays",
|
||||
NULL,
|
||||
NULL,
|
||||
thd4_execute
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Test sequence for threads.
|
||||
*/
|
||||
ROMCONST struct testcase * ROMCONST patternthd[] = {
|
||||
&testthd1,
|
||||
&testthd2,
|
||||
&testthd3,
|
||||
&testthd4,
|
||||
NULL
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _TESTRDY_H_
|
||||
#define _TESTRDY_H_
|
||||
|
||||
extern ROMCONST struct testcase * ROMCONST patternthd[];
|
||||
|
||||
#endif /* _TESTRDY_H_ */
|
Loading…
Reference in New Issue