我用 C 语言实现了一个循环调度程序,它循环执行 3 个任务。我想对我的任务进行时间切片,这意味着当任务花费的时间超过预先确定的超时值x时,它会被中断并开始下一个任务。
在调度程序的循环中,我在启动任务之前使用
setjmp()
保存上下文
while(1) {
int jump = setjmp(jmpbuf);
if (jump == 1) {
printf("TASK TOOK TOO LONG, SCHEDULING NEXT ONE INSTEAD.\n");
} else {
taskRun(sched->current);
}
sched->current = sched->current->next;
}
使用 esp32s3 上的定时器组 0,我设置了一个警报,该警报触发一个具有处理程序
my_isr
的中断,该处理程序会重置中断和警报寄存器并对之前保存的上下文执行 longjmp
。
void my_isr() {
printf("Panic!\n");
TIMG_INT_CLR_TIMERS_REG |= BIT(0);
reset(); //this resets the registers in timer group 0 and reenables the alarm.
longjmp(jmpbuf, 1);
}
第一次任务耗时过长,触发警报并正确抛出中断并调度下一个任务。但进一步,当警报再次触发时(我可以看到,因为警报位确实翻转),永远不会引发中断。
就我而言,我高度怀疑
longjmp
在某种程度上有责任,因为当我将 my_isr
修改为仅调用 reset()
然后返回(返回到调用 ISR 之前正在执行的任务)时,它是确实能够抛出其他后续中断。尽管问题的根源可能完全不同。
我没有找到解决这个问题的决定性方法,您对如何解决有什么想法吗?请注意,我必须使用
longjmp
。
除了评论中提到的
setjmp()
/longjmp()
的问题之外,您的主要错误是:
这也解释了为什么你的实验没有
longjmp()
有效:ISR 完成了中断服务。
您可能会在特定条件下逃脱,在这种情况下,您“确切地”知道您在机器级别上正在做什么,并且有如此多的守卫,以至于源将永远不会在这些条件之外使用。为此,您需要潜入目标的机房。所以一般规则是:不要这样做。它不便于携带,并且会比您想象的更早损坏。