// 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);