]> Zhao Yanbai Git Server - minix.git/commitdiff
Kernel: only reset/reload FPU state when necessary
authorDavid van Moolenbroek <david@minix3.org>
Sat, 3 Mar 2012 19:33:02 +0000 (20:33 +0100)
committerDavid van Moolenbroek <david@minix3.org>
Mon, 5 Mar 2012 21:32:14 +0000 (22:32 +0100)
kernel/arch/i386/arch_system.c
kernel/proc.c
kernel/proto.h
kernel/smp.c

index be8503a579629ee4981dbe7f3241bf39d71b1404..45549027342a797683456431955971f72d19926c 100644 (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*/);
        }
 }
 
index d385e4349ad95ae4c848195a92bff13b44dc2ad9..4595f08c2182c1ea9783b9b9cec3f499df0b5b2e 100644 (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;
        }
index e3f3a9f09479425b496bfeb5331f2b4e887d6ab5..a8288063fca9666deaf0c487f70d2b232a80305b 100644 (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 */
index 8a521f4748d047727c39c41b8c504e9303985bf4..8e2d097e58a8fddbefd9d7927517f70bd0b4af59 100644 (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);
                        }
                }