kernel: Add K_TIMEOUT_SUM() macro
The K_TIMEOUT_SUM() macro is intended as a means to add two k_timeout_t values together. This may be useful for a developer applying an exponential backoff algorithm. Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
This commit is contained in:
committed by
Maureen Helm
parent
29493ced6f
commit
e18a048c84
@@ -1665,6 +1665,22 @@ const char *k_thread_state_str(k_tid_t thread_id, char *buf, size_t buf_size);
|
||||
*/
|
||||
#define K_FOREVER Z_FOREVER
|
||||
|
||||
/**
|
||||
* @brief Add two k_timeout_t values together
|
||||
*
|
||||
* This macro adds two k_timeout_t values together. If only one value is an
|
||||
* absolute timeout, the result will be an absolute timeout. If both are
|
||||
* relative timeouts, the result will be a relative timeout. If the calculation
|
||||
* overflows, underflows or if both values are absolute timeouts, K_FOREVER
|
||||
* is returned.
|
||||
*
|
||||
* @param timeout1 First k_timeout_t value
|
||||
* @param timeout2 Second k_timeout_t value
|
||||
*
|
||||
* @return Sum of the two timeout values, or K_FOREVER if incalculable
|
||||
*/
|
||||
#define K_TIMEOUT_SUM(timeout1, timeout2) K_TICKS(z_timeout_sum(timeout1, timeout2))
|
||||
|
||||
#ifdef CONFIG_TIMEOUT_64BIT
|
||||
|
||||
/**
|
||||
@@ -1748,7 +1764,6 @@ const char *k_thread_state_str(k_tid_t thread_id, char *buf, size_t buf_size);
|
||||
* @return Timeout delay value
|
||||
*/
|
||||
#define K_TIMEOUT_ABS_CYC(t) K_TIMEOUT_ABS_TICKS(k_cyc_to_ticks_ceil64(t))
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
||||
@@ -172,6 +172,49 @@ typedef struct {
|
||||
/* The maximum duration in ticks strictly and semantically "less than" K_FOREVER */
|
||||
#define K_TICK_MAX ((k_ticks_t)(IS_ENABLED(CONFIG_TIMEOUT_64BIT) ? INT64_MAX : UINT32_MAX - 1))
|
||||
|
||||
/**
|
||||
* @brief Sum the ticks from two timeout values
|
||||
*
|
||||
* This routine determines the resulting tick value when adding two k_timeout_t
|
||||
* values together. If only one k_timeout_t value is an absolute timeout, the
|
||||
* result will be an absolute timeout. If both are relative timeouts, the
|
||||
* result will be a relative timeout. If the calculated tick value overflows,
|
||||
* underflows or if both values are absolute timeouts, it returns K_TICKS_FOREVER.
|
||||
*
|
||||
* @param t1 First k_timeout_t value
|
||||
* @param t2 Second k_timeout_t value
|
||||
*
|
||||
* @return Sum of the two timeout values in ticks, or val K_TICKS_FOREVER if incalculable
|
||||
*/
|
||||
static inline k_ticks_t z_timeout_sum(k_timeout_t t1, k_timeout_t t2)
|
||||
{
|
||||
k_ticks_t ticks1 = t1.ticks;
|
||||
k_ticks_t ticks2 = t2.ticks;
|
||||
|
||||
#ifdef CONFIG_TIMEOUT_64BIT
|
||||
if ((ticks1 == K_TICKS_FOREVER) || (ticks2 == K_TICKS_FOREVER)) {
|
||||
return K_TICKS_FOREVER;
|
||||
}
|
||||
|
||||
if (ticks1 < 0) {
|
||||
if (ticks2 < 0) {
|
||||
return K_TICKS_FOREVER; /* Both absolute timeouts */
|
||||
}
|
||||
|
||||
return ((ticks1 - INT64_MIN) < ticks2) ?
|
||||
K_TICKS_FOREVER : (ticks1 - ticks2);
|
||||
} else if (ticks2 < 0) {
|
||||
return ((ticks2 - INT64_MIN) < ticks1) ?
|
||||
K_TICKS_FOREVER : (ticks2 - ticks1);
|
||||
} else {
|
||||
return ((INT64_MAX - ticks1) < ticks2) ?
|
||||
K_TICKS_FOREVER : ticks1 + ticks2;
|
||||
}
|
||||
#else
|
||||
return ((UINT32_MAX - ticks1) < ticks2) ? K_TICKS_FOREVER : ticks1 + ticks2;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
#ifndef CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME
|
||||
|
||||
8
tests/kernel/timer/timeout/CMakeLists.txt
Normal file
8
tests/kernel/timer/timeout/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(timer_timeout)
|
||||
|
||||
FILE(GLOB app_sources src/*.c)
|
||||
target_sources(app PRIVATE ${app_sources})
|
||||
1
tests/kernel/timer/timeout/prj.conf
Normal file
1
tests/kernel/timer/timeout/prj.conf
Normal file
@@ -0,0 +1 @@
|
||||
CONFIG_ZTEST=y
|
||||
173
tests/kernel/timer/timeout/src/main.c
Normal file
173
tests/kernel/timer/timeout/src/main.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/ztest.h>
|
||||
|
||||
#ifdef CONFIG_TIMEOUT_64BIT
|
||||
/**
|
||||
* Verify that absolute timeout sums are handled correctly
|
||||
*/
|
||||
ZTEST(timeout, test_timeout_sum_absolute)
|
||||
{
|
||||
k_timeout_t abs_timeout = K_TIMEOUT_ABS_TICKS(1000);
|
||||
k_timeout_t result;
|
||||
|
||||
/* Two absolute timeouts should result in K_FOREVER */
|
||||
|
||||
result = K_TIMEOUT_SUM(abs_timeout, abs_timeout);
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
/* Absolute with K_FOREVER should result in K_FOREVER */
|
||||
|
||||
result = K_TIMEOUT_SUM(abs_timeout, K_FOREVER);
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_FOREVER, abs_timeout);
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
/* Absolute with K_NO_WAIT should return the absolute */
|
||||
|
||||
result = K_TIMEOUT_SUM(abs_timeout, K_NO_WAIT);
|
||||
zassert_true(K_TIMEOUT_EQ(result, abs_timeout),
|
||||
"Expected K_TIMEOUT_ABS_TICKS(1000)");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_NO_WAIT, abs_timeout);
|
||||
zassert_true(K_TIMEOUT_EQ(result, abs_timeout),
|
||||
"Expected K_TIMEOUT_ABS_TICKS(1000)");
|
||||
|
||||
/* Absolute + relative (no underflow) should return a new absolute */
|
||||
|
||||
result = K_TIMEOUT_SUM(abs_timeout, K_TICKS(100));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TIMEOUT_ABS_TICKS(1100)),
|
||||
"Expected K_TIMEOUT_ABS_TICKS(1100)");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(100), abs_timeout);
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TIMEOUT_ABS_TICKS(1100)),
|
||||
"Expected K_TIMEOUT_ABS_TICKS(1100)");
|
||||
|
||||
/* Limit testing: small absolute + large relative -- absolute 1st */
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TIMEOUT_ABS_TICKS(5), K_TICKS(INT64_MAX - 4));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TIMEOUT_ABS_TICKS(5), K_TICKS(INT64_MAX - 5));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TIMEOUT_ABS_TICKS(5), K_TICKS(INT64_MAX - 6));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TICKS(INT64_MIN)),
|
||||
"Expected INT64_MIN ticks");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TIMEOUT_ABS_TICKS(5), K_TICKS(INT64_MAX - 7));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TICKS(INT64_MIN + 1)),
|
||||
"Expected INT64_MIN + 1 ticks");
|
||||
|
||||
/* Limit testing: small absolute + large relative -- relative 1st */
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(INT64_MAX - 4), K_TIMEOUT_ABS_TICKS(5));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(INT64_MAX - 5), K_TIMEOUT_ABS_TICKS(5));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(INT64_MAX - 6), K_TIMEOUT_ABS_TICKS(5));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TICKS(INT64_MIN)),
|
||||
"Expected INT64_MIN ticks");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(INT64_MAX - 7), K_TIMEOUT_ABS_TICKS(5));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TICKS(INT64_MIN + 1)),
|
||||
"Expected INT64_MIN + 1 ticks");
|
||||
|
||||
/* Limit testing large absolute + small relative -- absolute 1st */
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TIMEOUT_ABS_TICKS(INT64_MAX - 5), K_TICKS(6));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TIMEOUT_ABS_TICKS(INT64_MAX - 6), K_TICKS(6));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TIMEOUT_ABS_TICKS(INT64_MAX - 7), K_TICKS(6));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TICKS(INT64_MIN)),
|
||||
"Expected INT64_MIN ticks");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TIMEOUT_ABS_TICKS(INT64_MAX - 8), K_TICKS(6));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TICKS(INT64_MIN + 1)),
|
||||
"Expected INT64_MIN + 1 ticks");
|
||||
|
||||
/* Limit testing large absolute + small relative -- relative 1st */
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(6), K_TIMEOUT_ABS_TICKS(INT64_MAX - 5));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(6), K_TIMEOUT_ABS_TICKS(INT64_MAX - 6));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(6), K_TIMEOUT_ABS_TICKS(INT64_MAX - 7));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TICKS(INT64_MIN)),
|
||||
"Expected INT64_MIN ticks");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(6), K_TIMEOUT_ABS_TICKS(INT64_MAX - 8));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TICKS(INT64_MIN + 1)),
|
||||
"Expected INT64_MIN + 1 ticks");
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Verify that relative timeout sums are handled correctly
|
||||
*/
|
||||
ZTEST(timeout, test_timeout_sum_relative)
|
||||
{
|
||||
k_timeout_t result;
|
||||
|
||||
/* Verify that normal sums work as expected */
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(1), K_TICKS(2));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TICKS(3)), "Expected 3 ticks");
|
||||
|
||||
/* K_NO_WAIT + X should return X */
|
||||
|
||||
result = K_TIMEOUT_SUM(K_NO_WAIT, K_TICKS(1));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TICKS(1)), "Expected 1 tick");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(1), K_NO_WAIT);
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TICKS(1)), "Expected 1 tick");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_NO_WAIT, K_NO_WAIT);
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_NO_WAIT), "Expected K_NO_WAIT");
|
||||
|
||||
/* K_FOREVER + anything should return K_FOREVER */
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(1), K_FOREVER);
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_FOREVER, K_TICKS(1));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_FOREVER, K_NO_WAIT);
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_NO_WAIT, K_FOREVER);
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_FOREVER, K_FOREVER);
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
/* Behavior at limits */
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(K_TICK_MAX - 1), K_TICKS(1));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TICKS(K_TICK_MAX)), "Expected K_TICK_MAX ticks");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(K_TICK_MAX - 1), K_TICKS(2));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(K_TICK_MAX), K_NO_WAIT);
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_TICKS(K_TICK_MAX)), "Expected K_TICK_MAX ticks");
|
||||
|
||||
result = K_TIMEOUT_SUM(K_TICKS(K_TICK_MAX), K_TICKS(1));
|
||||
zassert_true(K_TIMEOUT_EQ(result, K_FOREVER), "Expected K_FOREVER");
|
||||
}
|
||||
|
||||
ZTEST_SUITE(timeout, NULL, NULL, NULL, NULL, NULL);
|
||||
5
tests/kernel/timer/timeout/testcase.yaml
Normal file
5
tests/kernel/timer/timeout/testcase.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
tests:
|
||||
kernel.timer.timeout:
|
||||
tags:
|
||||
- kernel
|
||||
- timer
|
||||
Reference in New Issue
Block a user