TSS释疑
近日收到一位读者的来信,询问有关TSS的问题。坦率说,TSS是一个比较难理解的概念,很难理解透彻。
这位读者的问题大致如下:
“书(《软件调试》)上278-279综合我看完的理解是这样的,TR寄存器中保存的是当前任务的TSS,而后面又说任务切换时(WINDOWS下,是线程切换?)会把当前的状态复制到共享TSS段中,这么说岂不是有点乱套??因为你说TR是索引当前任务的TSS,那切换的时候前面的任务(线程)还COPY到这个共享段来干什么??。这样下来那到底这个TR指向的是谁啊
参考一网站上的资料:
所谓任务切换是指,挂起当前正在执行的任务,恢复或启动另一任务的执行。在任务切换过程中,首先,处理器中各寄存器的当前值被自动保存到TR所指定的TSS中;然后,下一任务的TSS的选择子被装入TR;最后,从TR所指定的TSS中取出各寄存器的值送到处理器的各寄存器中。由此可见,通过在TSS中保存任务现场各寄存器状态的完整映象,实现任务的切换。”
这个问题问的很深入,其中的困惑也非常有代表性。简单回答,第一段描述的是Windows操作系统使用的软件方式的任务切换,后一段描述的是x86 CPU内建的硬件方式的任务切换。
在一个实际的Windows+x86系统中,这两种切换方式都存在,大多数情况用的是第一种,但是在以下三种情况下会使用第二种:
1)处理NMI中断
2)处理双误异常
3)处理MCE异常
换句话来说,对于Windows操作系统来说,普通情况的线程调度使用的是软件方式,简单来说,就是在处理时钟中断时做线程调度,加载当前线程的上下文和更新TSS,然后中断返回,CPU便执行不同的线程了,因为TR寄存器没有更换,所以对CPU来讲,仿佛还在运行原来的任务。这样做的好处是速度快,容易移植到其它架构的CPU。
因为主要使用软件方式的任务切换,所以Windows根本没有必要为每个线程都建立一个TSS,而是创建一个TSS让大家共享,这就是书中所说的共享TSS。
但对于上面说的三种紧急情况,还得依靠硬件方式来切换任务,其实主要是切换栈。跟踪一下内核的启动过程就可以知道,内核实际上是为每个CPU准备4个TSS,三个是做紧急情况时使用,一个是给普通线程共享。
上面说的都是32位(IA-32)的情况,对于x64,CPU不再至持硬件方式的任务切换,但是引入了新的机制,在以上三种紧急情况下,CPU仍然可以自动切换栈。
这样解释还有疑问么?为什么《软件调试》书中没有如此解释呢?引用《论语》里的话来说:“不愤不启,不悱不发;举一隅不以三隅反,则不复也。” :-)