BUG: PowerPC FPSCR Not Saved on Thread Context Switch |
Q158947
Multithreaded applications compiled for Windows NT on PowerPC processors
may show incorrect or unexpected floating point exception handling
behavior. When two or more threads in a process set their floating point
masks to different values, all of the threads get the same mask value as
the thread that set its mask last.
When this problem is encountered, the exact behavior of the application
will depend on which floating point exceptions are masked and unmasked and
how the application handles exceptions that do occur. Following is a
possible scenario:
The PowerPC's floating point status and control register (FPSCR) is not being saved during thread context switches; it is being treated as a per- process resource rather than a per-thread resource.
Microsoft has confirmed this to be a problem in Microsoft Windows NT versions 3.51 and 4.0. Microsoft is researching this problem and will post new information here as it becomes available.
The only time this behavior becomes a problem is when a multithreaded
application uses different floating point exception masks for each thread.
If the application is single-threaded or if all threads use the same
floating point exception mask, the problem does not occur.
The code below demonstrates the problem. The first thread unmasks floating
point divide by zero exceptions and then spawns another thread and waits
for it to exit. The spawned thread unmasks floating point underflow
exceptions and then exits. When the first thread returns from waiting for
the second, the FPSCR is set to floating point underflow exceptions being
unmasked but floating point divide by zero exceptions being masked. Thus,
the FPSCR value of the first thread's is now set to that of the second
thread. When the first thread performs the computation, the divide by zero
error is not sent to the exception handler.
#include <windows.h>
#include <stdio.h>
#include <float.h>
DWORD WINAPI Thread (LPVOID lpvParam);
void main (int argc, char ** argv)
{
volatile float x1 = 5.0F,
x2 = 0.0F;
DWORD tid;
HANDLE hThread;
// Unmask floating point divide by zero exceptions for
// this thread.
_controlfp ((unsigned int)~_EM_ZERODIVIDE, _MCW_EM); // BP 1 here
// Create another thread
hThread = CreateThread(NULL, 0, Thread, NULL, 0, &tid);
// This will force a context switch.
WaitForSingleObject (hThread, INFINITE); // BP 2 here
CloseHandle (hThread);
// WHEN GET TO HERE, this thread's FPSCR should still
// have the FP divide by zero exception unmasked.
__try
{
x1 /= x2; // cause FP divide by zero // BP 3 here
}
__except (GetExceptionCode() == EXCEPTION_FLT_DIVIDE_BY_ZERO ?
EXCEPTION_EXECUTE_HANDLER :
EXCEPTION_CONTINUE_SEARCH)
{
// BP 4 on next line
printf ("Trapped floating point divide by zero exception\n");
_clearfp();
}
// BP 5 on next line
printf ("past floating point divide by zero exception\n");
}
// This is a dummy thread that gets the default FPSCR settings
// when created.
DWORD WINAPI Thread (LPVOID lpvParam)
{
// Unmask floating point underflow exceptions for
// this thread.
_controlfp ((unsigned int)~_EM_UNDERFLOW, _MCW_EM); // BP 6 here
return 0;
}
When this application works correctly, it should produce this output:
Trapped floating point divide by zero exception
past floating point divide by zero exception
The incorrect output is:
past floating point divide by zero exception
Additional query words: 3.51 4.00 kbdss fp floating point status control signal interrupt handler
Keywords : kbFloatPoint kbKernBase kbThread _IK kbGrpDSKernBase
Issue type : kbbug
Technology : kbWin32SDKSearch kbAudDeveloper kbSDKSearch kbWin32sSearch kbWin32SDKNT351 kbWin32SDKNT400
|
Last Reviewed: December 22, 1999 © 2001 Microsoft Corporation. All rights reserved. Terms of Use. |