git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9194 35acf78f-673a-0410-8e92-d51de3d6d3f4

This commit is contained in:
Giovanni Di Sirio 2016-04-01 12:13:54 +00:00
parent b472786cd2
commit 7b1bf2a147
30 changed files with 1052 additions and 4314 deletions

View File

@ -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.&lt;br&gt;&#xD;
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.&lt;br&gt;&#xD;
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.&lt;br&gt;&#xD;
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.&lt;br&gt;&#xD;
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.&lt;br&gt;&#xD;
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>

View File

@ -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);

View File

@ -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
};

View File

@ -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");
}
/** @} */

View File

@ -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
* .
*/

View File

@ -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_ */
/** @} */

View File

@ -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
};

View File

@ -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_ */

View File

@ -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
};

View File

@ -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_ */

View File

@ -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
};

View File

@ -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_ */

View File

@ -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
};

View File

@ -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_ */

View File

@ -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
};

View File

@ -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_ */

View File

@ -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
};

View File

@ -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_ */

View File

@ -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
};

View File

@ -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_ */

View File

@ -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
};

View File

@ -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_ */

View File

@ -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
};

View File

@ -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_ */

View File

@ -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
};

View File

@ -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_ */

View File

@ -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
};

View File

@ -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_ */

View File

@ -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
};

View File

@ -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_ */