Kernel: only reset/reload FPU state when necessary

This commit is contained in:
David van Moolenbroek 2012-03-03 20:33:02 +01:00
parent a615a7d4d2
commit c8c9565a03
4 changed files with 15 additions and 18 deletions

View file

@ -274,24 +274,27 @@ PUBLIC void fpu_init(void)
}
}
PUBLIC void save_local_fpu(struct proc *pr)
PUBLIC void save_local_fpu(struct proc *pr, int retain)
{
/* Save process FPU context. If the 'retain' flag is set, keep the FPU
* state as is. If the flag is not set, the state is undefined upon
* return, and the caller is responsible for reloading a proper state.
*/
if(!is_fpu())
return;
/* Save changed FPU context. */
if(osfxsr_feature) {
fxsave(pr->p_fpu_state.fpu_save_area_p);
fninit();
} else {
fnsave(pr->p_fpu_state.fpu_save_area_p);
if (retain)
(void) frstor(pr->p_fpu_state.fpu_save_area_p);
}
}
PUBLIC void save_fpu(struct proc *pr)
{
int r;
#ifdef CONFIG_SMP
if (cpuid != pr->p_cpu) {
int stopped;
@ -316,13 +319,7 @@ PUBLIC void save_fpu(struct proc *pr)
if (get_cpulocal_var(fpu_owner) == pr) {
disable_fpu_exception();
save_local_fpu(pr);
/* The state may now be reset, and the caller does not expect
* this. Immediately restore the saved state.
*/
r = restore_fpu(pr);
assert(r == OK);
save_local_fpu(pr, TRUE /*retain*/);
}
}

View file

@ -1878,7 +1878,7 @@ PUBLIC void copr_not_available_handler(void)
local_fpu_owner = get_cpulocal_var_ptr(fpu_owner);
if (*local_fpu_owner != NULL) {
assert(*local_fpu_owner != p);
save_local_fpu(*local_fpu_owner);
save_local_fpu(*local_fpu_owner, FALSE /*retain*/);
}
/*
@ -1889,7 +1889,7 @@ PUBLIC void copr_not_available_handler(void)
/* Restoring FPU state failed. This is always the process's own
* fault. Send a signal, and schedule another process instead.
*/
*local_fpu_owner = NULL;
*local_fpu_owner = NULL; /* release FPU */
cause_sig(proc_nr(p), SIGFPE);
return;
}

View file

@ -34,7 +34,7 @@ _PROTOTYPE( void context_stop, (struct proc * p) );
_PROTOTYPE( void context_stop_idle, (void) );
_PROTOTYPE( int restore_fpu, (struct proc *) );
_PROTOTYPE( void save_fpu, (struct proc *) );
_PROTOTYPE( void save_local_fpu, (struct proc *) );
_PROTOTYPE( void save_local_fpu, (struct proc *, int retain) );
_PROTOTYPE( void fpu_sigcontext, (struct proc *, struct sigframe *fr, struct sigcontext *sc) );
/* main.c */

View file

@ -168,12 +168,12 @@ PUBLIC void smp_sched_handler(void)
RTS_SET(p, RTS_PROC_STOP);
}
if (flgs & SCHED_IPI_SAVE_CTX) {
/* all context have been save already, FPU remains */
/* all context has been saved already, FPU remains */
if (proc_used_fpu(p) &&
get_cpulocal_var(fpu_owner) == p) {
disable_fpu_exception();
save_local_fpu(p);
/* we re preparing to migrate somewhere else */
save_local_fpu(p, FALSE /*retain*/);
/* we're preparing to migrate somewhere else */
release_fpu(p);
}
}