Intel floating-point initialization

Xavier Leroy (Xavier.Leroy@inria.fr)
Thu, 14 May 1998 10:55:49 +0200


Two users of LinuxThreads on SMP Intel machines reported occasional
floating-point errors in their multithreaded programs: sometimes they
would get NaNs instead of the correct results. One of them noticed
that the problem goes away if he put asm("finit") at the beginning of
his threads.

This made me suspect that there might be something wrong in FPU
initialization when a new thread is created, on Intel SMP. Indeed,
at the end of copy_thread in arch/i386/kernel/process.c, we have:

if (last_task_used_math == current)
__asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));

This seems very wrong on an SMP system, as last_task_used_math is
meaningless on an SMP system.

The patch below fixes copy_thread to make it consistent with the way
floating-point context is handled in the remainder of
arch/i386/kernel/process.c. My user tested the patch and it worked
for him.

There are actually two patches, one for 2.0.33 and the other for
recent 2.1.xx kernels. Same changes, different contexts.

- Xavier Leroy

--------------------------------------------------

--- linux-2.1.98/arch/i386/kernel/process.c~ Thu May 14 10:36:22 1998
+++ linux-2.1.98/arch/i386/kernel/process.c Thu May 14 10:37:21 1998
@@ -528,7 +528,11 @@
*/
p->tss.bitmap = sizeof(struct thread_struct);

- if (last_task_used_math == current)
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU)
+#else
+ if (last_task_used_math == current)
+#endif
__asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));

return 0;

--------------------------------------------------

--- linux-2.0.33/arch/i386/kernel/process.c~ Wed Nov 19 10:41:21 1997
+++ linux-2.0.33/arch/i386/kernel/process.c Wed May 13 11:46:31 1998
@@ -493,7 +493,11 @@
p->tss.bitmap = offsetof(struct thread_struct,io_bitmap);
for (i = 0; i < IO_BITMAP_SIZE+1 ; i++) /* IO bitmap is actually SIZE+1 */
p->tss.io_bitmap[i] = ~0;
- if (last_task_used_math == current)
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU)
+#else
+ if (last_task_used_math == current)
+#endif
__asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu