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