繁体   English   中英

为什么 MS-DOS“不可重入”并且 DOS 中断不能调用另一个中断?

[英]Why is MS-DOS “not reentrant” and a DOS interrupt can't call another one?

这个问题纯粹是学术性的,因为现在没有人使用 MS-DOS,但我仍然想知道为什么。

在一些书籍和文章中,他们说如果您在另一本书和文章中调用 DOS 中断,可能会导致死锁。 这就是 MS-DOS 不可重入的原因。 例如, RESIDENT PROGRAMS和另一本书,如下所述:

 A interrupt occurs B interrupt handling C DOS command starts D new interrupt occurs E interrupt handling F DOS COMMAND starts G DOS command finished H interrupt finished I return to the original interrupt handling J return to original DOS command

它说,当我完成后,转到 J,它试图返回到第一个 DOS 命令被中断的点,但是由于所有 DOS 变量和堆栈都被 F 和 G 更改,当您尝试 go 回到原来的位置时中断(B),你实际上 go 回到第二个中断(E),这导致了死锁。

但就我而言,中断就像调用一样。 保存当前CS:IP,查向量,找到中断处理程序,执行,返回中断发生处。 就像call一样。 僵局怎么可能发生是没有意义的。

所以我的问题是究竟是什么导致了僵局? 一个具体的例子将不胜感激。

主要有两个原因:

DOS kernel 不是为可重入设计的

当代码应该是可重入的时,在设计时必须考虑到这一点,并且不能使用某些设计模式,例如 static 临时数据缓冲区。 避免这些设计模式并不是 DOS 作者的优先考虑,因此代码通常不是可重入的。

对于其他功能,以可重入的方式实现它们真的很难甚至是不可能的。 例如,将一个字符输出到屏幕的 function。 这是通过首先推进 cursor 然后将字符绘制到帧缓冲区中来完成的。 假设中断发生在 cursor 被推进之后但字符被绘制之前。 然后,会发生以下情况:

  1. 外部调用:cursor 从 position 1 提前到 position 2
  2. 打断!
  3. inner call: cursor 从 position 2 升级到 position 3
  4. 内部呼叫:角色绘制在 position 3
  5. 中断结束
  6. 外部调用:字符绘制在 position 3

因此,不是两个字符,而是只绘制了一个,中间有一个空白。

虽然在某些情况下可以通过关闭中断来避免此类问题,但实际上一直这样做并不是好的设计,因为这会增加中断延迟。 此外,对于文件系统等更复杂的子系统,可能需要截然不同的设计才能做到这一点。

可重入的另一个问题(与多线程安全相反)是您不能真正使用临界区。 当您是中断处理程序并尝试进入临界区但无法进入时,您将无法等待临界区空闲,因为持有它的代码在中断处理程序完成之前不会继续执行。 所以这是一个难题,正确处理这种情况真的很困难。

DOS kernel 有自己的堆栈

DOS 应用程序往往具有非常小的堆栈。 与此同时,DOS 多年来不断发展壮大,可能需要大量的堆栈空间来执行其功能。 为了解决这个问题,DOS 设计者从 DOS 2 开始添加了 DOS 内部堆栈。每当调用 DOS 中断时,中断处理程序首先切换到 DOS 堆栈,然后执行用户调用的功能。 如果在 DOS 内部尝试此操作,堆栈切换将破坏外部 DOS 调用的调用堆栈。

幸运的是,DOS 阻止您这样做:有一个“in DOS”标志可以跟踪 DOS 调用是否正在运行。 如果调用正在运行,则堆栈切换将中止并且您的 DOS 调用将失败。

顺便说一下,在编写弹出式 TSR 时这是一个大问题,关于这个主题的书籍用很长的篇幅讲述 DOS 调用时你可以做什么和不能做什么,以及如何解决这些问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM