Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

k_sleep() returns incorrect remaining time 12 days after booting #79863

Open
akasona opened this issue Oct 15, 2024 · 2 comments
Open

k_sleep() returns incorrect remaining time 12 days after booting #79863

akasona opened this issue Oct 15, 2024 · 2 comments
Assignees
Labels
area: Kernel bug The issue is a bug, or the PR is fixing a bug priority: low Low impact/importance bug

Comments

@akasona
Copy link

akasona commented Oct 15, 2024

Describe the bug

k_sleep() returns zero even if the thread is woken up by k_wakeup().
The issue occurs exactly when the kernel tick count jumps over 2^32 (4,294,967,296).

In our product system, CONFIG_SYS_CLOCK_TICKS_PER_SEC=4096, it occurs 12 days (exactly 1,048,576 seconds) after booting.
In the testing system, CONFIG_SYS_CLOCK_TICKS_PER_SEC=50000, it occurs 24 hours after booting.

environment board CONFIG_PM tick source ticks per sec delay
Production nucleo_l476rg y LSE 4096 2^32 / 4096 = 1,048,576 seconds
Test nucleo_l476rg n Cortex-M Systick 50000 2^32 / 50000 = 85,899 seconds

To Reproduce

  1. the sensor interrupt calls k_wakeup() every 10 ms.
  2. the sensor_thread calls k_sleep() with longer delay.
  3. the sensor_thread wakes up every 10 ms, and k_sleep() returns non-zero value.
  4. repeat 1-3, and at some point k_sleep() returns zero even if the interrupt fires in time.
// Called by sensor interrupt every 10 ms
void data_ready_callback(void) {
    k_wakeup(sensor_thread);
}

// sensor_thread's main routine
void sensor(void) {
    while (1) {
        int32_t left_ms = k_sleep(K_MSEC(1100));
        if (left_ms == 0) {
            // handles sensor error
        }
        // normal actions continues...
    }
}

Expected behavior

If the sensor is healthy and its interrupt fires periodically, k_sleep() returns non-zero value.

Impact

I can workaround the issue to ignore k_sleep()'s return value and to calculate elapsed time in the sensor thread.

Logs and console output

Environment (please complete the following information):

  • OS: Windows
  • Toolchain: Zephyr SDK 0.16.5-1
  • Commit SHA or Version used: v3.5.0

Additional context

The cause of the problem is z_tick_sleep() implementation in kernel/sched.c.
https://github.com/zephyrproject-rtos/zephyr/blob/main/kernel/sched.c#L1173

uint32_t expected_wakeup_ticks keeps the tick count in 32bit format that the thread wakes up without disturbing.

But the expression below results incorrect, when:

  1. expected_wakeup_ticks has wrapped around (ex. 10)
  2. sys_clock_tick_get_32() is nearly wrapping around (ex. 4,294,967,280)
  3. k_ticks_t is defined as a 64bit integer type
ticks = (k_ticks_t)expected_wakeup_ticks - sys_clock_tick_get_32();

I tried to handle integer wraparound properly, and it works :)

uint32_t left_ticks = expected_wakeup_ticks - sys_clock_tick_get_32();
ticks = (k_ticks_t)(int32_t)left_ticks;
@akasona akasona added the bug The issue is a bug, or the PR is fixing a bug label Oct 15, 2024
Copy link

Hi @akasona! We appreciate you submitting your first issue for our open-source project. 🌟

Even though I'm a bot, I can assure you that the whole community is genuinely grateful for your time and effort. 🤖💙

@dkalowsk
Copy link
Contributor

The reported version is no longer on the supported list. Can this issue be reproduced in 3.7 or main?

@dkalowsk dkalowsk added the priority: low Low impact/importance bug label Oct 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Kernel bug The issue is a bug, or the PR is fixing a bug priority: low Low impact/importance bug
Projects
None yet
Development

No branches or pull requests

5 participants