kernel: nothread: use k_timer to sleep instead of busy waiting#101192
kernel: nothread: use k_timer to sleep instead of busy waiting#101192MaureenHelm merged 1 commit intozephyrproject-rtos:mainfrom
Conversation
8962fce to
1027682
Compare
kernel/nothread.c
Outdated
| return arch_is_in_isr(); | ||
| } | ||
|
|
||
| static volatile bool k_sleep_timedout; |
There was a problem hiding this comment.
use atomic_t for atomics
There was a problem hiding this comment.
I can use atomic_t, but this is not an "atomic" variable; there is no race to access this variable.
kernel/nothread.c
Outdated
| __ASSERT(!arch_is_in_isr(), ""); | ||
| __ASSERT_NO_MSG(!k_sleep_timedout); | ||
|
|
||
| unsigned int key; |
There was a problem hiding this comment.
use struct k_spinlock for spinlocks (critical sections)
There was a problem hiding this comment.
also define variables at the top of the function (MISRA)
There was a problem hiding this comment.
Regarding the use of a spinlock instead of irq_lock(), I think I understand why it would be preferrable in general, but in this specific case when multithreading is disabled, SMP out of the picture. With that assumption, irq_lock() achieves the same as a spinlock, while also providing me the key to pass to k_cpu_atomic_idle(). I can't use k_cpu_atomic_idle() with a spinlock key directly.
There was a problem hiding this comment.
irq_lock() achieves the same as a spinlock
irq_lock() is a legacy API and we want to avoid introducing new usage of it.
kernel/nothread.c
Outdated
| return arch_is_in_isr(); | ||
| } | ||
|
|
||
| static volatile bool k_sleep_timedout; |
There was a problem hiding this comment.
static private variables should not use a namespace which could clash with a public definition, just use sleep_timedout
lemrey
left a comment
There was a problem hiding this comment.
I can update this to use k_timer_status_get(), but could you clarify why are you suggesting that? Is it so that we avoid declaring one function and one variable, or are there other reasons?
kernel/nothread.c
Outdated
| __ASSERT(!arch_is_in_isr(), ""); | ||
| __ASSERT_NO_MSG(!k_sleep_timedout); | ||
|
|
||
| unsigned int key; |
There was a problem hiding this comment.
Regarding the use of a spinlock instead of irq_lock(), I think I understand why it would be preferrable in general, but in this specific case when multithreading is disabled, SMP out of the picture. With that assumption, irq_lock() achieves the same as a spinlock, while also providing me the key to pass to k_cpu_atomic_idle(). I can't use k_cpu_atomic_idle() with a spinlock key directly.
kernel/nothread.c
Outdated
| return arch_is_in_isr(); | ||
| } | ||
|
|
||
| static volatile bool k_sleep_timedout; |
kernel/nothread.c
Outdated
| return arch_is_in_isr(); | ||
| } | ||
|
|
||
| static volatile bool k_sleep_timedout; |
There was a problem hiding this comment.
I can use atomic_t, but this is not an "atomic" variable; there is no race to access this variable.
peter-mitsis
left a comment
There was a problem hiding this comment.
I think this is OK.
bjarki-andreasen
left a comment
There was a problem hiding this comment.
I believe we should use the existing API for waiting on a timer:
static K_TIMER_DEFINE(sleep_timer, NULL, NULL);
/* This is a fallback implementation of k_sleep() for when multi-threading is
* disabled. The main implementation is in sched.c.
*/
int32_t z_impl_k_sleep(k_timeout_t timeout)
{
__ASSERT(!arch_is_in_isr(), "");
SYS_PORT_TRACING_FUNC_ENTER(k_thread, sleep, timeout);
k_timer_start(&sleep_timer, timeout, K_FOREVER);
k_timer_status_sync(&sleep_timer);
SYS_PORT_TRACING_FUNC_EXIT(k_thread, sleep, timeout, 0);
return 0;
}
and update the implementation here:
Lines 270 to 285 in af171d4
to something like:
do {
unsigned int key = irq_lock();
if (!z_is_inactive_timeout(&timer->timeout)) {
result = *(volatile uint32_t *)&timer->status;
timer->status = 0U;
if (result > 0) {
irq_unlock(key);
break;
}
k_cpu_atomic_idle(key);
} else {
result = timer->status;
irq_unlock(key);
break;
}
} while (true);
this way we have one implementation for waiting on a timer which works with and without threads, instead of one implementation for k_sleep, and another for k_timer_get_status_sync, both of which work without threads
|
@bjarki-andreasen ok I'll try and do that change to |
|
Here #101758 |
The current implementation of k_sleep(), when multi-threading is disabled, busy waits using k_busy_wait() until the sleep timeout has expired. This patch aims to improve power efficiency of k_sleep() for single-threaded applications by starting a timer (k_timer) and idling the CPU until the timer interrupt wakes it up, thus avoiding busy-looping. Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
1027682 to
6f27a8c
Compare
|
|
@bjarki-andreasen please have another look |
bjarki-andreasen
left a comment
There was a problem hiding this comment.
That is pretty cool



The current implementation of
k_sleep(), when multi-threading is disabled, busy waits usingk_busy_wait()until the sleep timeout has expired.This patch aims to improve power efficiency of
k_sleep()for single-threaded applications by starting a timer (k_timer) and idling the CPU until the timer interrupt wakes it up, thus avoiding busy-looping.