1#include "test_timers.h"
2
3#include "lwip/def.h"
4#include "lwip/timeouts.h"
5#include "arch/sys_arch.h"
6
7/* Setups/teardown functions */
8
9static struct sys_timeo* old_list_head;
10
11static void
12timers_setup(void)
13{
14  struct sys_timeo** list_head = sys_timeouts_get_next_timeout();
15  old_list_head = *list_head;
16  *list_head = NULL;
17}
18
19static void
20timers_teardown(void)
21{
22  struct sys_timeo** list_head = sys_timeouts_get_next_timeout();
23  *list_head = old_list_head;
24  lwip_sys_now = 0;
25}
26
27static int fired[3];
28static void
29dummy_handler(void* arg)
30{
31  int index = LWIP_PTR_NUMERIC_CAST(int, arg);
32  fired[index] = 1;
33}
34
35#define HANDLER_EXECUTION_TIME 5
36static int cyclic_fired;
37static void
38dummy_cyclic_handler(void)
39{
40   cyclic_fired = 1;
41   lwip_sys_now += HANDLER_EXECUTION_TIME;
42}
43
44struct lwip_cyclic_timer test_cyclic = {10, dummy_cyclic_handler};
45
46static void
47do_test_cyclic_timers(u32_t offset)
48{
49  struct sys_timeo** list_head = sys_timeouts_get_next_timeout();
50
51  /* verify normal timer expiration */
52  lwip_sys_now = offset + 0;
53  sys_timeout(test_cyclic.interval_ms, lwip_cyclic_timer, &test_cyclic);
54
55  cyclic_fired = 0;
56  sys_check_timeouts();
57  fail_unless(cyclic_fired == 0);
58
59  lwip_sys_now = offset + test_cyclic.interval_ms;
60  sys_check_timeouts();
61  fail_unless(cyclic_fired == 1);
62
63  fail_unless((*list_head)->time == (u32_t)(lwip_sys_now + test_cyclic.interval_ms - HANDLER_EXECUTION_TIME));
64
65  sys_untimeout(lwip_cyclic_timer, &test_cyclic);
66
67
68  /* verify "overload" - next cyclic timer execution is already overdue twice */
69  lwip_sys_now = offset + 0;
70  sys_timeout(test_cyclic.interval_ms, lwip_cyclic_timer, &test_cyclic);
71
72  cyclic_fired = 0;
73  sys_check_timeouts();
74  fail_unless(cyclic_fired == 0);
75
76  lwip_sys_now = offset + 2*test_cyclic.interval_ms;
77  sys_check_timeouts();
78  fail_unless(cyclic_fired == 1);
79
80  fail_unless((*list_head)->time == (u32_t)(lwip_sys_now + test_cyclic.interval_ms));
81}
82
83START_TEST(test_cyclic_timers)
84{
85  LWIP_UNUSED_ARG(_i);
86
87  /* check without u32_t wraparound */
88  do_test_cyclic_timers(0);
89
90  /* check with u32_t wraparound */
91  do_test_cyclic_timers(0xfffffff0);
92}
93END_TEST
94
95/* reproduce bug #52748: the bug in timeouts.c */
96START_TEST(test_bug52748)
97{
98  LWIP_UNUSED_ARG(_i);
99
100  memset(&fired, 0, sizeof(fired));
101
102  lwip_sys_now = 50;
103  sys_timeout(20, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0));
104  sys_timeout( 5, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 2));
105
106  lwip_sys_now = 55;
107  sys_check_timeouts();
108  fail_unless(fired[0] == 0);
109  fail_unless(fired[1] == 0);
110  fail_unless(fired[2] == 1);
111
112  lwip_sys_now = 60;
113  sys_timeout(10, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 1));
114  sys_check_timeouts();
115  fail_unless(fired[0] == 0);
116  fail_unless(fired[1] == 0);
117  fail_unless(fired[2] == 1);
118
119  lwip_sys_now = 70;
120  sys_check_timeouts();
121  fail_unless(fired[0] == 1);
122  fail_unless(fired[1] == 1);
123  fail_unless(fired[2] == 1);
124}
125END_TEST
126
127static void
128do_test_timers(u32_t offset)
129{
130  struct sys_timeo** list_head = sys_timeouts_get_next_timeout();
131
132  lwip_sys_now = offset + 0;
133
134  sys_timeout(10, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0));
135  fail_unless(sys_timeouts_sleeptime() == 10);
136  sys_timeout(20, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 1));
137  fail_unless(sys_timeouts_sleeptime() == 10);
138  sys_timeout( 5, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 2));
139  fail_unless(sys_timeouts_sleeptime() == 5);
140
141  /* linked list correctly sorted? */
142  fail_unless((*list_head)->time             == (u32_t)(lwip_sys_now + 5));
143  fail_unless((*list_head)->next->time       == (u32_t)(lwip_sys_now + 10));
144  fail_unless((*list_head)->next->next->time == (u32_t)(lwip_sys_now + 20));
145
146  /* check timers expire in correct order */
147  memset(&fired, 0, sizeof(fired));
148
149  lwip_sys_now += 4;
150  sys_check_timeouts();
151  fail_unless(fired[2] == 0);
152
153  lwip_sys_now += 1;
154  sys_check_timeouts();
155  fail_unless(fired[2] == 1);
156
157  lwip_sys_now += 4;
158  sys_check_timeouts();
159  fail_unless(fired[0] == 0);
160
161  lwip_sys_now += 1;
162  sys_check_timeouts();
163  fail_unless(fired[0] == 1);
164
165  lwip_sys_now += 9;
166  sys_check_timeouts();
167  fail_unless(fired[1] == 0);
168
169  lwip_sys_now += 1;
170  sys_check_timeouts();
171  fail_unless(fired[1] == 1);
172
173  sys_untimeout(dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0));
174  sys_untimeout(dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 1));
175  sys_untimeout(dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 2));
176}
177
178START_TEST(test_timers)
179{
180  LWIP_UNUSED_ARG(_i);
181
182  /* check without u32_t wraparound */
183  do_test_timers(0);
184
185  /* check with u32_t wraparound */
186  do_test_timers(0xfffffff0);
187}
188END_TEST
189
190START_TEST(test_long_timer)
191{
192  LWIP_UNUSED_ARG(_i);
193
194  memset(&fired, 0, sizeof(fired));
195  lwip_sys_now = 0;
196
197  sys_timeout(LWIP_UINT32_MAX / 4, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0));
198  fail_unless(sys_timeouts_sleeptime() == LWIP_UINT32_MAX / 4);
199
200  sys_check_timeouts();
201  fail_unless(fired[0] == 0);
202
203  lwip_sys_now += LWIP_UINT32_MAX / 8;
204
205  sys_check_timeouts();
206  fail_unless(fired[0] == 0);
207
208  lwip_sys_now += LWIP_UINT32_MAX / 8;
209
210  sys_check_timeouts();
211  fail_unless(fired[0] == 0);
212
213  lwip_sys_now += 1;
214
215  sys_check_timeouts();
216  fail_unless(fired[0] == 1);
217
218  sys_untimeout(dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0));
219}
220END_TEST
221
222/** Create the suite including all tests for this module */
223Suite *
224timers_suite(void)
225{
226  testfunc tests[] = {
227    TESTFUNC(test_bug52748),
228    TESTFUNC(test_cyclic_timers),
229    TESTFUNC(test_timers),
230    TESTFUNC(test_long_timer),
231  };
232  return create_suite("TIMERS", tests, LWIP_ARRAYSIZE(tests), timers_setup, timers_teardown);
233}
234