diff --git a/readme.txt b/readme.txt index 9fb3876be..e8b31e4b5 100644 --- a/readme.txt +++ b/readme.txt @@ -84,11 +84,11 @@ Win32-MinGW - ChibiOS/RT simulator and demo into a WIN32 process, - FIX: Removed usused list functions (bug 2755230)(backported in stable branch). - NEW: Added a code coverage analysis application under ./tests/coverage. -- Added more test cases in order to improve the test suite code coverage (it - was 74% in version 1.2.0). -- Added a new "naked" context switch benchmark that better defines the - real context switch time, for the STM32 the context switch is performed - under 1.48uS. +- NEW: Added more test cases in order to improve the test suite code coverage + (it was 74% in version 1.2.0). +- NEW: Added a new "naked" context switch benchmark that better defines the + real context switch time, previous benchmarks introduced too much overhead + to the measurement. The STM32 performs the context switch in under 1.48uS. *** 1.2.0 *** - Added license exception text to the 1.2.0 branch. diff --git a/test/testevt.c b/test/testevt.c index 9c6f7bf6e..3987a41e8 100644 --- a/test/testevt.c +++ b/test/testevt.c @@ -29,7 +29,7 @@ static EventSource es1, es2; static char *evt1_gettest(void) { - return "Events, wait and broadcast"; + return "Events, registration and dispatch"; } static void evt1_setup(void) { @@ -37,58 +37,31 @@ static void evt1_setup(void) { chEvtClear(ALL_EVENTS); } -static msg_t thread(void *p) { - - chEvtBroadcast(&es1); - chThdSleepMilliseconds(50); - chEvtBroadcast(&es2); - return 0; -} +static void h1(eventid_t id) {test_emit_token('A');} +static void h2(eventid_t id) {test_emit_token('B');} +static void h3(eventid_t id) {test_emit_token('C');} +static const evhandler_t evhndl[] = {h1, h2, h3}; static void evt1_execute(void) { - eventmask_t m; EventListener el1, el2; - systime_t target_time; /* - * Test on chEvtWaitOne(). - */ - chEvtPend(5); - m = chEvtWaitOne(ALL_EVENTS); - test_assert(m == 1, "#1"); /* Single bit error.*/ - m = chEvtWaitOne(ALL_EVENTS); - test_assert(m == 4, "#2"); /* Single bit error.*/ - m = chEvtClear(0); - test_assert(m == 0, "#3"); /* Stuck event.*/ - - /* - * Test on chEvtWaitAny(). - */ - chEvtPend(5); - m = chEvtWaitAny(ALL_EVENTS); - test_assert(m == 5, "#4"); /* Unexpected pending.*/ - m = chEvtClear(0); - test_assert(m == 0, "#5"); /* Stuck event.*/ - - /* - * Test on chEvtWaitAll(), chEvtRegisterMask() and chEvtUnregister(). + * Testing chEvtRegisterMask() and chEvtUnregister(). */ chEvtInit(&es1); - chEvtInit(&es2); chEvtRegisterMask(&es1, &el1, 1); - chEvtRegisterMask(&es2, &el2, 4); - target_time = chTimeNow() + MS2ST(50); - threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()-1, thread, "A"); - m = chEvtWaitAll(5); - test_assert_time_window(target_time, target_time + ALLOWED_DELAY); - m = chEvtClear(0); - test_assert(m == 0, "#6"); /* Stuck event.*/ - - test_wait_threads(); + chEvtRegisterMask(&es1, &el2, 2); + test_assert(chEvtIsListening(&es1), "#1"); /* Must not be empty */ chEvtUnregister(&es1, &el1); - chEvtUnregister(&es2, &el2); - test_assert(!chEvtIsListening(&es1), "#7"); /* Stuck listener.*/ - test_assert(!chEvtIsListening(&es2), "#8"); /* Stuck listener.*/ + test_assert(chEvtIsListening(&es1), "#2"); /* Must not be empty */ + chEvtUnregister(&es1, &el2); + test_assert(!chEvtIsListening(&es1), "#3"); /* Stuck listener.*/ + + /* + * Testing chEvtDispatch(). + */ + chEvtDispatch(evhndl, 7); + test_assert_sequence("ABC"); } const struct testcase testevt1 = { @@ -98,6 +71,152 @@ const struct testcase testevt1 = { evt1_execute }; +static char *evt2_gettest(void) { + + return "Events, wait and broadcast"; +} + +static void evt2_setup(void) { + + chEvtClear(ALL_EVENTS); +} + +static msg_t thread1(void *p) { + + chThdSleepMilliseconds(50); + chEvtSignal((Thread *)p, 1); + return 0; +} + +static msg_t thread2(void *p) { + + chEvtBroadcast(&es1); + chThdSleepMilliseconds(50); + chEvtBroadcast(&es2); + return 0; +} + +static void evt2_execute(void) { + eventmask_t m; + EventListener el1, el2; + systime_t target_time; + + /* + * Test on chEvtWaitOne() without wait. + */ + chEvtPend(5); + m = chEvtWaitOne(ALL_EVENTS); + test_assert(m == 1, "#1"); /* Single bit error.*/ + m = chEvtWaitOne(ALL_EVENTS); + test_assert(m == 4, "#2"); /* Single bit error.*/ + m = chEvtClear(0); + test_assert(m == 0, "#3"); /* Stuck bit.*/ + + /* + * Test on chEvtWaitOne() with wait. + */ + test_wait_tick(); + target_time = chTimeNow() + MS2ST(50); + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority() - 1, + thread1, chThdSelf()); + m = chEvtWaitOne(ALL_EVENTS); + test_assert_time_window(target_time, target_time + ALLOWED_DELAY); + test_assert(m == 1, "#5"); /* Single bit error.*/ + m = chEvtClear(0); + test_assert(m == 0, "#6"); /* Stuck bit.*/ + test_wait_threads(); + + /* + * Test on chEvtWaitAny() without wait. + */ + chEvtPend(5); + m = chEvtWaitAny(ALL_EVENTS); + test_assert(m == 5, "#7"); /* Unexpected pending bit.*/ + m = chEvtClear(0); + test_assert(m == 0, "#8"); /* Stuck bit.*/ + + /* + * Test on chEvtWaitAny() with wait. + */ + test_wait_tick(); + target_time = chTimeNow() + MS2ST(50); + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority() - 1, + thread1, chThdSelf()); + m = chEvtWaitAny(ALL_EVENTS); + test_assert_time_window(target_time, target_time + ALLOWED_DELAY); + test_assert(m == 1, "#9"); /* Single bit error.*/ + m = chEvtClear(0); + test_assert(m == 0, "#10"); /* Stuck bit.*/ + test_wait_threads(); + + /* + * Test on chEvtWaitAll(). + */ + chEvtInit(&es1); + chEvtInit(&es2); + chEvtRegisterMask(&es1, &el1, 1); + chEvtRegisterMask(&es2, &el2, 4); + test_wait_tick(); + target_time = chTimeNow() + MS2ST(50); + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority() - 1, + thread2, "A"); + m = chEvtWaitAll(5); + test_assert_time_window(target_time, target_time + ALLOWED_DELAY); + m = chEvtClear(0); + test_assert(m == 0, "#11"); /* Stuck event.*/ + test_wait_threads(); + chEvtUnregister(&es1, &el1); + chEvtUnregister(&es2, &el2); + test_assert(!chEvtIsListening(&es1), "#12"); /* Stuck listener.*/ + test_assert(!chEvtIsListening(&es2), "#13"); /* Stuck listener.*/ +} + +const struct testcase testevt2 = { + evt2_gettest, + evt2_setup, + NULL, + evt2_execute +}; + +#if CH_USE_EVENTS_TIMEOUT +static char *evt3_gettest(void) { + + return "Events, timeouts"; +} + +static void evt3_setup(void) { + + chEvtClear(ALL_EVENTS); +} + +static void evt3_execute(void) { + eventmask_t m; + + /* + * Tests various timeout situations. + */ + m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_IMMEDIATE); + test_assert(m == 0, "#1"); + m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_IMMEDIATE); + test_assert(m == 0, "#2"); + m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_IMMEDIATE); + test_assert(m == 0, "#3"); + m = chEvtWaitOneTimeout(ALL_EVENTS, 10); + test_assert(m == 0, "#4"); + m = chEvtWaitAnyTimeout(ALL_EVENTS, 10); + test_assert(m == 0, "#5"); + m = chEvtWaitAllTimeout(ALL_EVENTS, 10); + test_assert(m == 0, "#6"); +#endif +} + +const struct testcase testevt3 = { + evt3_gettest, + evt3_setup, + NULL, + evt3_execute +}; + #endif /* CH_USE_EVENTS */ /* @@ -106,6 +225,10 @@ const struct testcase testevt1 = { const struct testcase * const patternevt[] = { #if CH_USE_EVENTS &testevt1, + &testevt2, +#if CH_USE_EVENTS_TIMEOUT + &testevt3, +#endif #endif NULL }; diff --git a/test/testheap.c b/test/testheap.c index a72bad6bb..2740f8a9e 100644 --- a/test/testheap.c +++ b/test/testheap.c @@ -44,21 +44,38 @@ static void heap1_execute(void) { p1 = chHeapAlloc(SIZE); p2 = chHeapAlloc(SIZE); p3 = chHeapAlloc(SIZE); - chHeapFree(p1); /* Does not merge */ - chHeapFree(p2); /* Merges backward */ - chHeapFree(p3); /* Merges both sides */ + chHeapFree(p1); /* Does not merge */ + chHeapFree(p2); /* Merges backward */ + chHeapFree(p3); /* Merges both sides */ test_assert(chHeapStatus(&n) == 1, "#1"); /* Heap fragmented.*/ /* Reverse order */ p1 = chHeapAlloc(SIZE); p2 = chHeapAlloc(SIZE); p3 = chHeapAlloc(SIZE); - chHeapFree(p3); /* Merges forward */ - chHeapFree(p2); /* Merges forward */ - chHeapFree(p1); /* Merges forward */ + chHeapFree(p3); /* Merges forward */ + chHeapFree(p2); /* Merges forward */ + chHeapFree(p1); /* Merges forward */ test_assert(chHeapStatus(&n) == 1, "#2"); /* Heap fragmented.*/ - test_assert(n == sz, "#3"); /* Heap size changed.*/ + /* Small fragments handling */ + p1 = chHeapAlloc(SIZE + 1); + p2 = chHeapAlloc(SIZE); + chHeapFree(p1); + test_assert(chHeapStatus(&n) == 2, "#3"); /* Heap must contain 2 blocks.*/ + p1 = chHeapAlloc(SIZE); + test_assert(chHeapStatus(&n) == 1, "#4"); /* Heap fragmented.*/ + chHeapFree(p2); + chHeapFree(p1); + + /* Allocate all handling */ + (void)chHeapStatus(&n); + p1 = chHeapAlloc(n); + test_assert(chHeapStatus(&n) == 0, "#5"); /* Heap must be empty.*/ + chHeapFree(p1); + + test_assert(chHeapStatus(&n) == 1, "#6"); /* Heap fragmented.*/ + test_assert(n == sz, "#7"); /* Heap size changed.*/ } else { test_print("--- Size : "); diff --git a/test/testsem.c b/test/testsem.c index d6e432a36..eac0e041b 100644 --- a/test/testsem.c +++ b/test/testsem.c @@ -85,7 +85,10 @@ static void sem2_setup(void) { static msg_t thread2(void *p) { chThdSleepMilliseconds(50); - chSemSignal(&sem1); + chSysLock(); + chSemSignalI(&sem1); /* For coverage reasons */ + chSchRescheduleS(); + chSysUnlock(); return 0; } @@ -115,6 +118,7 @@ static void sem2_execute(void) { /* * Testing timeout condition. */ + test_wait_tick(); target_time = chTimeNow() + MS2ST(5 * 500); for (i = 0; i < 5; i++) { test_emit_token('A' + i); @@ -134,6 +138,44 @@ const struct testcase testsem2 = { sem2_execute }; #endif /* CH_USE_SEMAPHORES_TIMEOUT */ + +#if CH_USE_SEMSW +static char *sem3_gettest(void) { + + return "Semaphores, atomic signal-wait"; +} + +static void sem3_setup(void) { + + chSemInit(&sem1, 0); +} + +static msg_t thread3(void *p) { + + chSemWait(&sem1); + chSemSignal(&sem1); + return 0; +} + +static void sem3_execute(void) { + + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+1, thread3, "A"); + chSemSignalWait(&sem1, &sem1); + test_assert(isempty(&sem1.s_queue), "#1"); /* Queue not empty */ + test_assert(sem1.s_cnt == 0, "#2"); /* Counter not zero */ + + chSemSignalWait(&sem1, &sem1); + test_assert(isempty(&sem1.s_queue), "#3"); /* Queue not empty */ + test_assert(sem1.s_cnt == 0, "#4"); /* Counter not zero */ +} + +const struct testcase testsem3 = { + sem3_gettest, + sem3_setup, + NULL, + sem3_execute +}; +#endif /* CH_USE_SEMSW */ #endif /* CH_USE_SEMAPHORES */ /* @@ -145,6 +187,9 @@ const struct testcase * const patternsem[] = { #if CH_USE_SEMAPHORES_TIMEOUT &testsem2, #endif +#if CH_USE_SEMSW + &testsem3, +#endif #endif NULL }; diff --git a/test/testthd.c b/test/testthd.c index cac77a43a..e5964f17f 100644 --- a/test/testthd.c +++ b/test/testthd.c @@ -130,25 +130,27 @@ static char *thd4_gettest(void) { static void thd4_execute(void) { systime_t time; + test_wait_tick(); + /* Timeouts in microseconds.*/ time = chTimeNow(); chThdSleepMicroseconds(100000); - test_assert(chTimeIsWithin(time + US2ST(100000), time + US2ST(100000) + 1), "#1"); + test_assert_time_window(time + US2ST(100000), time + US2ST(100000) + 1); /* Timeouts in milliseconds.*/ time = chTimeNow(); chThdSleepMilliseconds(100); - test_assert(chTimeIsWithin(time + MS2ST(100), time + MS2ST(100) + 1), "#2"); + test_assert_time_window(time + MS2ST(100), time + MS2ST(100) + 1); /* Timeouts in seconds.*/ time = chTimeNow(); chThdSleepSeconds(1); - test_assert(chTimeIsWithin(time + S2ST(1), time + S2ST(1) + 1), "#3"); + test_assert_time_window(time + S2ST(1), time + S2ST(1) + 1); /* Absolute timelines.*/ time = chTimeNow() + MS2ST(100); chThdSleepUntil(time); - test_assert(chTimeIsWithin(time, time + 1), "#4"); + test_assert_time_window(time, time + 1); } const struct testcase testthd4 = {