概念
使CPU空闲会导致内核暂停所有操作,直到事件(通常是中断)
唤醒CPU。在常规系统中,idle线程负责此操作。但是,在某些受约束的系统中,可能是另一个线程承担此职责。
实现
使CPU空闲
使CPU空闲很简单:调用k_cpu_idle()
API。CPU将停止执行指令,直到事件发生。最有可能的是,该函数将在循环中调用。
请注意,在某些体系结构中,在
k_cpu_idle()
返回时将无条件的解除中断。
static k_sem my_sem;
void my_isr(void *unused)
{
k_sem_give(&my_sem);
}
void main(void)
{
k_sem_init(&my_sem, 0, 1);
/* wait for semaphore from ISR, then do related work */
for (;;) {
/* wait for ISR to trigger work to perform */
if (k_sem_take(&my_sem, K_NO_WAIT) == 0) {
/* ... do processing */
}
/* put CPU to sleep to save power */
k_cpu_idle();
}
}
原子方式使 CPU 空闲
在使CPU空闲之前,可能需要以原子方式执行一些工作。在这种情况下,应改用k_cpu_atomic_idle()
。
实际上,在前面的示例中存在一个争用条件:中断可能发生在获取信号量获取和使CPU再次空闲之间。在某些系统中,这可能会导致CPU空闲,从而完全挂起系统。为了防止这种情况,应该使用k_cpu_atomic_idle()
,如本例所示。
static k_sem my_sem;
void my_isr(void *unused)
{
k_sem_give(&my_sem);
}
void main(void)
{
k_sem_init(&my_sem, 0, 1);
for (;;) {
unsigned int key = irq_lock();
/*
* Wait for semaphore from ISR; if acquired, do related work, then
* go to next loop iteration (the semaphore might have been given
* again); else, make the CPU idle.
*/
if (k_sem_take(&my_sem, K_NO_WAIT) == 0) {
irq_unlock(key);
/* ... do processing */
} else {
/* put CPU to sleep to save power */
k_cpu_atomic_idle(key);
}
}
}