diff --git a/test/rt/configuration.xml b/test/rt/configuration.xml index f155ab19e..e8f20ed4e 100644 --- a/test/rt/configuration.xml +++ b/test/rt/configuration.xml @@ -1141,7 +1141,7 @@ test_assert_sequence("A", "invalid sequence");]]> - + @@ -1688,7 +1688,7 @@ Thread A performs wait(50), lock(m1), unlock(m1), exit. Thread B performs wait(1 chMtxObjectInit(&m2);]]> - + @@ -2071,7 +2071,7 @@ The test expects the threads to reach their goal in increasing priority order re - @@ -2090,11 +2090,11 @@ chMtxObjectInit(&m1);]]> - @@ -2106,15 +2106,15 @@ threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread6, "A");]]> - @@ -2133,8 +2133,9 @@ The test expects the threads to reach their goal in increasing priority order re - + @@ -2152,11 +2153,11 @@ chMtxObjectInit(&m1);]]> - @@ -2168,8 +2169,8 @@ threads[4] = chThdCreateStatic(wa[4], WA_SIZE, prio+5, thread8, "A");]]> - @@ -2177,6 +2178,89 @@ test_assert_sequence("ABCDE", "invalid sequence");]]> + + + Internal Tests + + + Synchronous Messages. + + + This module implements the test sequence for the Synchronous Messages subsystem. + + + CH_CFG_USE_MESSAGES + + + + + + + + Messages Server loop. + + + A messenger thread is spawned that sends four messages back to the tester thread.<br> +The test expect to receive the messages in the correct sequence and to not find a fifth message waiting. + + + + + + + + + + + + + + + + + + + Starting the messenger thread. + + + + + + + + + + + Waiting for four messages then testing the receive order. + + + + + + + + + + + + Internal Tests diff --git a/test/rt/source/test/test_root.c b/test/rt/source/test/test_root.c index d9aa0a8f2..796af8fbb 100644 --- a/test/rt/source/test/test_root.c +++ b/test/rt/source/test/test_root.c @@ -29,6 +29,7 @@ * - @subpage test_sequence_006 * - @subpage test_sequence_007 * - @subpage test_sequence_008 + * - @subpage test_sequence_009 * . */ @@ -59,6 +60,7 @@ const testcase_t * const *test_suite[] = { test_sequence_006, test_sequence_007, test_sequence_008, + test_sequence_009, NULL }; diff --git a/test/rt/source/test/test_root.h b/test/rt/source/test/test_root.h index e167ecc7b..114bfd9bf 100644 --- a/test/rt/source/test/test_root.h +++ b/test/rt/source/test/test_root.h @@ -30,6 +30,7 @@ #include "test_sequence_006.h" #include "test_sequence_007.h" #include "test_sequence_008.h" +#include "test_sequence_009.h" #if !defined(__DOXYGEN__) diff --git a/test/rt/source/test/test_sequence_004.c b/test/rt/source/test/test_sequence_004.c index 0be4f03fb..e4d29ff3b 100644 --- a/test/rt/source/test/test_sequence_004.c +++ b/test/rt/source/test/test_sequence_004.c @@ -353,6 +353,10 @@ static void test_004_005_setup(void) { chSemObjectInit(&sem1, 0); } +static void test_004_005_teardown(void) { + test_wait_threads(); +} + static void test_004_005_execute(void) { /* [4.5.1] An higher priority thread is created that performs @@ -386,7 +390,7 @@ static void test_004_005_execute(void) { static const testcase_t test_004_005 = { "Testing chSemWaitSignal() functionality", test_004_005_setup, - NULL, + test_004_005_teardown, test_004_005_execute }; diff --git a/test/rt/source/test/test_sequence_005.c b/test/rt/source/test/test_sequence_005.c index d5eb89546..1d67f07ea 100644 --- a/test/rt/source/test/test_sequence_005.c +++ b/test/rt/source/test/test_sequence_005.c @@ -452,6 +452,10 @@ static void test_005_004_setup(void) { chMtxObjectInit(&m2); } +static void test_005_004_teardown(void) { + test_wait_threads(); +} + static void test_005_004_execute(void) { tprio_t p, pa, pb; @@ -525,7 +529,7 @@ static void test_005_004_execute(void) { static const testcase_t test_005_004 = { "Priority return verification", test_005_004_setup, - NULL, + test_005_004_teardown, test_005_004_execute }; @@ -865,6 +869,7 @@ static const testcase_t test_005_007 = { static void test_005_008_setup(void) { chCondObjectInit(&c1); chMtxObjectInit(&m1); + chMtxObjectInit(&m2); } static void test_005_008_execute(void) { diff --git a/test/rt/source/test/test_sequence_006.c b/test/rt/source/test/test_sequence_006.c index cba9cbf9c..b44ab02ae 100644 --- a/test/rt/source/test/test_sequence_006.c +++ b/test/rt/source/test/test_sequence_006.c @@ -19,369 +19,102 @@ #include "test_root.h" /** - * @page test_sequence_006 [6] Mailboxes + * @page test_sequence_006 [6] Synchronous Messages * * File: @ref test_sequence_006.c * *

Description

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

Conditions

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

Test Cases

* - @subpage test_006_001 - * - @subpage test_006_002 - * - @subpage test_006_003 * . */ -#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__) +#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) /**************************************************************************** * Shared code. ****************************************************************************/ -#define MB_SIZE 4 +static THD_FUNCTION(msg_thread1, p) { -static msg_t mb_buffer[MB_SIZE]; -static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE); + chMsgSend(p, 'A'); + chMsgSend(p, 'B'); + chMsgSend(p, 'C'); + chMsgSend(p, 'D'); +} /**************************************************************************** * Test cases. ****************************************************************************/ /** - * @page test_006_001 [6.1] Mailbox normal API, non-blocking tests + * @page test_006_001 [6.1] Messages Server loop * *

Description

- * The mailbox normal API is tested without triggering blocking - * conditions. + * A messenger thread is spawned that sends four messages back to the + * tester thread.
The test expect to receive the messages in the + * correct sequence and to not find a fifth message waiting. * *

Test Steps

- * - [6.1.1] Testing the mailbox size. - * - [6.1.2] Resetting the mailbox, conditions are checked, no errors - * expected. - * - [6.1.3] Filling the mailbox using chMBPost() and chMBPostAhead() - * once, no errors expected. - * - [6.1.4] Testing intermediate conditions. Data pointers must be - * aligned, semaphore counters are checked. - * - [6.1.5] Emptying the mailbox using chMBFetch(), no errors - * expected. - * - [6.1.6] Posting and then fetching one more message, no errors - * expected. - * - [6.1.7] Testing final conditions. Data pointers must be aligned to - * buffer start, semaphore counters are checked. + * - [6.1.1] Starting the messenger thread. + * - [6.1.2] Waiting for four messages then testing the receive order. * . */ -static void test_006_001_setup(void) { - chMBObjectInit(&mb1, mb_buffer, MB_SIZE); -} - -static void test_006_001_teardown(void) { - chMBReset(&mb1); -} - static void test_006_001_execute(void) { - msg_t msg1, msg2; - unsigned i; + thread_t *tp; + msg_t msg; - /* [6.1.1] Testing the mailbox size.*/ + /* [6.1.1] Starting the messenger thread.*/ test_set_step(1); { - test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size"); + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() + 1, + msg_thread1, chThdGetSelfX()); } - /* [6.1.2] Resetting the mailbox, conditions are checked, no errors - expected.*/ + /* [6.1.2] Waiting for four messages then testing the receive + order.*/ 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"); - } + unsigned i; - /* [6.1.3] Filling the mailbox using chMBPost() and chMBPostAhead() - once, no errors expected.*/ - 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"); + for (i = 0; i < 4; i++) { + tp = chMsgWait(); + msg = chMsgGet(tp); + chMsgRelease(tp, msg); + test_emit_token(msg); } - msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE); - test_assert(msg1 == MSG_OK, "wrong wake-up message"); - } - - /* [6.1.4] Testing intermediate conditions. Data pointers must be - aligned, semaphore counters are checked.*/ - 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"); - } - - /* [6.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"); - } - - /* [6.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"); - } - - /* [6.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"); + test_wait_threads(); + test_assert_sequence("ABCD", "invalid sequence"); } } static const testcase_t test_006_001 = { - "Mailbox normal API, non-blocking tests", - test_006_001_setup, - test_006_001_teardown, + "Messages Server loop", + NULL, + NULL, test_006_001_execute }; -/** - * @page test_006_002 [6.2] Mailbox I-Class API, non-blocking tests - * - *

Description

- * The mailbox I-Class API is tested without triggering blocking - * conditions. - * - *

Test Steps

- * - [6.2.1] Testing the mailbox size. - * - [6.2.2] Resetting the mailbox, conditions are checked, no errors - * expected. - * - [6.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI() - * once, no errors expected. - * - [6.2.4] Testing intermediate conditions. Data pointers must be - * aligned, semaphore counters are checked. - * - [6.2.5] Emptying the mailbox using chMBFetchI(), no errors - * expected. - * - [6.2.6] Posting and then fetching one more message, no errors - * expected. - * - [6.2.7] Testing final conditions. Data pointers must be aligned to - * buffer start, semaphore counters are checked. - * . - */ - -static void test_006_002_setup(void) { - chMBObjectInit(&mb1, mb_buffer, MB_SIZE); -} - -static void test_006_002_teardown(void) { - chMBReset(&mb1); -} - -static void test_006_002_execute(void) { - msg_t msg1, msg2; - unsigned i; - - /* [6.2.1] Testing the mailbox size.*/ - test_set_step(1); - { - test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size"); - } - - /* [6.2.2] Resetting the mailbox, conditions are checked, no errors - expected.*/ - 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"); - } - - /* [6.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI() - once, no errors expected.*/ - 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"); - } - - /* [6.2.4] Testing intermediate conditions. Data pointers must be - aligned, semaphore counters are checked.*/ - 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"); - } - - /* [6.2.5] Emptying the mailbox using chMBFetchI(), no errors - expected.*/ - test_set_step(5); - { - 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"); - } - - /* [6.2.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"); - } - - /* [6.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_006_002 = { - "Mailbox I-Class API, non-blocking tests", - test_006_002_setup, - test_006_002_teardown, - test_006_002_execute -}; - -/** - * @page test_006_003 [6.3] Mailbox timeouts - * - *

Description

- * The mailbox API is tested for timeouts. - * - *

Test Steps

- * - [6.3.1] Filling the mailbox. - * - [6.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and - * chMBPostAheadI() timeout. - * - [6.3.3] Resetting the mailbox. - * - [6.3.4] Testing chMBFetch() and chMBFetchI() timeout. - * . - */ - -static void test_006_003_setup(void) { - chMBObjectInit(&mb1, mb_buffer, MB_SIZE); -} - -static void test_006_003_teardown(void) { - chMBReset(&mb1); -} - -static void test_006_003_execute(void) { - msg_t msg1, msg2; - unsigned i; - - /* [6.3.1] Filling the mailbox.*/ - 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"); - } - } - - /* [6.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"); - } - - /* [6.3.3] Resetting the mailbox.*/ - test_set_step(3); - { - chMBReset(&mb1); - } - - /* [6.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_006_003 = { - "Mailbox timeouts", - test_006_003_setup, - test_006_003_teardown, - test_006_003_execute -}; - /**************************************************************************** * Exported data. ****************************************************************************/ /** - * @brief Mailboxes. + * @brief Synchronous Messages. */ const testcase_t * const test_sequence_006[] = { &test_006_001, - &test_006_002, - &test_006_003, NULL }; -#endif /* CH_CFG_USE_MAILBOXES */ +#endif /* CH_CFG_USE_MESSAGES */ diff --git a/test/rt/source/test/test_sequence_007.c b/test/rt/source/test/test_sequence_007.c index a1cd8039d..9563965fb 100644 --- a/test/rt/source/test/test_sequence_007.c +++ b/test/rt/source/test/test_sequence_007.c @@ -19,18 +19,18 @@ #include "test_root.h" /** - * @page test_sequence_007 [7] Memory Pools + * @page test_sequence_007 [7] Mailboxes * * File: @ref test_sequence_007.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_007_001 [7.1] Loading and emptying a memory pool + * @page test_007_001 [7.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

- * - [7.1.1] Adding the objects to the pool using chPoolLoadArray(). - * - [7.1.2] Emptying the pool using chPoolAlloc(). - * - [7.1.3] Now must be empty. - * - [7.1.4] Adding the objects to the pool using chPoolFree(). - * - [7.1.5] Emptying the pool using chPoolAlloc() again. - * - [7.1.6] Now must be empty again. - * - [7.1.7] Covering the case where a provider is unable to return - * more memory. + * - [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. * . */ static void test_007_001_setup(void) { - chPoolObjectInit(&mp1, sizeof (uint32_t), NULL); + 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; - /* [7.1.1] Adding the objects to the pool using chPoolLoadArray().*/ + /* [7.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"); } - /* [7.1.2] Emptying the pool using chPoolAlloc().*/ + /* [7.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"); } - /* [7.1.3] Now must be empty.*/ + /* [7.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"); } - /* [7.1.4] Adding the objects to the pool using chPoolFree().*/ + /* [7.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"); } - /* [7.1.5] Emptying the pool using chPoolAlloc() again.*/ + /* [7.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"); } - /* [7.1.6] Now must be empty again.*/ + /* [7.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"); } - /* [7.1.7] Covering the case where a provider is unable to return - more memory.*/ + /* [7.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_007_001 = { - "Loading and emptying a memory pool", + "Mailbox normal API, non-blocking tests", test_007_001_setup, - NULL, + test_007_001_teardown, test_007_001_execute }; -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) /** - * @page test_007_002 [7.2] Loading and emptying a guarded memory pool without waiting + * @page test_007_002 [7.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

- * - [7.2.1] Adding the objects to the pool using - * chGuardedPoolLoadArray(). - * - [7.2.2] Emptying the pool using chGuardedPoolAllocTimeout(). - * - [7.2.3] Now must be empty. - * - [7.2.4] Adding the objects to the pool using chGuardedPoolFree(). - * - [7.2.5] Emptying the pool using chGuardedPoolAllocTimeout() again. - * - [7.2.6] Now must be empty again. + * - [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. * . */ static void test_007_002_setup(void) { - chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t)); + chMBObjectInit(&mb1, mb_buffer, MB_SIZE); +} + +static void test_007_002_teardown(void) { + chMBReset(&mb1); } static void test_007_002_execute(void) { + msg_t msg1, msg2; unsigned i; - /* [7.2.1] Adding the objects to the pool using - chGuardedPoolLoadArray().*/ + /* [7.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"); } - /* [7.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/ + /* [7.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"); } - /* [7.2.3] Now must be empty.*/ + /* [7.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"); } - /* [7.2.4] Adding the objects to the pool using - chGuardedPoolFree().*/ + /* [7.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"); } - /* [7.2.5] Emptying the pool using chGuardedPoolAllocTimeout() - again.*/ + /* [7.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"); } - /* [7.2.6] Now must be empty again.*/ + /* [7.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"); + } + + /* [7.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_007_002 = { - "Loading and emptying a guarded memory pool without waiting", + "Mailbox I-Class API, non-blocking tests", test_007_002_setup, - NULL, + test_007_002_teardown, test_007_002_execute }; -#endif /* CH_CFG_USE_SEMAPHORES */ -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) /** - * @page test_007_003 [7.3] Guarded Memory Pools timeout + * @page test_007_003 [7.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

- * - [7.3.1] Trying to allocate with 100mS timeout, must fail because - * the pool is empty. + * - [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. * . */ static void test_007_003_setup(void) { - chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t)); + chMBObjectInit(&mb1, mb_buffer, MB_SIZE); +} + +static void test_007_003_teardown(void) { + chMBReset(&mb1); } static void test_007_003_execute(void) { + msg_t msg1, msg2; + unsigned i; - /* [7.3.1] Trying to allocate with 100mS timeout, must fail because - the pool is empty.*/ + /* [7.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"); + } + } + + /* [7.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"); + } + + /* [7.3.3] Resetting the mailbox.*/ + test_set_step(3); + { + chMBReset(&mb1); + } + + /* [7.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_007_003 = { - "Guarded Memory Pools timeout", + "Mailbox timeouts", test_007_003_setup, - NULL, + test_007_003_teardown, test_007_003_execute }; -#endif /* CH_CFG_USE_SEMAPHORES */ /**************************************************************************** * Exported data. ****************************************************************************/ /** - * @brief Memory Pools. + * @brief Mailboxes. */ const testcase_t * const test_sequence_007[] = { &test_007_001, -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) &test_007_002, -#endif -#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) &test_007_003, -#endif NULL }; -#endif /* CH_CFG_USE_MEMPOOLS */ +#endif /* CH_CFG_USE_MAILBOXES */ diff --git a/test/rt/source/test/test_sequence_008.c b/test/rt/source/test/test_sequence_008.c index 8f9f5ff0f..6e9c05f1c 100644 --- a/test/rt/source/test/test_sequence_008.c +++ b/test/rt/source/test/test_sequence_008.c @@ -19,252 +19,272 @@ #include "test_root.h" /** - * @page test_sequence_008 [8] Memory Heaps + * @page test_sequence_008 [8] Memory Pools * * File: @ref test_sequence_008.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_008_001 * - @subpage test_008_002 + * - @subpage test_008_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_008_001 [8.1] Allocation and fragmentation + * @page test_008_001 [8.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

- * - [8.1.1] Testing initial conditions, the heap must not be - * fragmented and one free block present. - * - [8.1.2] Trying to allocate an block bigger than available space, - * an error is expected. - * - [8.1.3] Single block allocation using chHeapAlloc() then the block - * is freed using chHeapFree(), must not fail. - * - [8.1.4] Using chHeapStatus() to assess the heap state. There must - * be at least one free block of sufficient size. - * - [8.1.5] Allocating then freeing in the same order. - * - [8.1.6] Allocating then freeing in reverse order. - * - [8.1.7] Small fragments handling. Checking the behavior when - * allocating blocks with size not multiple of alignment unit. - * - [8.1.8] Skipping a fragment, the first fragment in the list is too - * small so the allocator must pick the second one. - * - [8.1.9] Allocating the whole available space. - * - [8.1.10] Testing final conditions. The heap geometry must be the - * same than the one registered at beginning. + * - [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. * . */ static void test_008_001_setup(void) { - chHeapObjectInit(&test_heap, myheap, sizeof(myheap)); + chPoolObjectInit(&mp1, sizeof (uint32_t), NULL); } static void test_008_001_execute(void) { - void *p1, *p2, *p3; - size_t n, sz; + unsigned i; - /* [8.1.1] Testing initial conditions, the heap must not be - fragmented and one free block present.*/ + /* [8.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); } - /* [8.1.2] Trying to allocate an block bigger than available space, - an error is expected.*/ + /* [8.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"); } - /* [8.1.3] Single block allocation using chHeapAlloc() then the block - is freed using chHeapFree(), must not fail.*/ + /* [8.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"); } - /* [8.1.4] Using chHeapStatus() to assess the heap state. There must - be at least one free block of sufficient size.*/ + /* [8.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]); } - /* [8.1.5] Allocating then freeing in the same order.*/ + /* [8.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"); } - /* [8.1.6] Allocating then freeing in reverse order.*/ + /* [8.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"); } - /* [8.1.7] Small fragments handling. Checking the behavior when - allocating blocks with size not multiple of alignment unit.*/ + /* [8.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"); - } - - /* [8.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"); - } - - /* [8.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); - } - - /* [8.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_008_001 = { - "Allocation and fragmentation", + "Loading and emptying a memory pool", test_008_001_setup, NULL, test_008_001_execute }; +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) /** - * @page test_008_002 [8.2] Default Heap + * @page test_008_002 [8.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

- * - [8.2.1] Single block allocation using chHeapAlloc() then the block - * is freed using chHeapFree(), must not fail. - * - [8.2.2] Testing allocation failure. + * - [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. * . */ -static void test_008_002_execute(void) { - void *p1; - size_t total_size, largest_size; +static void test_008_002_setup(void) { + chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t)); +} - /* [8.2.1] Single block allocation using chHeapAlloc() then the block - is freed using chHeapFree(), must not fail.*/ +static void test_008_002_execute(void) { + unsigned i; + + /* [8.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); } - /* [8.2.2] Testing allocation failure.*/ + /* [8.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"); + } + + /* [8.2.3] Now must be empty.*/ + test_set_step(3); + { + test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty"); + } + + /* [8.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]); + } + + /* [8.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"); + } + + /* [8.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_008_002 = { - "Default Heap", - NULL, + "Loading and emptying a guarded memory pool without waiting", + test_008_002_setup, NULL, 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 + * + *

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

+ * - [8.3.1] Trying to allocate with 100mS timeout, must fail because + * the pool is empty. + * . + */ + +static void test_008_003_setup(void) { + chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t)); +} + +static void test_008_003_execute(void) { + + /* [8.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_008_003 = { + "Guarded Memory Pools timeout", + test_008_003_setup, + NULL, + test_008_003_execute +}; +#endif /* CH_CFG_USE_SEMAPHORES */ /**************************************************************************** * Exported data. ****************************************************************************/ /** - * @brief Memory Heaps. + * @brief Memory Pools. */ 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_HEAP */ +#endif /* CH_CFG_USE_MEMPOOLS */ diff --git a/test/rt/source/test/test_sequence_009.c b/test/rt/source/test/test_sequence_009.c new file mode 100644 index 000000000..b980b828e --- /dev/null +++ b/test/rt/source/test/test_sequence_009.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_009 [9] Memory Heaps + * + * File: @ref test_sequence_009.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_009_001 + * - @subpage test_009_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_009_001 [9.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

+ * - [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. + * . + */ + +static void test_009_001_setup(void) { + chHeapObjectInit(&test_heap, myheap, sizeof(myheap)); +} + +static void test_009_001_execute(void) { + void *p1, *p2, *p3; + size_t n, sz; + + /* [9.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"); + } + + /* [9.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"); + } + + /* [9.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); + } + + /* [9.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"); + } + + /* [9.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"); + } + + /* [9.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"); + } + + /* [9.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"); + } + + /* [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"); + } +} + +static const testcase_t test_009_001 = { + "Allocation and fragmentation", + test_009_001_setup, + NULL, + test_009_001_execute +}; + +/** + * @page test_009_002 [9.2] Default Heap + * + *

Description

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

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. + * . + */ + +static void test_009_002_execute(void) { + void *p1; + size_t total_size, largest_size; + + /* [9.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); + } + + /* [9.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_009_002 = { + "Default Heap", + NULL, + NULL, + test_009_002_execute +}; + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Memory Heaps. + */ +const testcase_t * const test_sequence_009[] = { + &test_009_001, + &test_009_002, + NULL +}; + +#endif /* CH_CFG_USE_HEAP */ diff --git a/test/rt/source/test/test_sequence_009.h b/test/rt/source/test/test_sequence_009.h new file mode 100644 index 000000000..dfe6e9175 --- /dev/null +++ b/test/rt/source/test/test_sequence_009.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_009[]; diff --git a/test/rt/test.mk b/test/rt/test.mk index 026536008..d2afbaf36 100644 --- a/test/rt/test.mk +++ b/test/rt/test.mk @@ -8,7 +8,8 @@ TESTSRC = ${CHIBIOS}/test/lib/ch_test.c \ ${CHIBIOS}/test/rt/source/test/test_sequence_005.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_008.c \ + ${CHIBIOS}/test/rt/source/test/test_sequence_009.c # Required include directories TESTINC = ${CHIBIOS}/test/lib \