| // Copyright (c) 2019-2020 Nordic Semiconductor ASA |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| // Convert legacy integer timeouts to timeout API |
| // |
| // Some existing code assumes that timeout parameters are provided as |
| // integer milliseconds, when they were intended to be timeout values |
| // produced by specific constants and macros. Convert integer |
| // literals and parameters to the desired equivalent |
| // |
| // A few expressions that are clearly integer values are also |
| // converted. |
| // |
| // Options: --include-headers |
| |
| virtual patch |
| virtual report |
| |
| // ** Handle timeouts at the last position of kernel API arguments |
| |
| // Base rule provides the complex identifier regular expression |
| @r_last_timeout@ |
| identifier last_timeout =~ "(?x)^k_ |
| ( delayed_work_submit(|_to_queue) |
| | futex_wait |
| | mbox_data_block_get |
| | (mbox|msgq)_get |
| | mem_(pool|slab)_alloc |
| | mutex_lock |
| | pipe_(get|put) |
| | poll |
| | queue_get |
| | sem_take |
| | sleep |
| | stack_pop |
| | thread_create |
| | timer_start |
| | work_poll_submit(|_to_queue) |
| )$"; |
| @@ |
| last_timeout(...) |
| |
| // Identify call sites where an identifier is used for the timeout |
| @r_last_timeout_id |
| extends r_last_timeout |
| @ |
| identifier D; |
| position p; |
| @@ |
| last_timeout@p(..., D) |
| |
| // Select call sites where a constant literal (not identifier) is used |
| // for the timeout and replace the constant with the appropriate macro |
| |
| @r_last_timeout_const_patch |
| extends r_last_timeout |
| depends on patch |
| @ |
| constant C; |
| position p != r_last_timeout_id.p; |
| @@ |
| last_timeout@p(..., |
| ( |
| - 0 |
| + K_NO_WAIT |
| | |
| - -1 |
| + K_FOREVER |
| | |
| - C |
| + K_MSEC(C) |
| ) |
| ) |
| |
| @r_last_timeout_const_report |
| extends r_last_timeout |
| depends on report |
| @ |
| constant C; |
| position p != r_last_timeout_id.p; |
| @@ |
| last_timeout@p(..., C) |
| |
| @script:python |
| depends on report |
| @ |
| fn << r_last_timeout.last_timeout; |
| p << r_last_timeout_const_report.p; |
| C << r_last_timeout_const_report.C; |
| @@ |
| msg = "WARNING: replace constant {} with timeout in {}".format(C, fn) |
| coccilib.report.print_report(p[0], msg); |
| |
| // ** Handle call sites where a timeout is specified by an expression |
| // ** scaled by MSEC_PER_SEC and replace with the corresponding |
| // ** K_SECONDS() expression. |
| |
| @r_last_timeout_scaled_patch |
| extends r_last_timeout |
| depends on patch |
| @ |
| // identifier K_MSEC =~ "^K_MSEC$"; |
| symbol K_MSEC; |
| identifier MSEC_PER_SEC =~ "^MSEC_PER_SEC$"; |
| expression V; |
| position p; |
| @@ |
| last_timeout@p(..., |
| ( |
| - MSEC_PER_SEC |
| + K_SECONDS(1) |
| | |
| - V * MSEC_PER_SEC |
| + K_SECONDS(V) |
| | |
| - K_MSEC(MSEC_PER_SEC) |
| + K_SECONDS(1) |
| | |
| - K_MSEC(V * MSEC_PER_SEC) |
| + K_SECONDS(V) |
| ) |
| ) |
| |
| @r_last_timeout_scaled_report_req |
| extends r_last_timeout |
| depends on report |
| @ |
| identifier MSEC_PER_SEC =~ "^MSEC_PER_SEC$"; |
| expression V; |
| position p; |
| @@ |
| last_timeout@p(..., |
| ( |
| MSEC_PER_SEC |
| | V * MSEC_PER_SEC |
| ) |
| ) |
| |
| @r_last_timeout_scaled_report_opt |
| extends r_last_timeout |
| depends on report |
| @ |
| identifier MSEC_PER_SEC =~ "^MSEC_PER_SEC$"; |
| expression V; |
| position p; |
| @@ |
| last_timeout@p(..., |
| ( |
| K_MSEC(MSEC_PER_SEC) |
| | K_MSEC(V * MSEC_PER_SEC) |
| ) |
| ) |
| |
| @script:python |
| depends on report |
| @ |
| fn << r_last_timeout.last_timeout; |
| p << r_last_timeout_scaled_report_req.p; |
| @@ |
| msg = "WARNING: use K_SECONDS() for timeout in {}".format(fn) |
| coccilib.report.print_report(p[0], msg); |
| |
| @script:python |
| depends on report |
| @ |
| fn << r_last_timeout.last_timeout; |
| p << r_last_timeout_scaled_report_opt.p; |
| @@ |
| msg = "NOTE: use K_SECONDS() for timeout in {}".format(fn) |
| coccilib.report.print_report(p[0], msg); |
| |
| // ** Handle call sites where an integer parameter is used in a |
| // ** position that requires a timeout value. |
| |
| @r_last_timeout_int_param_patch |
| extends r_last_timeout |
| depends on patch |
| @ |
| identifier FN; |
| identifier P; |
| typedef int32_t, uint32_t; |
| @@ |
| FN(..., |
| (int |
| |int32_t |
| |uint32_t |
| ) |
| P, ...) { |
| ... |
| last_timeout(..., |
| -P |
| +K_MSEC(P) |
| ) |
| ... |
| } |
| |
| @r_last_timeout_int_param_report |
| extends r_last_timeout |
| depends on report |
| @ |
| identifier FN; |
| identifier P; |
| position p; |
| typedef int32_t, uint32_t; |
| @@ |
| FN(..., |
| (int |
| |int32_t |
| |uint32_t |
| ) |
| P, ...) { |
| ... |
| last_timeout@p(..., P) |
| ... |
| } |
| |
| @script:python |
| depends on report |
| @ |
| param << r_last_timeout_int_param_report.P; |
| fn << r_last_timeout.last_timeout; |
| p << r_last_timeout_int_param_report.p; |
| @@ |
| msg = "WARNING: replace integer parameter {} with timeout in {}".format(param, fn) |
| coccilib.report.print_report(p[0], msg); |
| |
| // ** Convert timeout-valued delays in K_THREAD_DEFINE with durations |
| // ** in milliseconds |
| |
| // Select declarers where the startup delay is a timeout expression |
| // and replace with the corresponding millisecond duration. |
| @r_thread_decl_patch |
| depends on patch@ |
| declarer name K_THREAD_DEFINE; |
| identifier K_NO_WAIT =~ "^K_NO_WAIT$"; |
| identifier K_FOREVER =~ "^K_FOREVER$"; |
| expression E; |
| position p; |
| @@ |
| K_THREAD_DEFINE@p(..., |
| ( |
| - K_NO_WAIT |
| + 0 |
| | |
| - K_FOREVER |
| + -1 |
| | |
| - K_MSEC(E) |
| + E |
| ) |
| ); |
| |
| // |
| @r_thread_decl_report |
| depends on report@ |
| declarer name K_THREAD_DEFINE; |
| identifier K_NO_WAIT =~ "^K_NO_WAIT$"; |
| identifier K_FOREVER =~ "^K_FOREVER$"; |
| expression V; |
| position p; |
| @@ |
| K_THREAD_DEFINE@p(..., |
| ( |
| K_NO_WAIT |
| | |
| K_FOREVER |
| | |
| K_MSEC(V) |
| ) |
| ); |
| |
| |
| @script:python |
| depends on report |
| @ |
| p << r_thread_decl_report.p; |
| @@ |
| msg = "WARNING: replace timeout-valued delay with millisecond duration".format() |
| coccilib.report.print_report(p[0], msg); |
| |
| // ** Handle k_timer_start where the second (not last) argument is a |
| // ** constant literal. |
| |
| // Select call sites where an identifier is used for the duration timeout |
| @r_timer_duration@ |
| expression T; |
| identifier D; |
| expression I; |
| position p; |
| @@ |
| k_timer_start@p(T, D, I) |
| |
| // Select call sites where a constant literal (not identifier) is used |
| // for the timeout and replace the constant with the appropriate macro |
| @depends on patch@ |
| expression T; |
| constant C; |
| expression I; |
| position p != r_timer_duration.p; |
| @@ |
| k_timer_start@p(T, |
| ( |
| - 0 |
| + K_NO_WAIT |
| | |
| - -1 |
| + K_FOREVER |
| | |
| - C |
| + K_MSEC(C) |
| ) |
| , I) |
| |
| @r_timer_duration_report |
| depends on report |
| @ |
| expression T; |
| constant C; |
| expression I; |
| position p != r_timer_duration.p; |
| @@ |
| k_timer_start@p(T, C, I) |
| |
| @script:python |
| depends on report |
| @ |
| p << r_timer_duration_report.p; |
| C << r_timer_duration_report.C; |
| @@ |
| msg = "WARNING: replace constant {} with duration timeout in k_timer_start".format(C) |
| coccilib.report.print_report(p[0], msg); |