提问人:chaya kumar 提问时间:11/2/2023 更新时间:11/9/2023 访问量:60
线程和 ISR 之间的信号量行为
Semaphore behaviour between the thread and an ISR
问:
这个问题一直萦绕在我的脑海中,因为我是 RTOS 概念的新手。
假设任务/线程和 ISR 正在使用信号量资源。现在,中断触发器和 ISR 尝试 获取信号量资源,但被另一个任务使用。它是否会导致 ISR 的阻塞条件?通常,我们不应该阻止 ISR。OS/RTOS 如何处理这种情况? 是否有任何灌输 FreeRTOS 或 Linux 内核的解决方案/API?
答:
不应在中断上下文中使用阻止调用。大多数 RTOS 会发出错误(至少在调试版本中)并停止或以其他方式阻止您这样做。
当然,问题是ISR已经完成。如果你阻止等待一个信号量,那么什么都不会跑来实际给出它。您只能采用之前给出的信号量。
如果您确实在 ISR 中获取信号量,则必须使用非阻塞语义,即立即返回并指示信号量是否可用。根据特定的 RTOS,这可能是 sem take 的特殊版本,或者只是需要零超时参数。然而,在大多数情况下,信号量的这种使用与原子类型的简单共享变量相比没有优势。
也就是说,中断是异步的,信号量是同步原语。很难看出在 ISR 中采用信号量有意义的情况。如果你发现自己这样做,我会质疑你的设计。更可能的用法是 ISR 提供(或递增)信号量以发出等待任务的信号。
这并不难避免 - ISR 除了向线程上下文发出信号(使用信号量或事件标志)外什么都不做,然后线程上下文可以等待信号量与其他线程上下文或其他 ISR 同步(如有必要)。也就是说,如果处理中断事件需要等待其他上下文,则应将处理推迟到允许阻塞的线程上下文。例如,请参阅 FreeRTOS 中的延迟中断处理。
RTOS 在处理可以从 IST 调用哪些 API 的方式上有所不同。有些只是要求非阻塞(零超时)使用标准 API,而其他 API 则具有特定于 ISR 的版本。例如,FreeRTOS 具有 xSemaphoreTakeFromISR(),它不会阻塞。但是,我不会将这种函数的存在视为使用它有任何意义的迹象!很多 FreeRTOS 都是这样的;-)
评论
它是否会导致 ISR 的阻塞条件?
简短的回答--不。答案很长——这很复杂。
以下是通常发生的情况。如果确实需要从 ISR 获取信号量,则应为调用方指定零/无等待超时。在这种情况下,当信号量不可用时,它将立即失败并返回。如果指定了非零超时,并且信号量不可用,则它应该立即失败。
然后有一种情况是,如果指定了非零超时的 ISR,但信号量可用,这应该有效吗?这将取决于操作系统。但是,在我看来,最好是导致错误,因为系统不应该在 ISR 中使用非零超时进行奖励。
但是,如果系统实际上试图阻止 ISR 内部,会发生什么?我对此感到头晕目眩,因为具体细节因操作系统而异。简短的回答是没什么好事。长答案是“视情况而定”。然而,一种潜在的情况是......
- 系统会错误地认为中断的线程是应该阻塞的线程。
- 寄存器值和堆栈信息将(错误地)保存到该线程的控制块中。
- 该中断的线程将被(错误地)标记为已阻止,并计划一个新线程。
- 事情甚至可能在一段时间内看起来进展正常......直到它没有。
为什么不呢?如果硬件需要某种特殊的中断结束指令序列,那永远不会发生,因为上下文切换很糟糕。这可能会导致中断再也无法得到维修。
还有什么?如果存在专用中断堆栈,则该中断堆栈已被先前标识的中断线程劫持。任何后续中断都将进一步损坏该中断线程现在使用的堆栈(和保存的寄存器)。然后,在该线程重新切换上下文后,崩溃可能会显现出来。
同样,这不会带来任何好处。
我们如何阻止 ISR 内部? 忙等待/旋转,直到满足某些条件。只要被测试的条件由其他东西满足,就可以做到这一点。在 SMP 系统上,这可能是自旋锁 - 自旋锁由不同的 CPU 提供。或者,人们可能正在旋转,等待硬件设置一个就绪的位。无论哪种方式,在这种情况下,都不会在旋转的 CPU 上执行上下文切换。
下一个:使用 west 的相对路径
评论