我正在使用Win32 API来停止/启动/检查/更改线程状态。通常效果很好。有时它会失败,而我正试图找出原因。

我有一个线程通过以下方式强制在其他线程上进行上下文切换:

thread stop
fetch processor state into windows context block
read thread registers from windows context block to my own context block
write thread registers from another context block into windows context block
restart thread

效果非常好。。。。。。。。。。。。。但是,很少有上下文切换失败。
(症状:我的多线程系统在执行一个带有奇怪寄存器内容的奇怪地方时引人注目)。

上下文控制是通过以下方式完成的:
if ((suspend_count=SuspendThread(WindowsThreadHandle))<0)
   { printf("TimeSlicer Suspend Thread failure");
      ...
   }
...
Context.ContextFlags = (CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_FLOATING_POINT);
if (!GetThreadContext(WindowsThreadHandle,&Context))
   {   printf("Context fetch failure");
       ...
   }

call ContextSwap(&Context); // does the context swap

if (ResumeThread(WindowsThreadHandle)<0)
   {  printf("Thread resume failure");
        ...
   }

没有任何打印语句被执行过。我得出的结论是Windows认为上下文操作都是可靠发生的。

哦,是的,我确实知道被停止的线程何时不进行计算(例如在系统功能中),并且不会尝试停止/上下文切换该线程。我知道这一点是因为每个执行除计算之外的操作的线程都会在执行除计算之外的操作时设置特定于线程的“请勿触摸我”标志。 (设备驱动程序程序员将其视为等同于“中断禁用”指令)。

因此,我想知道上下文块内容的可靠性。
我对从上下文块中取出的各种寄存器值添加了各种健全性测试;您实际上可以确定ESP正常(在TIB中定义的堆栈区域的范围内),PC在我期望的程序中或在系统调用中,等等。在这里没有什么奇怪的。

我决定检查条件码位(EFLAGS)是否已正确读出。如果这是错误的,则它将导致切换的任务在其状态为“错误分支”时采取“错误分支”
已恢复。因此,根据英特尔引用手册(http://en.wikipedia.org/wiki/FLAGS_register),我添加了以下代码来验证所声称的EFLAGS寄存器是否包含仅类似于EFLAGS的内容。
   mov        eax, Context.EFlags[ebx]  ; ebx points to Windows Context block
   mov        ecx, eax                ; check that we seem to have flag bits
   and        ecx, 0FFFEF32Ah         ; where we expect constant flag bits to be
   cmp        ecx, 000000202h         ; expected state of constant flag bits
   je         @f
   breakpoint                         ; trap if unexpected flag bit status
@@:

在我的Win 7 AMD Phenom II X6 1090T(十六进制核心)上,
它偶尔会在断点处捕获,ECX = 0200h。在我的Win 7 Intel i7系统上失败。我会忽略这一点,
就像我怀疑的那样,它暗示着EFLAGS的存储不正确。

根据我对Intel(以及AMD)引用手册的阅读,保留位1,并且始终将其值设置为“1”。不是我在这里看到的。

显然,MS通过在线程停止时执行复杂的操作来填充上下文块。我希望他们能够准确地存储状态。此位未正确存储。
如果他们没有正确存储此位,他们还不存储什么?

为什么有时/应该为零的任何解释?

编辑:我的代码在捕获断点时转储了寄存器和堆栈。
堆栈区域包含上下文块作为局部变量。
EAX和上下文块中EFLAGS的适当偏移量的堆栈中的值都包含值0244h。因此,上下文块中的值确实是错误的。

EDIT2:我将掩码和比较值更改为
    and        ecx, 0FFFEF328h         ; was FFEF32Ah where we expect flag bits to be
    cmp        ecx, 000000200h

这似乎运行可靠,没有任何投诉。显然,Win7并没有正确执行eflags的第1位,这似乎无关紧要。

仍然对解释感兴趣,但是显然这并不是我偶尔发生上下文切换崩溃的原因。

最佳答案

微软有悠久的历史,一直在不真正使用的地方浪费几分钱。 Raymond Chen举了很多例子,例如使用未字节对齐的指针的低位。

在这种情况下,Windows可能需要将其某些线程上下文存储在现有的CONTEXT结构中,并决定在EFLAGS中使用其他未使用的位。无论如何,您什么也做不了,当您调用SetThreadContext时,Windows会收回该位。

关于multithreading - x86保留的EFLAGS位1 == 0 : how can this happen?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22777727/

10-11 15:55