blob: 820b718924f74757f19bf9b38dee5d2efd4d947c [file] [log] [blame]
#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);
}