Ticket #4391 (closed bug: fixed)
forkIO threads do not properly save/restore the floating point environment
|Reported by:||draconx||Owned by:|
|Operating System:||Unknown/Multiple||Architecture:||x86_64 (amd64)|
|Type of failure:||None/Unknown||Difficulty:|
|Test Case:||Blocked By:|
When using forkIO threads, the floating point environment is not correctly saved and/or restored on context switches. This causes floating point state to leak between the threads.
For example, if two threads (call them A and B) are created, and thread A changes the rounding direction, computations in thread B will be carried out under the rounding direction set by A, and vice versa. Likewise, any exceptions raised by computations in thread A are visible in thread B.
If forkIO threads are not intended to be used with floating point, this should be spelled out explicitly in the documentation rather than some vague notion of avoiding "thread local state".
I've attached a short test program which demonstrates this issue. For portability, it uses standard C library functions to manipulate the floating point environment. It prints the following when compiled with GHC (parenthetical statements added):
A: ToNearest (default rounding mode) A: True B: ToNearest B: TowardZero B: Infinity (result of division by 0) A: [DivByZero] (A sees B's exception) A: TowardZero (A sees B's rounding direction) A: False
If we use OS threads (which properly save/restore the floating point environment):
A: ToNearest A: True B: ToNearest B: TowardZero B: Infinity (result of division by zero) A:  (no new exceptions are visible) A: ToNearest (rounding direction is unchanged) A: True