1// Copyright (c) 2019-2020 Nordic Semiconductor ASA
2// SPDX-License-Identifier: Apache-2.0
3
4// Convert legacy integer timeouts to timeout API
5//
6// Some existing code assumes that timeout parameters are provided as
7// integer milliseconds, when they were intended to be timeout values
8// produced by specific constants and macros.  Convert integer
9// literals and parameters to the desired equivalent
10//
11// A few expressions that are clearly integer values are also
12// converted.
13//
14// Options: --include-headers
15
16virtual patch
17virtual report
18
19// ** Handle timeouts at the last position of kernel API arguments
20
21// Base rule provides the complex identifier regular expression
22@r_last_timeout@
23identifier last_timeout =~ "(?x)^k_
24( delayed_work_submit(|_to_queue)
25| futex_wait
26| mbox_data_block_get
27| (mbox|msgq)_get
28| mem_(pool|slab)_alloc
29| mutex_lock
30| pipe_(get|put)
31| poll
32| queue_get
33| sem_take
34| sleep
35| stack_pop
36| thread_create
37| timer_start
38| work_poll_submit(|_to_queue)
39)$";
40@@
41last_timeout(...)
42
43// Identify call sites where an identifier is used for the timeout
44@r_last_timeout_id
45 extends r_last_timeout
46@
47identifier D;
48position p;
49@@
50last_timeout@p(..., D)
51
52// Select call sites where a constant literal (not identifier) is used
53// for the timeout and replace the constant with the appropriate macro
54
55@r_last_timeout_const_patch
56 extends r_last_timeout
57 depends on patch
58@
59constant C;
60position p != r_last_timeout_id.p;
61@@
62last_timeout@p(...,
63(
64- 0
65+ K_NO_WAIT
66|
67- -1
68+ K_FOREVER
69|
70- C
71+ K_MSEC(C)
72)
73 )
74
75@r_last_timeout_const_report
76 extends r_last_timeout
77 depends on report
78@
79constant C;
80position p != r_last_timeout_id.p;
81@@
82last_timeout@p(..., C)
83
84@script:python
85 depends on report
86@
87fn << r_last_timeout.last_timeout;
88p << r_last_timeout_const_report.p;
89C << r_last_timeout_const_report.C;
90@@
91msg = "WARNING: replace constant {} with timeout in {}".format(C, fn)
92coccilib.report.print_report(p[0], msg);
93
94// ** Handle call sites where a timeout is specified by an expression
95// ** scaled by MSEC_PER_SEC and replace with the corresponding
96// ** K_SECONDS() expression.
97
98@r_last_timeout_scaled_patch
99 extends r_last_timeout
100 depends on patch
101@
102// identifier K_MSEC =~ "^K_MSEC$";
103symbol K_MSEC;
104identifier MSEC_PER_SEC =~ "^MSEC_PER_SEC$";
105expression V;
106position p;
107@@
108last_timeout@p(...,
109(
110- MSEC_PER_SEC
111+ K_SECONDS(1)
112|
113- V * MSEC_PER_SEC
114+ K_SECONDS(V)
115|
116- K_MSEC(MSEC_PER_SEC)
117+ K_SECONDS(1)
118|
119- K_MSEC(V * MSEC_PER_SEC)
120+ K_SECONDS(V)
121)
122 )
123
124@r_last_timeout_scaled_report_req
125 extends r_last_timeout
126 depends on report
127@
128identifier MSEC_PER_SEC =~ "^MSEC_PER_SEC$";
129expression V;
130position p;
131@@
132last_timeout@p(...,
133(
134  MSEC_PER_SEC
135| V * MSEC_PER_SEC
136)
137 )
138
139@r_last_timeout_scaled_report_opt
140 extends r_last_timeout
141 depends on report
142@
143identifier MSEC_PER_SEC =~ "^MSEC_PER_SEC$";
144expression V;
145position p;
146@@
147last_timeout@p(...,
148(
149  K_MSEC(MSEC_PER_SEC)
150| K_MSEC(V * MSEC_PER_SEC)
151)
152 )
153
154@script:python
155 depends on report
156@
157fn << r_last_timeout.last_timeout;
158p << r_last_timeout_scaled_report_req.p;
159@@
160msg = "WARNING: use K_SECONDS() for timeout in {}".format(fn)
161coccilib.report.print_report(p[0], msg);
162
163@script:python
164 depends on report
165@
166fn << r_last_timeout.last_timeout;
167p << r_last_timeout_scaled_report_opt.p;
168@@
169msg = "NOTE: use K_SECONDS() for timeout in {}".format(fn)
170coccilib.report.print_report(p[0], msg);
171
172// ** Handle call sites where an integer parameter is used in a
173// ** position that requires a timeout value.
174
175@r_last_timeout_int_param_patch
176 extends r_last_timeout
177 depends on patch
178 @
179identifier FN;
180identifier P;
181typedef int32_t, uint32_t;
182@@
183 FN(...,
184(int
185|int32_t
186|uint32_t
187)
188 P, ...) {
189 ...
190 last_timeout(...,
191-P
192+K_MSEC(P)
193 )
194 ...
195 }
196
197@r_last_timeout_int_param_report
198 extends r_last_timeout
199 depends on report
200 @
201identifier FN;
202identifier P;
203position p;
204typedef int32_t, uint32_t;
205@@
206 FN(...,
207(int
208|int32_t
209|uint32_t
210)
211 P, ...) {
212 ...
213 last_timeout@p(..., P)
214 ...
215 }
216
217@script:python
218 depends on report
219@
220param << r_last_timeout_int_param_report.P;
221fn << r_last_timeout.last_timeout;
222p << r_last_timeout_int_param_report.p;
223@@
224msg = "WARNING: replace integer parameter {} with timeout in {}".format(param, fn)
225coccilib.report.print_report(p[0], msg);
226
227// ** Convert timeout-valued delays in K_THREAD_DEFINE with durations
228// ** in milliseconds
229
230// Select declarers where the startup delay is a timeout expression
231// and replace with the corresponding millisecond duration.
232@r_thread_decl_patch
233 depends on patch@
234declarer name K_THREAD_DEFINE;
235identifier K_NO_WAIT =~ "^K_NO_WAIT$";
236identifier K_FOREVER =~ "^K_FOREVER$";
237expression E;
238position p;
239@@
240K_THREAD_DEFINE@p(...,
241(
242- K_NO_WAIT
243+ 0
244|
245- K_FOREVER
246+ -1
247|
248- K_MSEC(E)
249+ E
250)
251 );
252
253//
254@r_thread_decl_report
255 depends on report@
256declarer name K_THREAD_DEFINE;
257identifier K_NO_WAIT =~ "^K_NO_WAIT$";
258identifier K_FOREVER =~ "^K_FOREVER$";
259expression V;
260position p;
261@@
262K_THREAD_DEFINE@p(...,
263(
264 K_NO_WAIT
265|
266 K_FOREVER
267|
268 K_MSEC(V)
269)
270 );
271
272
273@script:python
274 depends on report
275@
276p << r_thread_decl_report.p;
277@@
278msg = "WARNING: replace timeout-valued delay with millisecond duration".format()
279coccilib.report.print_report(p[0], msg);
280
281// ** Handle k_timer_start where the second (not last) argument is a
282// ** constant literal.
283
284// Select call sites where an identifier is used for the duration timeout
285@r_timer_duration@
286expression T;
287identifier D;
288expression I;
289position p;
290@@
291k_timer_start@p(T, D, I)
292
293// Select call sites where a constant literal (not identifier) is used
294// for the timeout and replace the constant with the appropriate macro
295@depends on patch@
296expression T;
297constant C;
298expression I;
299position p != r_timer_duration.p;
300@@
301k_timer_start@p(T,
302(
303- 0
304+ K_NO_WAIT
305|
306- -1
307+ K_FOREVER
308|
309- C
310+ K_MSEC(C)
311)
312, I)
313
314@r_timer_duration_report
315 depends on report
316@
317expression T;
318constant C;
319expression I;
320position p != r_timer_duration.p;
321@@
322k_timer_start@p(T, C, I)
323
324@script:python
325 depends on report
326@
327p << r_timer_duration_report.p;
328C << r_timer_duration_report.C;
329@@
330msg = "WARNING: replace constant {} with duration timeout in k_timer_start".format(C)
331coccilib.report.print_report(p[0], msg);
332