在 ESP32S3 裸机上使用 setjmp/longjmp 使用定时器对任务进行时间切片

问题描述 投票:0回答:1

我用 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

c interrupt esp32 bare-metal setjmp
1个回答
0
投票

除了评论中提到的

setjmp()
/
longjmp()
的问题之外,您的主要错误是:

  • 您可以在任何中断服务级别之外的主线程中创建“闭包”。
  • 您从 ISR 跳回该位置,该位置无法完成其中断服务。
  • 如果再次触发same中断,它不会调用ISR,因为它之前的服务还没有完成,仍然处于阻塞状态。

这也解释了为什么你的实验没有

longjmp()
有效:ISR 完成了中断服务。

您可能会在特定条件下逃脱,在这种情况下,您“确切地”知道您在机器级别上正在做什么,并且有如此多的守卫,以至于源将永远不会在这些条件之外使用。为此,您需要潜入目标的机房。所以一般规则是:不要这样做。它不便于携带,并且会比您想象的更早损坏。

© www.soinside.com 2019 - 2024. All rights reserved.