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
9 static struct sys_timeo* old_list_head;
10
11 static void
timers_setup(void)12 timers_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
19 static void
timers_teardown(void)20 timers_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
27 static int fired[3];
28 static void
dummy_handler(void * arg)29 dummy_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
36 static int cyclic_fired;
37 static void
dummy_cyclic_handler(void)38 dummy_cyclic_handler(void)
39 {
40 cyclic_fired = 1;
41 lwip_sys_now += HANDLER_EXECUTION_TIME;
42 }
43
44 struct lwip_cyclic_timer test_cyclic = {10, dummy_cyclic_handler};
45
46 static void
do_test_cyclic_timers(u32_t offset)47 do_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
START_TEST(test_cyclic_timers)83 START_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 }
93 END_TEST
94
95 /* reproduce bug #52748: the bug in timeouts.c */
START_TEST(test_bug52748)96 START_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 }
125 END_TEST
126
127 static void
do_test_timers(u32_t offset)128 do_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
START_TEST(test_timers)178 START_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 }
188 END_TEST
189
START_TEST(test_long_timer)190 START_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 }
220 END_TEST
221
222 /** Create the suite including all tests for this module */
223 Suite *
timers_suite(void)224 timers_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