From: David van Moolenbroek Date: Sat, 3 Mar 2012 19:33:02 +0000 (+0100) Subject: Kernel: only reset/reload FPU state when necessary X-Git-Url: http://zhaoyanbai.com/repos/man.dnssec-checkds.html?a=commitdiff_plain;h=784af1207446cb107229858b2ecd7d5ef2488d9a;p=minix.git Kernel: only reset/reload FPU state when necessary --- diff --git a/kernel/arch/i386/arch_system.c b/kernel/arch/i386/arch_system.c index be8503a57..455490273 100644 --- a/kernel/arch/i386/arch_system.c +++ b/kernel/arch/i386/arch_system.c @@ -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*/); } } diff --git a/kernel/proc.c b/kernel/proc.c index d385e4349..4595f08c2 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -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; } diff --git a/kernel/proto.h b/kernel/proto.h index e3f3a9f09..a8288063f 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -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 */ diff --git a/kernel/smp.c b/kernel/smp.c index 8a521f474..8e2d097e5 100644 --- a/kernel/smp.c +++ b/kernel/smp.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); } }