}
}
-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;
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*/);
}
}
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*/);
}
/*
/* 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;
}
_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 */
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);
}
}