我正在研究各种操作系统设计,希望为DCPU-16编写一个简单的多任务操作系统。然而,我读到的所有关于抢占式多任务实现的东西都是围绕着中断的。这听起来像是在16位硬件和软件的时代,协作多任务更常见,但这要求每个程序在编写时都考虑到多任务。
有没有办法在无中断架构上实现抢占式多任务?我所能想到的就是一个可以动态切换任务的解释器,但这会对性能造成很大的影响(如果它必须解析每个操作,并且不让任何东西在本地运行,我想可能会有10-20x+的量级)。
发布于 2012-04-09 13:18:24
抢占式多任务通常是通过让中断例程将状态改变/感兴趣的事件发送到调度器来实现的,调度器根据优先级决定挂起哪些任务以及启动/继续哪些新任务。但是,当正在运行的任务调用OS例程时,可能会发生其他有趣的事件,这可能具有相同的效果。
但重要的是,某个事件在某个地方被记录下来,调度器决定运行谁。因此,您可以使所有此类事件信号/调度仅在操作系统调用时发生。
您可以在各种任务应用程序代码中的“方便”点添加对调度器的异常调用,以使系统更频繁地切换。它是否只是切换,还是使用一些背景信息,例如自上次调用以来经过的时间是调度程序的详细信息。
您的系统将不会像由中断驱动的系统那样具有响应能力,但是您已经通过选择CPU放弃了这一点。
发布于 2012-04-09 13:31:11
实际上,是的。最有效的方法是简单地在加载器中修补运行时。内核/守护进程可以自定义补丁,以获得更好的响应能力。更好的是,如果你可以访问所有的源代码,你可以在编译器中打补丁。
补丁可以由各种分布式调度器组成。可以对每个程序打补丁,使其具有非常低的延迟计时器;在加载时,它将设置计时器,并且在每次从调度器返回时,它将重置计时器。一种简单的方法将允许代码简单地执行
if (timer - start_timer) yield to scheduler;这不会产生太大的性能影响。主要的问题是找到好的切入点把它们放进去。在每个函数调用之间是一个开始,检测循环并插入它们是原始的,但如果您确实需要抢占响应,则有效。
它不是完美的,但它会工作的。
主要的问题是确保计时器返回是低延迟的;这样它只是一个比较和分支。此外,以某种方式处理异常-代码中导致无限循环的错误。从技术上讲,您可以使用相当简单的硬件看门狗定时器,并在CPU上断言重置,而无需清除任何RAM;RAM中的例程将是重置向量点的位置,它将检查堆栈并将堆栈展开回程序调用(从而使程序崩溃,但保留其他所有内容)。这有点像一种蛮力,如果所有其他的都失败了,就会使程序崩溃。或者你可以通过这种方式将其更改为多任务,重置为中断,但这要困难得多。
So...yes。这是可能的,但很复杂;使用来自JIT编译器和动态翻译器的技术(仿真器使用它们)。
这是一个有点混乱的解释,我知道,但我很累。如果不是很清楚,我可以明天再来清理。
顺便说一句,在CPU中间程序上断言重置听起来很疯狂,但它是一种久经考验的技术。Windows的早期版本甚至在兼容模式下运行,我认为386是正确的,因为没有办法从16位模式切换回32位模式。其他处理器和OSes也做到了这一点。
编辑:所以我研究了一下DCPU是什么,哈哈。它不是真正的CPU。我不知道你是否可以在诺奇的模拟器中断言重置,我会问他。也就是说,这是一种方便的技术。
发布于 2012-04-09 13:28:08
我认为你的评估是正确的。如果调度器可以(在无变化的字典意义上)中断一个正在运行的任务并自动切换到另一个任务,就会发生抢占式多任务。因此,必须有某种类型的参与者来促使调度程序采取行动。如果没有中断设备(在变形的技术意义上),那么在一般情况下,您几乎无能为力。
但是,不是切换到完整的解释器,而是动态地重新编写所提供的程序代码。因此,在进入进程之前,调度器知道整个进程的状态,包括它将要进入的程序计数器值。然后,它可以从那里向前扫描,用跳转回调度器来替换,比方说,第20个指令代码或下一个跳转指令代码,这些指令代码不是立即在程序计数器处。当进程返回时,调度器将原始指令放回。如果它是一个跳转(有条件的或其他的),那么它也会适当地影响跳转。
当然,只有当程序代码不动态修改自身时,此方案才有效。在这种情况下,你可以对它进行预处理,这样你就可以提前知道跳跃在哪里,而不需要线性搜索。如果编写良好的自我修改代码愿意指定所有可能被修改的地址,那么从技术上讲,您可以允许编写良好的自我修改代码,从而明确避免在调度程序的动态修改中出现这种情况。
你最终会运行一个解释器,但仅仅是为了跳转。
https://stackoverflow.com/questions/10068847
复制相似问题