Kernel: only reset/reload FPU state when necessary
This commit is contained in:
parent
a615a7d4d2
commit
c8c9565a03
4 changed files with 15 additions and 18 deletions
|
@ -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*/);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue