26
26
#include <nuttx/arch.h>
27
27
#include <nuttx/wdog.h>
28
28
29
+ #include <assert.h>
29
30
#include <pthread.h>
30
31
#include <stdio.h>
31
- #include <assert .h>
32
+ #include <syslog .h>
32
33
#include <unistd.h>
33
34
34
35
/****************************************************************************
35
36
* Pre-processor Definitions
36
37
****************************************************************************/
37
38
38
39
#define WDOGTEST_RAND_ITER 1024
39
- #define WDOGTEST_THREAD_NR 8
40
- #define WDOGTEST_TOLERENT_LATENCY_US 5000
40
+ #define WDOGTEST_THREAD_NR (CONFIG_SMP_NCPUS * 4)
41
+ #define WDOGTEST_TOLERENT_TICK 10
41
42
42
43
#define wdtest_assert (x ) _ASSERT(x, __FILE__, __LINE__)
43
44
44
- #define wdtest_printf (...) printf( __VA_ARGS__)
45
+ #define wdtest_printf (...) syslog(LOG_WARNING, __VA_ARGS__)
45
46
46
47
#define wdtest_delay (delay_ns ) usleep(delay_ns / 1000 + 1)
47
48
@@ -64,63 +65,131 @@ typedef struct wdtest_param_s
64
65
#ifdef CONFIG_BUILD_FLAT
65
66
static void wdtest_callback (wdparm_t param )
66
67
{
67
- struct timespec tp ;
68
68
FAR wdtest_param_t * wdtest_param = (FAR wdtest_param_t * )param ;
69
69
70
- clock_gettime ( CLOCK_MONOTONIC , & tp );
70
+ /* Increment the callback count */
71
71
72
72
wdtest_param -> callback_cnt += 1 ;
73
- wdtest_param -> triggered_tick = clock_time2ticks (& tp );
73
+
74
+ /* Record the system tick at which the callback was triggered */
75
+
76
+ wdtest_param -> triggered_tick = clock_systime_ticks ();
77
+ }
78
+
79
+ static void wdtest_checkdelay (sclock_t diff , sclock_t delay_tick )
80
+ {
81
+ /* Ensure the watchdog trigger time is not earlier than expected. */
82
+
83
+ wdtest_assert (diff - delay_tick >= 0 );
84
+
85
+ /* If the timer latency exceeds the tolerance, print a warning. */
86
+
87
+ if (diff - delay_tick > WDOGTEST_TOLERENT_TICK )
88
+ {
89
+ wdtest_printf ("WARNING: wdog latency ticks %lld "
90
+ "(> %u may indicate timing error)\n" ,
91
+ (long long )diff - delay_tick ,
92
+ WDOGTEST_TOLERENT_TICK );
93
+ }
74
94
}
75
95
76
96
static void wdtest_once (FAR struct wdog_s * wdog , FAR wdtest_param_t * param ,
77
97
sclock_t delay_ns )
78
98
{
79
- uint64_t cnt ;
80
- long long diff ;
81
- clock_t wdset_tick ;
82
- struct timespec tp ;
83
- clock_t delay_ticks = (clock_t )NSEC2TICK ((clock_t )delay_ns );
99
+ uint64_t cnt ;
100
+ sclock_t diff ;
101
+ clock_t wdset_tick ;
102
+ irqstate_t flags ;
103
+ sclock_t delay_tick = (sclock_t )NSEC2TICK ((clock_t )delay_ns );
84
104
85
105
wdtest_printf ("wdtest_once %lld ns\n" , (long long )delay_ns );
86
106
87
- clock_gettime ( CLOCK_MONOTONIC , & tp );
107
+ /* Save the current callback count. */
88
108
89
- wdset_tick = clock_time2ticks (& tp );
90
109
cnt = param -> callback_cnt ;
91
110
92
- wdtest_assert (wd_start (wdog , delay_ticks , wdtest_callback ,
111
+ /* Enter a critical section to prevent interruptions. */
112
+
113
+ flags = enter_critical_section ();
114
+
115
+ /* Record the current system tick before setting the watchdog. */
116
+
117
+ wdset_tick = clock_systime_ticks ();
118
+
119
+ wdtest_assert (wd_start (wdog , delay_tick , wdtest_callback ,
93
120
(wdparm_t )param ) == OK );
94
121
95
- wdtest_delay ( delay_ns );
122
+ leave_critical_section ( flags );
96
123
97
- diff = ( long long )( param -> triggered_tick - wdset_tick );
124
+ /* Wait until the callback is triggered exactly once. */
98
125
99
- wdtest_assert (cnt + 1 == param -> callback_cnt );
126
+ while (cnt + 1 != param -> callback_cnt )
127
+ {
128
+ wdtest_delay (delay_ns );
129
+ }
130
+
131
+ /* Check if the delay is within the acceptable tolerance. */
100
132
101
- /* Ensure diff - delay_ticks >= 0. */
133
+ diff = ( sclock_t )( param -> triggered_tick - wdset_tick );
102
134
103
- wdtest_assert (diff - (long long )delay_ticks >= 0 );
104
- wdtest_printf ("wdtest_once latency ticks %lld\n" , diff - delay_ticks );
135
+ wdtest_checkdelay (diff , delay_tick );
105
136
}
106
137
107
138
static void wdtest_rand (FAR struct wdog_s * wdog , FAR wdtest_param_t * param ,
108
139
sclock_t rand_ns )
109
140
{
110
- int idx ;
111
- sclock_t delay_ns ;
141
+ uint64_t cnt ;
142
+ int idx ;
143
+ sclock_t delay_ns ;
144
+ clock_t wdset_tick ;
145
+ sclock_t delay_tick ;
146
+ sclock_t diff ;
147
+ irqstate_t flags ;
148
+
149
+ /* Perform multiple iterations with random delays. */
112
150
113
151
for (idx = 0 ; idx < WDOGTEST_RAND_ITER ; idx ++ )
114
152
{
153
+ cnt = param -> callback_cnt ;
154
+
155
+ /* Generate a random delay within the specified range. */
156
+
115
157
delay_ns = rand () % rand_ns ;
116
- wdtest_assert (wd_start (wdog , NSEC2TICK (delay_ns ), wdtest_callback ,
158
+ delay_tick = NSEC2TICK (delay_ns );
159
+
160
+ /* Enter critical section if the callback count is odd. */
161
+
162
+ if (cnt % 2 )
163
+ {
164
+ flags = enter_critical_section ();
165
+ }
166
+
167
+ wdset_tick = clock_systime_ticks ();
168
+ wdtest_assert (wd_start (wdog , delay_tick , wdtest_callback ,
117
169
(wdparm_t )param ) == 0 );
170
+ if (cnt % 2 )
171
+ {
172
+ leave_critical_section (flags );
173
+ }
118
174
119
- /* Wait or Cancel 50/50 */
175
+ /* Decide to wait for the callback or cancel the watchdog. */
120
176
121
177
if (delay_ns % 2 )
122
178
{
123
- wdtest_delay (delay_ns );
179
+ /* Wait for the callback. */
180
+
181
+ while (cnt + 1 != param -> callback_cnt )
182
+ {
183
+ wdtest_delay (delay_ns );
184
+ }
185
+
186
+ /* Check the delay if the callback count is odd. */
187
+
188
+ if (cnt % 2 )
189
+ {
190
+ diff = (sclock_t )(param -> triggered_tick - wdset_tick );
191
+ wdtest_checkdelay (diff , delay_tick );
192
+ }
124
193
}
125
194
else
126
195
{
@@ -131,14 +200,11 @@ static void wdtest_rand(FAR struct wdog_s *wdog, FAR wdtest_param_t *param,
131
200
132
201
static void wdtest_callback_recursive (wdparm_t param )
133
202
{
134
- struct timespec tp ;
135
203
FAR wdtest_param_t * wdtest_param = (FAR wdtest_param_t * )param ;
136
204
sclock_t interval = wdtest_param -> interval ;
137
205
138
- clock_gettime (CLOCK_MONOTONIC , & tp );
139
-
140
206
wdtest_param -> callback_cnt += 1 ;
141
- wdtest_param -> triggered_tick = clock_time2ticks ( & tp );
207
+ wdtest_param -> triggered_tick = clock_systime_ticks ( );
142
208
143
209
wd_start (wdtest_param -> wdog , interval ,
144
210
wdtest_callback_recursive , param );
@@ -149,24 +215,29 @@ static void wdtest_recursive(FAR struct wdog_s *wdog,
149
215
sclock_t delay_ns ,
150
216
unsigned int times )
151
217
{
152
- uint64_t cnt ;
153
- struct timespec tp ;
154
- clock_t wdset_tick ;
218
+ uint64_t cnt ;
219
+ clock_t wdset_tick ;
220
+ irqstate_t flags ;
155
221
156
222
wdtest_printf ("wdtest_recursive %lldus\n" , (long long )delay_ns );
223
+
157
224
cnt = param -> callback_cnt ;
225
+
158
226
param -> wdog = wdog ;
159
227
param -> interval = (sclock_t )NSEC2TICK ((clock_t )delay_ns );
160
228
161
229
wdtest_assert (param -> interval >= 0 );
162
230
163
- clock_gettime (CLOCK_MONOTONIC , & tp );
164
- wdset_tick = clock_time2ticks (& tp );
231
+ flags = enter_critical_section ();
232
+
233
+ wdset_tick = clock_systime_ticks ();
165
234
166
235
wdtest_assert (wd_start (param -> wdog , param -> interval ,
167
236
wdtest_callback_recursive ,
168
237
(wdparm_t )param ) == OK );
169
238
239
+ leave_critical_section (flags );
240
+
170
241
wdtest_delay (times * delay_ns );
171
242
172
243
wdtest_assert (wd_cancel (param -> wdog ) == 0 );
@@ -208,7 +279,6 @@ static void wdog_test_run(FAR wdtest_param_t *param)
208
279
wdtest_once (& test_wdog , param , 100 );
209
280
wdtest_once (& test_wdog , param , 1000 );
210
281
wdtest_once (& test_wdog , param , 10000 );
211
- wdtest_delay (10 );
212
282
213
283
/* Delay > 0, middle 100us */
214
284
@@ -242,11 +312,11 @@ static void wdog_test_run(FAR wdtest_param_t *param)
242
312
243
313
wdtest_assert (rest < delay && rest > (delay >> 1 ));
244
314
245
- wdtest_printf ("wd_start with maximum delay, cancel %lld\n" ,
246
- (long long )rest );
247
-
248
315
wdtest_assert (wd_cancel (& test_wdog ) == 0 );
249
316
317
+ wdtest_printf ("wd_start with maximum delay, cancel OK, rest %lld\n" ,
318
+ (long long )rest );
319
+
250
320
/* Delay wraparound (delay < 0) */
251
321
252
322
delay = (sclock_t )((clock_t )delay + 1 );
0 commit comments