#include "test_timers.h" #include "lwip/def.h" #include "lwip/timeouts.h" #include "arch/sys_arch.h" /* Setups/teardown functions */ static struct sys_timeo* old_list_head; static void timers_setup(void) { struct sys_timeo** list_head = sys_timeouts_get_next_timeout(); old_list_head = *list_head; *list_head = NULL; } static void timers_teardown(void) { struct sys_timeo** list_head = sys_timeouts_get_next_timeout(); *list_head = old_list_head; lwip_sys_now = 0; } static int fired[3]; static void dummy_handler(void* arg) { int index = LWIP_PTR_NUMERIC_CAST(int, arg); fired[index] = 1; } #define HANDLER_EXECUTION_TIME 5 static int cyclic_fired; static void dummy_cyclic_handler(void) { cyclic_fired = 1; lwip_sys_now += HANDLER_EXECUTION_TIME; } struct lwip_cyclic_timer test_cyclic = {10, dummy_cyclic_handler}; static void do_test_cyclic_timers(u32_t offset) { struct sys_timeo** list_head = sys_timeouts_get_next_timeout(); /* verify normal timer expiration */ lwip_sys_now = offset + 0; sys_timeout(test_cyclic.interval_ms, lwip_cyclic_timer, &test_cyclic); cyclic_fired = 0; sys_check_timeouts(); fail_unless(cyclic_fired == 0); lwip_sys_now = offset + test_cyclic.interval_ms; sys_check_timeouts(); fail_unless(cyclic_fired == 1); fail_unless((*list_head)->time == (u32_t)(lwip_sys_now + test_cyclic.interval_ms - HANDLER_EXECUTION_TIME)); sys_untimeout(lwip_cyclic_timer, &test_cyclic); /* verify "overload" - next cyclic timer execution is already overdue twice */ lwip_sys_now = offset + 0; sys_timeout(test_cyclic.interval_ms, lwip_cyclic_timer, &test_cyclic); cyclic_fired = 0; sys_check_timeouts(); fail_unless(cyclic_fired == 0); lwip_sys_now = offset + 2*test_cyclic.interval_ms; sys_check_timeouts(); fail_unless(cyclic_fired == 1); fail_unless((*list_head)->time == (u32_t)(lwip_sys_now + test_cyclic.interval_ms)); } START_TEST(test_cyclic_timers) { LWIP_UNUSED_ARG(_i); /* check without u32_t wraparound */ do_test_cyclic_timers(0); /* check with u32_t wraparound */ do_test_cyclic_timers(0xfffffff0); } END_TEST /* reproduce bug #52748: the bug in timeouts.c */ START_TEST(test_bug52748) { LWIP_UNUSED_ARG(_i); memset(&fired, 0, sizeof(fired)); lwip_sys_now = 50; sys_timeout(20, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0)); sys_timeout( 5, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 2)); lwip_sys_now = 55; sys_check_timeouts(); fail_unless(fired[0] == 0); fail_unless(fired[1] == 0); fail_unless(fired[2] == 1); lwip_sys_now = 60; sys_timeout(10, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 1)); sys_check_timeouts(); fail_unless(fired[0] == 0); fail_unless(fired[1] == 0); fail_unless(fired[2] == 1); lwip_sys_now = 70; sys_check_timeouts(); fail_unless(fired[0] == 1); fail_unless(fired[1] == 1); fail_unless(fired[2] == 1); } END_TEST static void do_test_timers(u32_t offset) { struct sys_timeo** list_head = sys_timeouts_get_next_timeout(); lwip_sys_now = offset + 0; sys_timeout(10, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0)); fail_unless(sys_timeouts_sleeptime() == 10); sys_timeout(20, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 1)); fail_unless(sys_timeouts_sleeptime() == 10); sys_timeout( 5, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 2)); fail_unless(sys_timeouts_sleeptime() == 5); /* linked list correctly sorted? */ fail_unless((*list_head)->time == (u32_t)(lwip_sys_now + 5)); fail_unless((*list_head)->next->time == (u32_t)(lwip_sys_now + 10)); fail_unless((*list_head)->next->next->time == (u32_t)(lwip_sys_now + 20)); /* check timers expire in correct order */ memset(&fired, 0, sizeof(fired)); lwip_sys_now += 4; sys_check_timeouts(); fail_unless(fired[2] == 0); lwip_sys_now += 1; sys_check_timeouts(); fail_unless(fired[2] == 1); lwip_sys_now += 4; sys_check_timeouts(); fail_unless(fired[0] == 0); lwip_sys_now += 1; sys_check_timeouts(); fail_unless(fired[0] == 1); lwip_sys_now += 9; sys_check_timeouts(); fail_unless(fired[1] == 0); lwip_sys_now += 1; sys_check_timeouts(); fail_unless(fired[1] == 1); sys_untimeout(dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0)); sys_untimeout(dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 1)); sys_untimeout(dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 2)); } START_TEST(test_timers) { LWIP_UNUSED_ARG(_i); /* check without u32_t wraparound */ do_test_timers(0); /* check with u32_t wraparound */ do_test_timers(0xfffffff0); } END_TEST START_TEST(test_long_timer) { LWIP_UNUSED_ARG(_i); memset(&fired, 0, sizeof(fired)); lwip_sys_now = 0; sys_timeout(LWIP_UINT32_MAX / 4, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0)); fail_unless(sys_timeouts_sleeptime() == LWIP_UINT32_MAX / 4); sys_check_timeouts(); fail_unless(fired[0] == 0); lwip_sys_now += LWIP_UINT32_MAX / 8; sys_check_timeouts(); fail_unless(fired[0] == 0); lwip_sys_now += LWIP_UINT32_MAX / 8; sys_check_timeouts(); fail_unless(fired[0] == 0); lwip_sys_now += 1; sys_check_timeouts(); fail_unless(fired[0] == 1); sys_untimeout(dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0)); } END_TEST /** Create the suite including all tests for this module */ Suite * timers_suite(void) { testfunc tests[] = { TESTFUNC(test_bug52748), TESTFUNC(test_cyclic_timers), TESTFUNC(test_timers), TESTFUNC(test_long_timer), }; return create_suite("TIMERS", tests, LWIP_ARRAYSIZE(tests), timers_setup, timers_teardown); }