From 7c20551c988918cdad797a343d2126820cd75e8f Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Thu, 31 Mar 2016 14:03:43 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9189 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- test/rt/configuration.xml | 417 +++++++++++++++++++++++++++- test/rt/source/test/test_root.c | 2 + test/rt/source/test/test_root.h | 1 + test/rt/source/test/test_sequence_007.c | 477 +++++++++++++++++--------------- test/rt/source/test/test_sequence_008.c | 323 +++++++++++++-------- test/rt/source/test/test_sequence_009.c | 294 +++++++++++--------- test/rt/source/test/test_sequence_010.c | 270 ++++++++++++++++++ test/rt/source/test/test_sequence_010.h | 17 ++ test/rt/test.mk | 3 +- 9 files changed, 1324 insertions(+), 480 deletions(-) create mode 100644 test/rt/source/test/test_sequence_010.c create mode 100644 test/rt/source/test/test_sequence_010.h (limited to 'test/rt') diff --git a/test/rt/configuration.xml b/test/rt/configuration.xml index b77c0f831..607b4e474 100644 --- a/test/rt/configuration.xml +++ b/test/rt/configuration.xml @@ -1468,13 +1468,13 @@ static THD_FUNCTION(thread8, p) { test_emit_token(*(char *)p); chMtxUnlock(&m1); chMtxUnlock(&m2); -} - -static THD_FUNCTION(thread9, p) { - - chMtxLock(&m2); - test_emit_token(*(char *)p); - chMtxUnlock(&m2); +} + +static THD_FUNCTION(thread9, p) { + + chMtxLock(&m2); + test_emit_token(*(char *)p); + chMtxUnlock(&m2); } #endif /* CH_CFG_USE_CONDVARS */]]> @@ -2374,6 +2374,409 @@ test_assert_sequence("ABCD", "invalid sequence");]]> + + + Internal Tests + + + Event Sources and Event Flags. + + + This module implements the test sequence for the Events subsystem. + + + CH_CFG_USE_EVENTS + + + + + + + + Events registration. + + + 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. + + + + + + + + + + + + + + + + + + + An Event Source is initialized. + + + + + + + + + + + Two Event Listeners are registered on the Event Source, the Event Source is tested to have listeners. + + + + + + + + + + + An Event Listener is unregistered, the Event Source must still have listeners. + + + + + + + + + + + An Event Listener is unregistered, the Event Source must not have listeners. + + + + + + + + + + + + + Event Flags dispatching. + + + The test dispatches three event flags and verifies that the associated event handlers are invoked in LSb-first order. + + + + + + + + + + + + + + + + + + + Three evenf flag bits are raised then chEvtDispatch() is invoked, the sequence of handlers calls is tested. + + + + + + + + + + + + + Events Flags wait using chEvtWaitOne(). + + + Functionality of chEvtWaitOne() is tested under various scenarios. + + + + + + + + + + + + + + + + + + + Setting three event flags. + + + + + + + + + + + Calling chEvtWaitOne() three times, each time a single flag must be returned in order of priority. + + + + + + + + + + + Getting current time and starting a signaler thread, the thread will set an event flag after 50mS. + + + + + + + + + + + Calling chEvtWaitOne() then verifying that the event has been received after 50mS and that the event flags mask has been emptied. + + + + + + + + + + + + + Events Flags wait using chEvtWaitAny(). + + + Functionality of chEvtWaitAny() is tested under various scenarios. + + + + + + + + + + + + + + + + + + + Setting two, non contiguous, event flags. + + + + + + + + + + + Calling chEvtWaitAny() one time, the two flags must be returned. + + + + + + + + + + + Getting current time and starting a signaler thread, the thread will set an event flag after 50mS. + + + + + + + + + + + Calling chEvtWaitAny() then verifying that the event has been received after 50mS and that the event flags mask has been emptied. + + + + + + + + + + + + + Events Flags wait using chEvtWaitAll(). + + + Functionality of chEvtWaitAll() is tested under various scenarios. + + + + + + + + + + + + + + + + + + + Setting two, non contiguous, event flags. + + + + + + + + + + + Calling chEvtWaitAll() one time, the two flags must be returned. + + + + + + + + + + + Setting one event flag. + + + + + + + + + + + Getting current time and starting a signaler thread, the thread will set another event flag after 50mS. + + + + + + + + + + + Calling chEvtWaitAll() then verifying that both event flags have been received after 50mS and that the event flags mask has been emptied. + + + + + + + + + + + + Internal Tests diff --git a/test/rt/source/test/test_root.c b/test/rt/source/test/test_root.c index 796af8fbb..9ecbd3dea 100644 --- a/test/rt/source/test/test_root.c +++ b/test/rt/source/test/test_root.c @@ -30,6 +30,7 @@ * - @subpage test_sequence_007 * - @subpage test_sequence_008 * - @subpage test_sequence_009 + * - @subpage test_sequence_010 * . */ @@ -61,6 +62,7 @@ const testcase_t * const *test_suite[] = { test_sequence_007, test_sequence_008, test_sequence_009, + test_sequence_010, NULL }; diff --git a/test/rt/source/test/test_root.h b/test/rt/source/test/test_root.h index 114bfd9bf..6bbb1c989 100644 --- a/test/rt/source/test/test_root.h +++ b/test/rt/source/test/test_root.h @@ -31,6 +31,7 @@ #include "test_sequence_007.h" #include "test_sequence_008.h" #include "test_sequence_009.h" +#include "test_sequence_010.h" #if !defined(__DOXYGEN__) diff --git a/test/rt/source/test/test_sequence_007.c b/test/rt/source/test/test_sequence_007.c index 9563965fb..2a7e014b3 100644 --- a/test/rt/source/test/test_sequence_007.c +++ b/test/rt/source/test/test_sequence_007.c @@ -19,355 +19,386 @@ #include "test_root.h" /** - * @page test_sequence_007 [7] Mailboxes + * @page test_sequence_007 [7] Event Sources and Event Flags * * File: @ref test_sequence_007.c * *

Description

- * This sequence tests the ChibiOS/RT functionalities related to - * mailboxes. + * This module implements the test sequence for the Events subsystem. * *

Conditions

* This sequence is only executed if the following preprocessor condition * evaluates to true: - * - CH_CFG_USE_MAILBOXES + * - CH_CFG_USE_EVENTS * . * *

Test Cases

* - @subpage test_007_001 * - @subpage test_007_002 * - @subpage test_007_003 + * - @subpage test_007_004 + * - @subpage test_007_005 * . */ -#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__) +#if (CH_CFG_USE_EVENTS) || defined(__DOXYGEN__) /**************************************************************************** * Shared code. ****************************************************************************/ -#define MB_SIZE 4 +static EVENTSOURCE_DECL(es1); +static EVENTSOURCE_DECL(es2); -static msg_t mb_buffer[MB_SIZE]; -static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE); +static void h1(eventid_t id) {(void)id;test_emit_token('A');} +static void h2(eventid_t id) {(void)id;test_emit_token('B');} +static void h3(eventid_t id) {(void)id;test_emit_token('C');} +static ROMCONST evhandler_t evhndl[] = {h1, h2, h3}; + +static THD_FUNCTION(evt_thread3, p) { + + chThdSleepMilliseconds(50); + chEvtSignal((thread_t *)p, 1); +} + +static THD_FUNCTION(evt_thread4, p) { + + (void)p; + chEvtBroadcast(&es1); + chThdSleepMilliseconds(50); + chEvtBroadcast(&es2); +} /**************************************************************************** * Test cases. ****************************************************************************/ /** - * @page test_007_001 [7.1] Mailbox normal API, non-blocking tests + * @page test_007_001 [7.1] Events registration * *

Description

- * The mailbox normal API is tested without triggering blocking - * conditions. + * Two event listeners are registered on an event source and then + * unregistered in the same order.
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. * *

Test Steps

- * - [7.1.1] Testing the mailbox size. - * - [7.1.2] Resetting the mailbox, conditions are checked, no errors - * expected. - * - [7.1.3] Filling the mailbox using chMBPost() and chMBPostAhead() - * once, no errors expected. - * - [7.1.4] Testing intermediate conditions. Data pointers must be - * aligned, semaphore counters are checked. - * - [7.1.5] Emptying the mailbox using chMBFetch(), no errors - * expected. - * - [7.1.6] Posting and then fetching one more message, no errors - * expected. - * - [7.1.7] Testing final conditions. Data pointers must be aligned to - * buffer start, semaphore counters are checked. + * - [7.1.1] An Event Source is initialized. + * - [7.1.2] Two Event Listeners are registered on the Event Source, + * the Event Source is tested to have listeners. + * - [7.1.3] An Event Listener is unregistered, the Event Source must + * still have listeners. + * - [7.1.4] An Event Listener is unregistered, the Event Source must + * not have listeners. * . */ -static void test_007_001_setup(void) { - chMBObjectInit(&mb1, mb_buffer, MB_SIZE); -} - -static void test_007_001_teardown(void) { - chMBReset(&mb1); -} - static void test_007_001_execute(void) { - msg_t msg1, msg2; - unsigned i; + event_listener_t el1, el2; - /* [7.1.1] Testing the mailbox size.*/ + /* [7.1.1] An Event Source is initialized.*/ test_set_step(1); { - test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size"); + chEvtObjectInit(&es1); } - /* [7.1.2] Resetting the mailbox, conditions are checked, no errors - expected.*/ + /* [7.1.2] Two Event Listeners are registered on the Event Source, + the Event Source is tested to have listeners.*/ test_set_step(2); { - chMBReset(&mb1); - test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); - test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); - test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); - test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); + chEvtRegisterMask(&es1, &el1, 1); + chEvtRegisterMask(&es1, &el2, 2); + test_assert_lock(chEvtIsListeningI(&es1), "no listener"); } - /* [7.1.3] Filling the mailbox using chMBPost() and chMBPostAhead() - once, no errors expected.*/ + /* [7.1.3] An Event Listener is unregistered, the Event Source must + still have listeners.*/ test_set_step(3); { - for (i = 0; i < MB_SIZE - 1; i++) { - msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE); - test_assert(msg1 == MSG_OK, "wrong wake-up message"); - } - msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE); - test_assert(msg1 == MSG_OK, "wrong wake-up message"); + chEvtUnregister(&es1, &el1); + test_assert_lock(chEvtIsListeningI(&es1), "no listener"); } - /* [7.1.4] Testing intermediate conditions. Data pointers must be - aligned, semaphore counters are checked.*/ + /* [7.1.4] An Event Listener is unregistered, the Event Source must + not have listeners.*/ test_set_step(4); { - test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty"); - test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full"); - test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned"); - } - - /* [7.1.5] Emptying the mailbox using chMBFetch(), no errors - expected.*/ - test_set_step(5); - { - for (i = 0; i < MB_SIZE; i++) { - msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE); - test_assert(msg1 == MSG_OK, "wrong wake-up message"); - test_emit_token(msg2); - } - test_assert_sequence("ABCD", "wrong get sequence"); - } - - /* [7.1.6] Posting and then fetching one more message, no errors - expected.*/ - test_set_step(6); - { - msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE); - test_assert(msg1 == MSG_OK, "wrong wake-up message"); - msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE); - test_assert(msg1 == MSG_OK, "wrong wake-up message"); - } - - /* [7.1.7] Testing final conditions. Data pointers must be aligned to - buffer start, semaphore counters are checked.*/ - test_set_step(7); - { - test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); - test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); - test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); - test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); + chEvtUnregister(&es1, &el2); + test_assert_lock(!chEvtIsListeningI(&es1), "stuck listener"); } } static const testcase_t test_007_001 = { - "Mailbox normal API, non-blocking tests", - test_007_001_setup, - test_007_001_teardown, + "Events registration", + NULL, + NULL, test_007_001_execute }; /** - * @page test_007_002 [7.2] Mailbox I-Class API, non-blocking tests + * @page test_007_002 [7.2] Event Flags dispatching * *

Description

- * The mailbox I-Class API is tested without triggering blocking - * conditions. + * The test dispatches three event flags and verifies that the + * associated event handlers are invoked in LSb-first order. * *

Test Steps

- * - [7.2.1] Testing the mailbox size. - * - [7.2.2] Resetting the mailbox, conditions are checked, no errors - * expected. - * - [7.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI() - * once, no errors expected. - * - [7.2.4] Testing intermediate conditions. Data pointers must be - * aligned, semaphore counters are checked. - * - [7.2.5] Emptying the mailbox using chMBFetchI(), no errors - * expected. - * - [7.2.6] Posting and then fetching one more message, no errors - * expected. - * - [7.2.7] Testing final conditions. Data pointers must be aligned to - * buffer start, semaphore counters are checked. + * - [7.2.1] Three evenf flag bits are raised then chEvtDispatch() is + * invoked, the sequence of handlers calls is tested. * . */ static void test_007_002_setup(void) { - chMBObjectInit(&mb1, mb_buffer, MB_SIZE); + chEvtGetAndClearEvents(ALL_EVENTS); } -static void test_007_002_teardown(void) { - chMBReset(&mb1); +static void test_007_002_execute(void) { + + /* [7.2.1] Three evenf flag bits are raised then chEvtDispatch() is + invoked, the sequence of handlers calls is tested.*/ + test_set_step(1); + { + chEvtDispatch(evhndl, 7); + test_assert_sequence("ABC", "invalid sequence"); + } } -static void test_007_002_execute(void) { - msg_t msg1, msg2; - unsigned i; +static const testcase_t test_007_002 = { + "Event Flags dispatching", + test_007_002_setup, + NULL, + test_007_002_execute +}; + +/** + * @page test_007_003 [7.3] Events Flags wait using chEvtWaitOne() + * + *

Description

+ * Functionality of chEvtWaitOne() is tested under various scenarios. + * + *

Test Steps

+ * - [7.3.1] Setting three event flags. + * - [7.3.2] Calling chEvtWaitOne() three times, each time a single + * flag must be returned in order of priority. + * - [7.3.3] Getting current time and starting a signaler thread, the + * thread will set an event flag after 50mS. + * - [7.3.4] Calling chEvtWaitOne() then verifying that the event has + * been received after 50mS and that the event flags mask has been + * emptied. + * . + */ - /* [7.2.1] Testing the mailbox size.*/ +static void test_007_003_setup(void) { + chEvtGetAndClearEvents(ALL_EVENTS); +} + +static void test_007_003_execute(void) { + eventmask_t m; + systime_t target_time; + + /* [7.3.1] Setting three event flags.*/ test_set_step(1); { - test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size"); + chEvtAddEvents(7); } - /* [7.2.2] Resetting the mailbox, conditions are checked, no errors - expected.*/ + /* [7.3.2] Calling chEvtWaitOne() three times, each time a single + flag must be returned in order of priority.*/ test_set_step(2); { - chSysLock(); - chMBResetI(&mb1); - chSysUnlock(); - test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); - test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); - test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); - test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); + m = chEvtWaitOne(ALL_EVENTS); + test_assert(m == 1, "single event error"); + m = chEvtWaitOne(ALL_EVENTS); + test_assert(m == 2, "single event error"); + m = chEvtWaitOne(ALL_EVENTS); + test_assert(m == 4, "single event error"); + m = chEvtGetAndClearEvents(ALL_EVENTS); + test_assert(m == 0, "stuck event"); } - /* [7.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI() - once, no errors expected.*/ + /* [7.3.3] Getting current time and starting a signaler thread, the + thread will set an event flag after 50mS.*/ test_set_step(3); { - for (i = 0; i < MB_SIZE - 1; i++) { - chSysLock(); - msg1 = chMBPostI(&mb1, 'B' + i); - chSysUnlock(); - test_assert(msg1 == MSG_OK, "wrong wake-up message"); - } - chSysLock(); - msg1 = chMBPostAheadI(&mb1, 'A'); - chSysUnlock(); - test_assert(msg1 == MSG_OK, "wrong wake-up message"); + target_time = test_wait_tick() + MS2ST(50); + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1, + evt_thread3, chThdGetSelfX()); } - /* [7.2.4] Testing intermediate conditions. Data pointers must be - aligned, semaphore counters are checked.*/ + /* [7.3.4] Calling chEvtWaitOne() then verifying that the event has + been received after 50mS and that the event flags mask has been + emptied.*/ test_set_step(4); { - test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty"); - test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full"); - test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned"); + m = chEvtWaitOne(ALL_EVENTS); + test_assert_time_window(target_time, target_time + ALLOWED_DELAY, + "out of time window"); + test_assert(m == 1, "event flag error"); + m = chEvtGetAndClearEvents(ALL_EVENTS); + test_assert(m == 0, "stuck event"); + test_wait_threads(); } +} - /* [7.2.5] Emptying the mailbox using chMBFetchI(), no errors - expected.*/ - test_set_step(5); +static const testcase_t test_007_003 = { + "Events Flags wait using chEvtWaitOne()", + test_007_003_setup, + NULL, + test_007_003_execute +}; + +/** + * @page test_007_004 [7.4] Events Flags wait using chEvtWaitAny() + * + *

Description

+ * Functionality of chEvtWaitAny() is tested under various scenarios. + * + *

Test Steps

+ * - [7.4.1] Setting two, non contiguous, event flags. + * - [7.4.2] Calling chEvtWaitAny() one time, the two flags must be + * returned. + * - [7.4.3] Getting current time and starting a signaler thread, the + * thread will set an event flag after 50mS. + * - [7.4.4] Calling chEvtWaitAny() then verifying that the event has + * been received after 50mS and that the event flags mask has been + * emptied. + * . + */ + +static void test_007_004_setup(void) { + chEvtGetAndClearEvents(ALL_EVENTS); +} + +static void test_007_004_execute(void) { + eventmask_t m; + systime_t target_time; + + /* [7.4.1] Setting two, non contiguous, event flags.*/ + test_set_step(1); { - for (i = 0; i < MB_SIZE; i++) { - chSysLock(); - msg1 = chMBFetchI(&mb1, &msg2); - chSysUnlock(); - test_assert(msg1 == MSG_OK, "wrong wake-up message"); - test_emit_token(msg2); - } - test_assert_sequence("ABCD", "wrong get sequence"); + chEvtAddEvents(5); } - /* [7.2.6] Posting and then fetching one more message, no errors - expected.*/ - test_set_step(6); + /* [7.4.2] Calling chEvtWaitAny() one time, the two flags must be + returned.*/ + test_set_step(2); + { + m = chEvtWaitAny(ALL_EVENTS); + test_assert(m == 5, "unexpected pending bit"); + m = chEvtGetAndClearEvents(ALL_EVENTS); + test_assert(m == 0, "stuck event"); + } + + /* [7.4.3] Getting current time and starting a signaler thread, the + thread will set an event flag after 50mS.*/ + test_set_step(3); { - msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE); - test_assert(msg1 == MSG_OK, "wrong wake-up message"); - msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE); - test_assert(msg1 == MSG_OK, "wrong wake-up message"); + target_time = test_wait_tick() + MS2ST(50); + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1, + evt_thread3, chThdGetSelfX()); } - /* [7.2.7] Testing final conditions. Data pointers must be aligned to - buffer start, semaphore counters are checked.*/ - test_set_step(7); + /* [7.4.4] Calling chEvtWaitAny() then verifying that the event has + been received after 50mS and that the event flags mask has been + emptied.*/ + test_set_step(4); { - test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); - test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); - test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); - test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); + m = chEvtWaitAny(ALL_EVENTS); + test_assert_time_window(target_time, target_time + ALLOWED_DELAY, + "out of time window"); + test_assert(m == 1, "event flag error"); + m = chEvtGetAndClearEvents(ALL_EVENTS); + test_assert(m == 0, "stuck event"); + test_wait_threads(); } } -static const testcase_t test_007_002 = { - "Mailbox I-Class API, non-blocking tests", - test_007_002_setup, - test_007_002_teardown, - test_007_002_execute +static const testcase_t test_007_004 = { + "Events Flags wait using chEvtWaitAny()", + test_007_004_setup, + NULL, + test_007_004_execute }; /** - * @page test_007_003 [7.3] Mailbox timeouts + * @page test_007_005 [7.5] Events Flags wait using chEvtWaitAll() * *

Description

- * The mailbox API is tested for timeouts. + * Functionality of chEvtWaitAll() is tested under various scenarios. * *

Test Steps

- * - [7.3.1] Filling the mailbox. - * - [7.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and - * chMBPostAheadI() timeout. - * - [7.3.3] Resetting the mailbox. - * - [7.3.4] Testing chMBFetch() and chMBFetchI() timeout. + * - [7.5.1] Setting two, non contiguous, event flags. + * - [7.5.2] Calling chEvtWaitAll() one time, the two flags must be + * returned. + * - [7.5.3] Setting one event flag. + * - [7.5.4] Getting current time and starting a signaler thread, the + * thread will set another event flag after 50mS. + * - [7.5.5] Calling chEvtWaitAll() then verifying that both event + * flags have been received after 50mS and that the event flags mask + * has been emptied. * . */ -static void test_007_003_setup(void) { - chMBObjectInit(&mb1, mb_buffer, MB_SIZE); -} - -static void test_007_003_teardown(void) { - chMBReset(&mb1); +static void test_007_005_setup(void) { + chEvtGetAndClearEvents(ALL_EVENTS); } -static void test_007_003_execute(void) { - msg_t msg1, msg2; - unsigned i; +static void test_007_005_execute(void) { + eventmask_t m; + systime_t target_time; - /* [7.3.1] Filling the mailbox.*/ + /* [7.5.1] Setting two, non contiguous, event flags.*/ test_set_step(1); { - for (i = 0; i < MB_SIZE; i++) { - msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE); - test_assert(msg1 == MSG_OK, "wrong wake-up message"); - } + chEvtAddEvents(5); } - /* [7.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and - chMBPostAheadI() timeout.*/ + /* [7.5.2] Calling chEvtWaitAll() one time, the two flags must be + returned.*/ test_set_step(2); { - msg1 = chMBPost(&mb1, 'X', 1); - test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); - chSysLock(); - msg1 = chMBPostI(&mb1, 'X'); - chSysUnlock(); - test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); - msg1 = chMBPostAhead(&mb1, 'X', 1); - test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); - chSysLock(); - msg1 = chMBPostAheadI(&mb1, 'X'); - chSysUnlock(); - test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + m = chEvtWaitAll(5); + test_assert(m == 5, "unexpected pending bit"); + m = chEvtGetAndClearEvents(ALL_EVENTS); + test_assert(m == 0, "stuck event"); } - /* [7.3.3] Resetting the mailbox.*/ + /* [7.5.3] Setting one event flag.*/ test_set_step(3); { - chMBReset(&mb1); + chEvtAddEvents(4); } - /* [7.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/ + /* [7.5.4] Getting current time and starting a signaler thread, the + thread will set another event flag after 50mS.*/ test_set_step(4); { - msg1 = chMBFetch(&mb1, &msg2, 1); - test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); - chSysLock(); - msg1 = chMBFetchI(&mb1, &msg2); - chSysUnlock(); - test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + target_time = test_wait_tick() + MS2ST(50); + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1, + evt_thread3, chThdGetSelfX()); + } + + /* [7.5.5] Calling chEvtWaitAll() then verifying that both event + flags have been received after 50mS and that the event flags mask + has been emptied.*/ + test_set_step(5); + { + m = chEvtWaitAll(5); + test_assert_time_window(target_time, target_time + ALLOWED_DELAY, + "out of time window"); + test_assert(m == 5, "event flags error"); + m = chEvtGetAndClearEvents(ALL_EVENTS); + test_assert(m == 0, "stuck event"); + test_wait_threads(); } } -static const testcase_t test_007_003 = { - "Mailbox timeouts", - test_007_003_setup, - test_007_003_teardown, - test_007_003_execute +static const testcase_t test_007_005 = { + "Events Flags wait using chEvtWaitAll()", + test_007_005_setup, + NULL, + test_007_005_execute }; /**************************************************************************** @@ -375,13 +406,15 @@ static const testcase_t test_007_003 = { ****************************************************************************/ /** - * @brief Mailboxes. + * @brief Event Sources and Event Flags. */ const testcase_t * const test_sequence_007[] = { &test_007_001, &test_007_002, &test_007_003, + &test_007_004, + &test_007_005, NULL }; -#endif /* CH_CFG_USE_MAILBOXES */ +#endif /* CH_CFG_USE_EVENTS */ diff --git a/test/rt/source/test/test_sequence_008.c b/test/rt/source/test/test_sequence_008.c index 6e9c05f1c..4e3c1beb1 100644 --- a/test/rt/source/test/test_sequence_008.c +++ b/test/rt/source/test/test_sequence_008.c @@ -19,18 +19,18 @@ #include "test_root.h" /** - * @page test_sequence_008 [8] Memory Pools + * @page test_sequence_008 [8] Mailboxes * * File: @ref test_sequence_008.c * *

Description

- * This sequence tests the ChibiOS/RT functionalities related to memory - * pools. + * This sequence tests the ChibiOS/RT functionalities related to + * mailboxes. * *

Conditions

* This sequence is only executed if the following preprocessor condition * evaluates to true: - * - CH_CFG_USE_MEMPOOLS + * - CH_CFG_USE_MAILBOXES * . * *

Test Cases

@@ -40,251 +40,348 @@ * . */ -#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__) +#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__) /**************************************************************************** * Shared code. ****************************************************************************/ -#define MEMORY_POOL_SIZE 4 +#define MB_SIZE 4 -static uint32_t objects[MEMORY_POOL_SIZE]; -static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL); -static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t)); - -static void *null_provider(size_t size, unsigned align) { - - (void)size; - (void)align; - - return NULL; -} +static msg_t mb_buffer[MB_SIZE]; +static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE); /**************************************************************************** * Test cases. ****************************************************************************/ /** - * @page test_008_001 [8.1] Loading and emptying a memory pool + * @page test_008_001 [8.1] Mailbox normal API, non-blocking tests * *

Description

- * The memory pool functionality is tested by loading and emptying it, - * all conditions are tested. + * The mailbox normal API is tested without triggering blocking + * conditions. * *

Test Steps

- * - [8.1.1] Adding the objects to the pool using chPoolLoadArray(). - * - [8.1.2] Emptying the pool using chPoolAlloc(). - * - [8.1.3] Now must be empty. - * - [8.1.4] Adding the objects to the pool using chPoolFree(). - * - [8.1.5] Emptying the pool using chPoolAlloc() again. - * - [8.1.6] Now must be empty again. - * - [8.1.7] Covering the case where a provider is unable to return - * more memory. + * - [8.1.1] Testing the mailbox size. + * - [8.1.2] Resetting the mailbox, conditions are checked, no errors + * expected. + * - [8.1.3] Filling the mailbox using chMBPost() and chMBPostAhead() + * once, no errors expected. + * - [8.1.4] Testing intermediate conditions. Data pointers must be + * aligned, semaphore counters are checked. + * - [8.1.5] Emptying the mailbox using chMBFetch(), no errors + * expected. + * - [8.1.6] Posting and then fetching one more message, no errors + * expected. + * - [8.1.7] Testing final conditions. Data pointers must be aligned to + * buffer start, semaphore counters are checked. * . */ static void test_008_001_setup(void) { - chPoolObjectInit(&mp1, sizeof (uint32_t), NULL); + chMBObjectInit(&mb1, mb_buffer, MB_SIZE); +} + +static void test_008_001_teardown(void) { + chMBReset(&mb1); } static void test_008_001_execute(void) { + msg_t msg1, msg2; unsigned i; - /* [8.1.1] Adding the objects to the pool using chPoolLoadArray().*/ + /* [8.1.1] Testing the mailbox size.*/ test_set_step(1); { - chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE); + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size"); } - /* [8.1.2] Emptying the pool using chPoolAlloc().*/ + /* [8.1.2] Resetting the mailbox, conditions are checked, no errors + expected.*/ test_set_step(2); { - for (i = 0; i < MEMORY_POOL_SIZE; i++) - test_assert(chPoolAlloc(&mp1) != NULL, "list empty"); + chMBReset(&mb1); + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); + test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); + test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); } - /* [8.1.3] Now must be empty.*/ + /* [8.1.3] Filling the mailbox using chMBPost() and chMBPostAhead() + once, no errors expected.*/ test_set_step(3); { - test_assert(chPoolAlloc(&mp1) == NULL, "list not empty"); + for (i = 0; i < MB_SIZE - 1; i++) { + msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); } - /* [8.1.4] Adding the objects to the pool using chPoolFree().*/ + /* [8.1.4] Testing intermediate conditions. Data pointers must be + aligned, semaphore counters are checked.*/ test_set_step(4); { - for (i = 0; i < MEMORY_POOL_SIZE; i++) - chPoolFree(&mp1, &objects[i]); + test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full"); + test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned"); } - /* [8.1.5] Emptying the pool using chPoolAlloc() again.*/ + /* [8.1.5] Emptying the mailbox using chMBFetch(), no errors + expected.*/ test_set_step(5); { - for (i = 0; i < MEMORY_POOL_SIZE; i++) - test_assert(chPoolAlloc(&mp1) != NULL, "list empty"); + for (i = 0; i < MB_SIZE; i++) { + msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + test_emit_token(msg2); + } + test_assert_sequence("ABCD", "wrong get sequence"); } - /* [8.1.6] Now must be empty again.*/ + /* [8.1.6] Posting and then fetching one more message, no errors + expected.*/ test_set_step(6); { - test_assert(chPoolAlloc(&mp1) == NULL, "list not empty"); + msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); } - /* [8.1.7] Covering the case where a provider is unable to return - more memory.*/ + /* [8.1.7] Testing final conditions. Data pointers must be aligned to + buffer start, semaphore counters are checked.*/ test_set_step(7); { - chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider); - test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory"); + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); + test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); + test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); } } static const testcase_t test_008_001 = { - "Loading and emptying a memory pool", + "Mailbox normal API, non-blocking tests", test_008_001_setup, - NULL, + test_008_001_teardown, test_008_001_execute }; -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) /** - * @page test_008_002 [8.2] Loading and emptying a guarded memory pool without waiting + * @page test_008_002 [8.2] Mailbox I-Class API, non-blocking tests * *

Description

- * The memory pool functionality is tested by loading and emptying it, - * all conditions are tested. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_SEMAPHORES - * . + * The mailbox I-Class API is tested without triggering blocking + * conditions. * *

Test Steps

- * - [8.2.1] Adding the objects to the pool using - * chGuardedPoolLoadArray(). - * - [8.2.2] Emptying the pool using chGuardedPoolAllocTimeout(). - * - [8.2.3] Now must be empty. - * - [8.2.4] Adding the objects to the pool using chGuardedPoolFree(). - * - [8.2.5] Emptying the pool using chGuardedPoolAllocTimeout() again. - * - [8.2.6] Now must be empty again. + * - [8.2.1] Testing the mailbox size. + * - [8.2.2] Resetting the mailbox, conditions are checked, no errors + * expected. + * - [8.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI() + * once, no errors expected. + * - [8.2.4] Testing intermediate conditions. Data pointers must be + * aligned, semaphore counters are checked. + * - [8.2.5] Emptying the mailbox using chMBFetchI(), no errors + * expected. + * - [8.2.6] Posting and then fetching one more message, no errors + * expected. + * - [8.2.7] Testing final conditions. Data pointers must be aligned to + * buffer start, semaphore counters are checked. * . */ static void test_008_002_setup(void) { - chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t)); + chMBObjectInit(&mb1, mb_buffer, MB_SIZE); +} + +static void test_008_002_teardown(void) { + chMBReset(&mb1); } static void test_008_002_execute(void) { + msg_t msg1, msg2; unsigned i; - /* [8.2.1] Adding the objects to the pool using - chGuardedPoolLoadArray().*/ + /* [8.2.1] Testing the mailbox size.*/ test_set_step(1); { - chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE); + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size"); } - /* [8.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/ + /* [8.2.2] Resetting the mailbox, conditions are checked, no errors + expected.*/ test_set_step(2); { - for (i = 0; i < MEMORY_POOL_SIZE; i++) - test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty"); + chSysLock(); + chMBResetI(&mb1); + chSysUnlock(); + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); + test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); + test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); } - /* [8.2.3] Now must be empty.*/ + /* [8.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI() + once, no errors expected.*/ test_set_step(3); { - test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty"); + for (i = 0; i < MB_SIZE - 1; i++) { + chSysLock(); + msg1 = chMBPostI(&mb1, 'B' + i); + chSysUnlock(); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + chSysLock(); + msg1 = chMBPostAheadI(&mb1, 'A'); + chSysUnlock(); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); } - /* [8.2.4] Adding the objects to the pool using - chGuardedPoolFree().*/ + /* [8.2.4] Testing intermediate conditions. Data pointers must be + aligned, semaphore counters are checked.*/ test_set_step(4); { - for (i = 0; i < MEMORY_POOL_SIZE; i++) - chGuardedPoolFree(&gmp1, &objects[i]); + test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full"); + test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned"); } - /* [8.2.5] Emptying the pool using chGuardedPoolAllocTimeout() - again.*/ + /* [8.2.5] Emptying the mailbox using chMBFetchI(), no errors + expected.*/ test_set_step(5); { - for (i = 0; i < MEMORY_POOL_SIZE; i++) - test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty"); + for (i = 0; i < MB_SIZE; i++) { + chSysLock(); + msg1 = chMBFetchI(&mb1, &msg2); + chSysUnlock(); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + test_emit_token(msg2); + } + test_assert_sequence("ABCD", "wrong get sequence"); } - /* [8.2.6] Now must be empty again.*/ + /* [8.2.6] Posting and then fetching one more message, no errors + expected.*/ test_set_step(6); { - test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty"); + msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + + /* [8.2.7] Testing final conditions. Data pointers must be aligned to + buffer start, semaphore counters are checked.*/ + test_set_step(7); + { + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); + test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); + test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); } } static const testcase_t test_008_002 = { - "Loading and emptying a guarded memory pool without waiting", + "Mailbox I-Class API, non-blocking tests", test_008_002_setup, - NULL, + test_008_002_teardown, test_008_002_execute }; -#endif /* CH_CFG_USE_SEMAPHORES */ -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) /** - * @page test_008_003 [8.3] Guarded Memory Pools timeout + * @page test_008_003 [8.3] Mailbox timeouts * *

Description

- * The timeout features for the Guarded Memory Pools is tested. - * - *

Conditions

- * This test is only executed if the following preprocessor condition - * evaluates to true: - * - CH_CFG_USE_SEMAPHORES - * . + * The mailbox API is tested for timeouts. * *

Test Steps

- * - [8.3.1] Trying to allocate with 100mS timeout, must fail because - * the pool is empty. + * - [8.3.1] Filling the mailbox. + * - [8.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and + * chMBPostAheadI() timeout. + * - [8.3.3] Resetting the mailbox. + * - [8.3.4] Testing chMBFetch() and chMBFetchI() timeout. * . */ static void test_008_003_setup(void) { - chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t)); + chMBObjectInit(&mb1, mb_buffer, MB_SIZE); +} + +static void test_008_003_teardown(void) { + chMBReset(&mb1); } static void test_008_003_execute(void) { + msg_t msg1, msg2; + unsigned i; - /* [8.3.1] Trying to allocate with 100mS timeout, must fail because - the pool is empty.*/ + /* [8.3.1] Filling the mailbox.*/ test_set_step(1); { - test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty"); + for (i = 0; i < MB_SIZE; i++) { + msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + } + + /* [8.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and + chMBPostAheadI() timeout.*/ + test_set_step(2); + { + msg1 = chMBPost(&mb1, 'X', 1); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + chSysLock(); + msg1 = chMBPostI(&mb1, 'X'); + chSysUnlock(); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + msg1 = chMBPostAhead(&mb1, 'X', 1); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + chSysLock(); + msg1 = chMBPostAheadI(&mb1, 'X'); + chSysUnlock(); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + } + + /* [8.3.3] Resetting the mailbox.*/ + test_set_step(3); + { + chMBReset(&mb1); + } + + /* [8.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/ + test_set_step(4); + { + msg1 = chMBFetch(&mb1, &msg2, 1); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + chSysLock(); + msg1 = chMBFetchI(&mb1, &msg2); + chSysUnlock(); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); } } static const testcase_t test_008_003 = { - "Guarded Memory Pools timeout", + "Mailbox timeouts", test_008_003_setup, - NULL, + test_008_003_teardown, test_008_003_execute }; -#endif /* CH_CFG_USE_SEMAPHORES */ /**************************************************************************** * Exported data. ****************************************************************************/ /** - * @brief Memory Pools. + * @brief Mailboxes. */ const testcase_t * const test_sequence_008[] = { &test_008_001, -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) &test_008_002, -#endif -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) &test_008_003, -#endif NULL }; -#endif /* CH_CFG_USE_MEMPOOLS */ +#endif /* CH_CFG_USE_MAILBOXES */ diff --git a/test/rt/source/test/test_sequence_009.c b/test/rt/source/test/test_sequence_009.c index b980b828e..63e9f2da2 100644 --- a/test/rt/source/test/test_sequence_009.c +++ b/test/rt/source/test/test_sequence_009.c @@ -19,252 +19,272 @@ #include "test_root.h" /** - * @page test_sequence_009 [9] Memory Heaps + * @page test_sequence_009 [9] Memory Pools * * File: @ref test_sequence_009.c * *

Description

* This sequence tests the ChibiOS/RT functionalities related to memory - * heaps. + * pools. * *

Conditions

* This sequence is only executed if the following preprocessor condition * evaluates to true: - * - CH_CFG_USE_HEAP + * - CH_CFG_USE_MEMPOOLS * . * *

Test Cases

* - @subpage test_009_001 * - @subpage test_009_002 + * - @subpage test_009_003 * . */ -#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__) +#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__) /**************************************************************************** * Shared code. ****************************************************************************/ -#define ALLOC_SIZE 16 -#define HEAP_SIZE (ALLOC_SIZE * 8) +#define MEMORY_POOL_SIZE 4 -static memory_heap_t test_heap; -static CH_HEAP_AREA(myheap, HEAP_SIZE); +static uint32_t objects[MEMORY_POOL_SIZE]; +static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL); +static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t)); + +static void *null_provider(size_t size, unsigned align) { + + (void)size; + (void)align; + + return NULL; +} /**************************************************************************** * Test cases. ****************************************************************************/ /** - * @page test_009_001 [9.1] Allocation and fragmentation + * @page test_009_001 [9.1] Loading and emptying a memory pool * *

Description

- * Series of allocations/deallocations are performed in carefully - * designed sequences in order to stimulate all the possible code paths - * inside the allocator. The test expects to find the heap back to the - * initial status after each sequence. + * The memory pool functionality is tested by loading and emptying it, + * all conditions are tested. * *

Test Steps

- * - [9.1.1] Testing initial conditions, the heap must not be - * fragmented and one free block present. - * - [9.1.2] Trying to allocate an block bigger than available space, - * an error is expected. - * - [9.1.3] Single block allocation using chHeapAlloc() then the block - * is freed using chHeapFree(), must not fail. - * - [9.1.4] Using chHeapStatus() to assess the heap state. There must - * be at least one free block of sufficient size. - * - [9.1.5] Allocating then freeing in the same order. - * - [9.1.6] Allocating then freeing in reverse order. - * - [9.1.7] Small fragments handling. Checking the behavior when - * allocating blocks with size not multiple of alignment unit. - * - [9.1.8] Skipping a fragment, the first fragment in the list is too - * small so the allocator must pick the second one. - * - [9.1.9] Allocating the whole available space. - * - [9.1.10] Testing final conditions. The heap geometry must be the - * same than the one registered at beginning. + * - [9.1.1] Adding the objects to the pool using chPoolLoadArray(). + * - [9.1.2] Emptying the pool using chPoolAlloc(). + * - [9.1.3] Now must be empty. + * - [9.1.4] Adding the objects to the pool using chPoolFree(). + * - [9.1.5] Emptying the pool using chPoolAlloc() again. + * - [9.1.6] Now must be empty again. + * - [9.1.7] Covering the case where a provider is unable to return + * more memory. * . */ static void test_009_001_setup(void) { - chHeapObjectInit(&test_heap, myheap, sizeof(myheap)); + chPoolObjectInit(&mp1, sizeof (uint32_t), NULL); } static void test_009_001_execute(void) { - void *p1, *p2, *p3; - size_t n, sz; + unsigned i; - /* [9.1.1] Testing initial conditions, the heap must not be - fragmented and one free block present.*/ + /* [9.1.1] Adding the objects to the pool using chPoolLoadArray().*/ test_set_step(1); { - test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented"); + chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE); } - /* [9.1.2] Trying to allocate an block bigger than available space, - an error is expected.*/ + /* [9.1.2] Emptying the pool using chPoolAlloc().*/ test_set_step(2); { - p1 = chHeapAlloc(&test_heap, HEAP_SIZE * 2); - test_assert(p1 == NULL, "allocation not failed"); + for (i = 0; i < MEMORY_POOL_SIZE; i++) + test_assert(chPoolAlloc(&mp1) != NULL, "list empty"); } - /* [9.1.3] Single block allocation using chHeapAlloc() then the block - is freed using chHeapFree(), must not fail.*/ + /* [9.1.3] Now must be empty.*/ test_set_step(3); { - p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); - test_assert(p1 != NULL, "allocation failed"); - chHeapFree(p1); + test_assert(chPoolAlloc(&mp1) == NULL, "list not empty"); } - /* [9.1.4] Using chHeapStatus() to assess the heap state. There must - be at least one free block of sufficient size.*/ + /* [9.1.4] Adding the objects to the pool using chPoolFree().*/ test_set_step(4); { - size_t total_size, largest_size; - - n = chHeapStatus(&test_heap, &total_size, &largest_size); - test_assert(n == 1, "missing free block"); - test_assert(total_size >= ALLOC_SIZE, "unexpected heap state"); - test_assert(total_size == largest_size, "unexpected heap state"); + for (i = 0; i < MEMORY_POOL_SIZE; i++) + chPoolFree(&mp1, &objects[i]); } - /* [9.1.5] Allocating then freeing in the same order.*/ + /* [9.1.5] Emptying the pool using chPoolAlloc() again.*/ test_set_step(5); { - p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); - p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); - p3 = chHeapAlloc(&test_heap, ALLOC_SIZE); - chHeapFree(p1); /* Does not merge.*/ - chHeapFree(p2); /* Merges backward.*/ - chHeapFree(p3); /* Merges both sides.*/ - test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + for (i = 0; i < MEMORY_POOL_SIZE; i++) + test_assert(chPoolAlloc(&mp1) != NULL, "list empty"); } - /* [9.1.6] Allocating then freeing in reverse order.*/ + /* [9.1.6] Now must be empty again.*/ test_set_step(6); { - p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); - p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); - p3 = chHeapAlloc(&test_heap, ALLOC_SIZE); - chHeapFree(p3); /* Merges forward.*/ - chHeapFree(p2); /* Merges forward.*/ - chHeapFree(p1); /* Merges forward.*/ - test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + test_assert(chPoolAlloc(&mp1) == NULL, "list not empty"); } - /* [9.1.7] Small fragments handling. Checking the behavior when - allocating blocks with size not multiple of alignment unit.*/ + /* [9.1.7] Covering the case where a provider is unable to return + more memory.*/ test_set_step(7); { - p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1); - p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); - chHeapFree(p1); - test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state"); - p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); - /* Note, the first situation happens when the alignment size is smaller - than the header size, the second in the other cases.*/ - test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) || - (chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented"); - chHeapFree(p2); - chHeapFree(p1); - test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); - } - - /* [9.1.8] Skipping a fragment, the first fragment in the list is too - small so the allocator must pick the second one.*/ - test_set_step(8); - { - p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); - p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); - chHeapFree(p1); - test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state"); - p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/ - chHeapFree(p1); - chHeapFree(p2); - test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); - } - - /* [9.1.9] Allocating the whole available space.*/ - test_set_step(9); - { - (void)chHeapStatus(&test_heap, &n, NULL); - p1 = chHeapAlloc(&test_heap, n); - test_assert(p1 != NULL, "allocation failed"); - test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty"); - chHeapFree(p1); - } - - /* [9.1.10] Testing final conditions. The heap geometry must be the - same than the one registered at beginning.*/ - test_set_step(10); - { - test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); - test_assert(n == sz, "size changed"); + chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider); + test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory"); } } static const testcase_t test_009_001 = { - "Allocation and fragmentation", + "Loading and emptying a memory pool", test_009_001_setup, NULL, test_009_001_execute }; +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) /** - * @page test_009_002 [9.2] Default Heap + * @page test_009_002 [9.2] Loading and emptying a guarded memory pool without waiting * *

Description

- * The default heap is pre-allocated in the system. We test base - * functionality. + * The memory pool functionality is tested by loading and emptying it, + * all conditions are tested. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . * *

Test Steps

- * - [9.2.1] Single block allocation using chHeapAlloc() then the block - * is freed using chHeapFree(), must not fail. - * - [9.2.2] Testing allocation failure. + * - [9.2.1] Adding the objects to the pool using + * chGuardedPoolLoadArray(). + * - [9.2.2] Emptying the pool using chGuardedPoolAllocTimeout(). + * - [9.2.3] Now must be empty. + * - [9.2.4] Adding the objects to the pool using chGuardedPoolFree(). + * - [9.2.5] Emptying the pool using chGuardedPoolAllocTimeout() again. + * - [9.2.6] Now must be empty again. * . */ +static void test_009_002_setup(void) { + chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t)); +} + static void test_009_002_execute(void) { - void *p1; - size_t total_size, largest_size; + unsigned i; - /* [9.2.1] Single block allocation using chHeapAlloc() then the block - is freed using chHeapFree(), must not fail.*/ + /* [9.2.1] Adding the objects to the pool using + chGuardedPoolLoadArray().*/ test_set_step(1); { - (void)chHeapStatus(NULL, &total_size, &largest_size); - p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); - test_assert(p1 != NULL, "allocation failed"); - chHeapFree(p1); + chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE); } - /* [9.2.2] Testing allocation failure.*/ + /* [9.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/ test_set_step(2); { - p1 = chHeapAlloc(NULL, (size_t)-256); - test_assert(p1 == NULL, "allocation not failed"); + for (i = 0; i < MEMORY_POOL_SIZE; i++) + test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty"); + } + + /* [9.2.3] Now must be empty.*/ + test_set_step(3); + { + test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty"); + } + + /* [9.2.4] Adding the objects to the pool using + chGuardedPoolFree().*/ + test_set_step(4); + { + for (i = 0; i < MEMORY_POOL_SIZE; i++) + chGuardedPoolFree(&gmp1, &objects[i]); + } + + /* [9.2.5] Emptying the pool using chGuardedPoolAllocTimeout() + again.*/ + test_set_step(5); + { + for (i = 0; i < MEMORY_POOL_SIZE; i++) + test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty"); + } + + /* [9.2.6] Now must be empty again.*/ + test_set_step(6); + { + test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty"); } } static const testcase_t test_009_002 = { - "Default Heap", - NULL, + "Loading and emptying a guarded memory pool without waiting", + test_009_002_setup, NULL, test_009_002_execute }; +#endif /* CH_CFG_USE_SEMAPHORES */ + +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) +/** + * @page test_009_003 [9.3] Guarded Memory Pools timeout + * + *

Description

+ * The timeout features for the Guarded Memory Pools is tested. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . + * + *

Test Steps

+ * - [9.3.1] Trying to allocate with 100mS timeout, must fail because + * the pool is empty. + * . + */ + +static void test_009_003_setup(void) { + chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t)); +} + +static void test_009_003_execute(void) { + + /* [9.3.1] Trying to allocate with 100mS timeout, must fail because + the pool is empty.*/ + test_set_step(1); + { + test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty"); + } +} + +static const testcase_t test_009_003 = { + "Guarded Memory Pools timeout", + test_009_003_setup, + NULL, + test_009_003_execute +}; +#endif /* CH_CFG_USE_SEMAPHORES */ /**************************************************************************** * Exported data. ****************************************************************************/ /** - * @brief Memory Heaps. + * @brief Memory Pools. */ const testcase_t * const test_sequence_009[] = { &test_009_001, +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) &test_009_002, +#endif +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) + &test_009_003, +#endif NULL }; -#endif /* CH_CFG_USE_HEAP */ +#endif /* CH_CFG_USE_MEMPOOLS */ diff --git a/test/rt/source/test/test_sequence_010.c b/test/rt/source/test/test_sequence_010.c new file mode 100644 index 000000000..dc76be9cc --- /dev/null +++ b/test/rt/source/test/test_sequence_010.c @@ -0,0 +1,270 @@ +/* + 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 "hal.h" +#include "ch_test.h" +#include "test_root.h" + +/** + * @page test_sequence_010 [10] Memory Heaps + * + * File: @ref test_sequence_010.c + * + *

Description

+ * This sequence tests the ChibiOS/RT functionalities related to memory + * heaps. + * + *

Conditions

+ * This sequence is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_HEAP + * . + * + *

Test Cases

+ * - @subpage test_010_001 + * - @subpage test_010_002 + * . + */ + +#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__) + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +#define ALLOC_SIZE 16 +#define HEAP_SIZE (ALLOC_SIZE * 8) + +static memory_heap_t test_heap; +static CH_HEAP_AREA(myheap, HEAP_SIZE); + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +/** + * @page test_010_001 [10.1] Allocation and fragmentation + * + *

Description

+ * Series of allocations/deallocations are performed in carefully + * designed sequences in order to stimulate all the possible code paths + * inside the allocator. The test expects to find the heap back to the + * initial status after each sequence. + * + *

Test Steps

+ * - [10.1.1] Testing initial conditions, the heap must not be + * fragmented and one free block present. + * - [10.1.2] Trying to allocate an block bigger than available space, + * an error is expected. + * - [10.1.3] Single block allocation using chHeapAlloc() then the + * block is freed using chHeapFree(), must not fail. + * - [10.1.4] Using chHeapStatus() to assess the heap state. There must + * be at least one free block of sufficient size. + * - [10.1.5] Allocating then freeing in the same order. + * - [10.1.6] Allocating then freeing in reverse order. + * - [10.1.7] Small fragments handling. Checking the behavior when + * allocating blocks with size not multiple of alignment unit. + * - [10.1.8] Skipping a fragment, the first fragment in the list is + * too small so the allocator must pick the second one. + * - [10.1.9] Allocating the whole available space. + * - [10.1.10] Testing final conditions. The heap geometry must be the + * same than the one registered at beginning. + * . + */ + +static void test_010_001_setup(void) { + chHeapObjectInit(&test_heap, myheap, sizeof(myheap)); +} + +static void test_010_001_execute(void) { + void *p1, *p2, *p3; + size_t n, sz; + + /* [10.1.1] Testing initial conditions, the heap must not be + fragmented and one free block present.*/ + test_set_step(1); + { + test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented"); + } + + /* [10.1.2] Trying to allocate an block bigger than available space, + an error is expected.*/ + test_set_step(2); + { + p1 = chHeapAlloc(&test_heap, HEAP_SIZE * 2); + test_assert(p1 == NULL, "allocation not failed"); + } + + /* [10.1.3] Single block allocation using chHeapAlloc() then the + block is freed using chHeapFree(), must not fail.*/ + test_set_step(3); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + test_assert(p1 != NULL, "allocation failed"); + chHeapFree(p1); + } + + /* [10.1.4] Using chHeapStatus() to assess the heap state. There must + be at least one free block of sufficient size.*/ + test_set_step(4); + { + size_t total_size, largest_size; + + n = chHeapStatus(&test_heap, &total_size, &largest_size); + test_assert(n == 1, "missing free block"); + test_assert(total_size >= ALLOC_SIZE, "unexpected heap state"); + test_assert(total_size == largest_size, "unexpected heap state"); + } + + /* [10.1.5] Allocating then freeing in the same order.*/ + test_set_step(5); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p3 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p1); /* Does not merge.*/ + chHeapFree(p2); /* Merges backward.*/ + chHeapFree(p3); /* Merges both sides.*/ + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* [10.1.6] Allocating then freeing in reverse order.*/ + test_set_step(6); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p3 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p3); /* Merges forward.*/ + chHeapFree(p2); /* Merges forward.*/ + chHeapFree(p1); /* Merges forward.*/ + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* [10.1.7] Small fragments handling. Checking the behavior when + allocating blocks with size not multiple of alignment unit.*/ + test_set_step(7); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p1); + test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state"); + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + /* Note, the first situation happens when the alignment size is smaller + than the header size, the second in the other cases.*/ + test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) || + (chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented"); + chHeapFree(p2); + chHeapFree(p1); + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* [10.1.8] Skipping a fragment, the first fragment in the list is + too small so the allocator must pick the second one.*/ + test_set_step(8); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p1); + test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state"); + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/ + chHeapFree(p1); + chHeapFree(p2); + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* [10.1.9] Allocating the whole available space.*/ + test_set_step(9); + { + (void)chHeapStatus(&test_heap, &n, NULL); + p1 = chHeapAlloc(&test_heap, n); + test_assert(p1 != NULL, "allocation failed"); + test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty"); + chHeapFree(p1); + } + + /* [10.1.10] Testing final conditions. The heap geometry must be the + same than the one registered at beginning.*/ + test_set_step(10); + { + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + test_assert(n == sz, "size changed"); + } +} + +static const testcase_t test_010_001 = { + "Allocation and fragmentation", + test_010_001_setup, + NULL, + test_010_001_execute +}; + +/** + * @page test_010_002 [10.2] Default Heap + * + *

Description

+ * The default heap is pre-allocated in the system. We test base + * functionality. + * + *

Test Steps

+ * - [10.2.1] Single block allocation using chHeapAlloc() then the + * block is freed using chHeapFree(), must not fail. + * - [10.2.2] Testing allocation failure. + * . + */ + +static void test_010_002_execute(void) { + void *p1; + size_t total_size, largest_size; + + /* [10.2.1] Single block allocation using chHeapAlloc() then the + block is freed using chHeapFree(), must not fail.*/ + test_set_step(1); + { + (void)chHeapStatus(NULL, &total_size, &largest_size); + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + test_assert(p1 != NULL, "allocation failed"); + chHeapFree(p1); + } + + /* [10.2.2] Testing allocation failure.*/ + test_set_step(2); + { + p1 = chHeapAlloc(NULL, (size_t)-256); + test_assert(p1 == NULL, "allocation not failed"); + } +} + +static const testcase_t test_010_002 = { + "Default Heap", + NULL, + NULL, + test_010_002_execute +}; + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Memory Heaps. + */ +const testcase_t * const test_sequence_010[] = { + &test_010_001, + &test_010_002, + NULL +}; + +#endif /* CH_CFG_USE_HEAP */ diff --git a/test/rt/source/test/test_sequence_010.h b/test/rt/source/test/test_sequence_010.h new file mode 100644 index 000000000..b20e4a5cd --- /dev/null +++ b/test/rt/source/test/test_sequence_010.h @@ -0,0 +1,17 @@ +/* + 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. +*/ + +extern const testcase_t * const test_sequence_010[]; diff --git a/test/rt/test.mk b/test/rt/test.mk index d2afbaf36..2afe2ce8d 100644 --- a/test/rt/test.mk +++ b/test/rt/test.mk @@ -9,7 +9,8 @@ TESTSRC = ${CHIBIOS}/test/lib/ch_test.c \ ${CHIBIOS}/test/rt/source/test/test_sequence_006.c \ ${CHIBIOS}/test/rt/source/test/test_sequence_007.c \ ${CHIBIOS}/test/rt/source/test/test_sequence_008.c \ - ${CHIBIOS}/test/rt/source/test/test_sequence_009.c + ${CHIBIOS}/test/rt/source/test/test_sequence_009.c \ + ${CHIBIOS}/test/rt/source/test/test_sequence_010.c # Required include directories TESTINC = ${CHIBIOS}/test/lib \ -- cgit v1.2.3