如何在不重构的情况下跳出并在c代码中的任意位置恢复
how to jump out of and resume at arbitrary locations in c-code without refactoring
背景
我正在将 micropython 整合到我的自定义 合作 多任务处理 OS(不,我的公司不会更改为先发制人)
Micropython 使用 garbage collection,这比我分配的时间片花费更多的时间 即使没有什么可收集的,即我连续调用它两次,计时而且仍然需要很多时间。
显而易见的解决方案
是的,我可以重构 micropython 源代码,但只要有变化。 . .
理想的解决方案
理想的解决方案是调用一些会跳出的函数 void pause(&func_in_call_stack)
,保持堆栈完好无损,一直到调用堆栈顶部的函数,比如 main
.而 resume
会。 . .简历。
问题
是否可以使用 C 和汇编来实现 pause
?
更新
在我写这篇文章时,我意识到基于 C 的异常处理代码 nlr_push()/nlr_pop()
已经完成了我需要的大部分工作。
您的问题是关于实现上下文切换的。正如我们在评论中相当详尽地介绍的那样,支持上下文切换是任何多任务系统的关键特征之一,尤其是多任务 OS。由于您没有 OS 支持上下文切换,因此您正在谈论为 单任务 OS.
实现多任务
您将 OS 描述为提供某种任务队列 ("to relinquish control, a thread must simply exit its run loop") 并没有改变这一点,尽管在某种程度上我们可以将其视为语义问题。我想象这样一个系统的典型任务将通过创建和执行一系列微任务("run loop" 的工作)来运行,为每个微任务提供一个共享的、可变的内存上下文。这样的 运行 循环可以安全退出并稍后重新进入,以从它停止的地方恢复生成微任务。
在由肯定的应用程序操作定义的边界处将任务划分为微任务(即你的pause()
)将取决于 ISO C 提供的能力之外的能力。但是很有可能,它可以在一些程序集的帮助下完成,plus 某种框架支持。你至少需要这些东西:
- 一种用于记录任务当前执行上下文的机制 -- 堆栈、寄存器内容以及可能的其他细节。这本质上是特定于系统的。
- 一个与任务相关的地方,用于存储记录的执行上下文。有多种方法可以建立这样的东西。有前途的替代方案包括 (i) OS 提供的; (ii) 由某种用户态多任务系统 运行ning 在 OS 之上提供; (iii) 由编译器内置到任务中。
- 恢复记录的执行上下文的机制 -- 这也将是系统特定的。
如果OS不提供这样的功能,那么您可以考虑(现已删除)POSIX 上下文系统作为记录和恢复执行上下文的模型接口。 (请参阅 makecontext()
, swapcontext()
, getcontext()
和 setcontext()
。)但是,您需要自己实现这些,并且您可能希望包装它们以向应用程序提供更简单的接口。细节将高度依赖于硬件和底层 OS.
作为替代方案,您可以通过提供编译器来为这样的系统实现透明的多任务处理支持,这些编译器会发出经过特殊检测的代码(即比您需要的更特殊检测)。例如,考虑为您自己设计的 VM 发出字节码的编译器。结果程序 运行 所在的 VM 会自然地跟踪其中程序 运行 的状态,并且可以在每个序列的一定数量的操作码之后产生。
背景
我正在将 micropython 整合到我的自定义 合作 多任务处理 OS(不,我的公司不会更改为先发制人)
Micropython 使用 garbage collection,这比我分配的时间片花费更多的时间 即使没有什么可收集的,即我连续调用它两次,计时而且仍然需要很多时间。
显而易见的解决方案
是的,我可以重构 micropython 源代码,但只要有变化。 . .
理想的解决方案
理想的解决方案是调用一些会跳出的函数 void pause(&func_in_call_stack)
,保持堆栈完好无损,一直到调用堆栈顶部的函数,比如 main
.而 resume
会。 . .简历。
问题
是否可以使用 C 和汇编来实现 pause
?
更新
在我写这篇文章时,我意识到基于 C 的异常处理代码 nlr_push()/nlr_pop()
已经完成了我需要的大部分工作。
您的问题是关于实现上下文切换的。正如我们在评论中相当详尽地介绍的那样,支持上下文切换是任何多任务系统的关键特征之一,尤其是多任务 OS。由于您没有 OS 支持上下文切换,因此您正在谈论为 单任务 OS.
实现多任务您将 OS 描述为提供某种任务队列 ("to relinquish control, a thread must simply exit its run loop") 并没有改变这一点,尽管在某种程度上我们可以将其视为语义问题。我想象这样一个系统的典型任务将通过创建和执行一系列微任务("run loop" 的工作)来运行,为每个微任务提供一个共享的、可变的内存上下文。这样的 运行 循环可以安全退出并稍后重新进入,以从它停止的地方恢复生成微任务。
在由肯定的应用程序操作定义的边界处将任务划分为微任务(即你的pause()
)将取决于 ISO C 提供的能力之外的能力。但是很有可能,它可以在一些程序集的帮助下完成,plus 某种框架支持。你至少需要这些东西:
- 一种用于记录任务当前执行上下文的机制 -- 堆栈、寄存器内容以及可能的其他细节。这本质上是特定于系统的。
- 一个与任务相关的地方,用于存储记录的执行上下文。有多种方法可以建立这样的东西。有前途的替代方案包括 (i) OS 提供的; (ii) 由某种用户态多任务系统 运行ning 在 OS 之上提供; (iii) 由编译器内置到任务中。
- 恢复记录的执行上下文的机制 -- 这也将是系统特定的。
如果OS不提供这样的功能,那么您可以考虑(现已删除)POSIX 上下文系统作为记录和恢复执行上下文的模型接口。 (请参阅 makecontext()
, swapcontext()
, getcontext()
和 setcontext()
。)但是,您需要自己实现这些,并且您可能希望包装它们以向应用程序提供更简单的接口。细节将高度依赖于硬件和底层 OS.
作为替代方案,您可以通过提供编译器来为这样的系统实现透明的多任务处理支持,这些编译器会发出经过特殊检测的代码(即比您需要的更特殊检测)。例如,考虑为您自己设计的 VM 发出字节码的编译器。结果程序 运行 所在的 VM 会自然地跟踪其中程序 运行 的状态,并且可以在每个序列的一定数量的操作码之后产生。