I'm running kernel 2.2.14 (based on linux-2.2.14-000715.tar.gz) and
found a floating point calculation sometimes results an incorrect
value.
I think the problem is last 'if' statement in setup_sigcontext().
owned_fp = (current == last_task_used_math);
err |= __put_user(owned_fp, &sc->sc_ownedfp);
if (current->used_math) { /* fp is active. */
set_cp0_status(ST0_CU1, ST0_CU1);
err |= save_fp_context(sc);
last_task_used_math = NULL;
regs->cp0_status &= ~ST0_CU1;
current->used_math = 0;
}
This code can discard other task's FPU context in certain situations.
The scenario is:
(-2) Task_A executes FP insns.
(-1) Task_B executes FP insns.
(0) Task_C executes FP insns.
# save Task_B's FPU context.
# init Task_C's FPU context.
(1) Context switch (Task_C to Task_A).
(2) Task_A catch a signal.
setup_sigcontext() and restore_sigcontext() is called.
# Task_A's used_math was 1 and owned_fp was 0,
# so last_task_used_math becomes NULL.
(3) Context switch (Task_A to Task_B).
(4) Task_B executes FP insns.
# restore Task_B's FPU context. (discard Task_C's FPU context)
(5) Context switch (Task_B to Task_C).
(6) Task_C execute FP insns. (with Task_B's FPU context!)
I modified the 'if' statement as follows and the problem seems to be
fixed.
if (owned_fp) { /* fp is active. */
...
}
Is this the right fix?
---
Atsushi Nemoto
|