git: 755efb8d8fca - main - x86: Copy the FPU/XSAVE state from the creating thread to new threads.

John Baldwin jhb at FreeBSD.org
Fri Mar 12 17:49:26 UTC 2021


The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=755efb8d8fcacc6607bc46469750d78497f89378

commit 755efb8d8fcacc6607bc46469750d78497f89378
Author:     John Baldwin <jhb at FreeBSD.org>
AuthorDate: 2021-03-12 17:47:41 +0000
Commit:     John Baldwin <jhb at FreeBSD.org>
CommitDate: 2021-03-12 17:47:41 +0000

    x86: Copy the FPU/XSAVE state from the creating thread to new threads.
    
    POSIX states that new threads created via pthread_create() should
    inherit the "floating point environment" from the creating thread.
    
    Discussed with: kib
    MFC after:      1 week
    Sponsored by:   Netflix
    Differential Revision:  https://reviews.freebsd.org/D29204
---
 sys/amd64/amd64/vm_machdep.c | 10 ++++++----
 sys/i386/i386/vm_machdep.c   | 12 +++++++++---
 2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
index 76f7f400dd9c..f10d0339a65a 100644
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -564,16 +564,18 @@ cpu_copy_thread(struct thread *td, struct thread *td0)
 
 	pcb2 = td->td_pcb;
 
+	/* Ensure that td0's pcb is up to date. */
+	fpuexit(td0);
+	if (td0 == curthread)
+		update_pcb_bases(td0->td_pcb);
+
 	/*
 	 * Copy the upcall pcb.  This loads kernel regs.
 	 * Those not loaded individually below get their default
 	 * values here.
 	 */
-	if (td0 == curthread)
-		update_pcb_bases(td0->td_pcb);
 	bcopy(td0->td_pcb, pcb2, sizeof(*pcb2));
-	clear_pcb_flags(pcb2, PCB_FPUINITDONE | PCB_USERFPUINITDONE |
-	    PCB_KERNFPU);
+	clear_pcb_flags(pcb2, PCB_KERNFPU);
 	pcb2->pcb_save = get_pcb_user_save_pcb(pcb2);
 	bcopy(get_pcb_user_save_td(td0), pcb2->pcb_save,
 	    cpu_max_ext_state_size);
diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c
index d3182cb224bf..502de6e7f38f 100644
--- a/sys/i386/i386/vm_machdep.c
+++ b/sys/i386/i386/vm_machdep.c
@@ -428,14 +428,21 @@ cpu_copy_thread(struct thread *td, struct thread *td0)
 	/* Point the pcb to the top of the stack. */
 	pcb2 = td->td_pcb;
 
+	/* Ensure that td0's pcb is up to date. */
+	if (td0 == curthread)
+		td0->td_pcb->pcb_gs = rgs();
+	critical_enter();
+	if (PCPU_GET(fpcurthread) == td0)
+		npxsave(td0->td_pcb->pcb_save);
+	critical_exit();
+
 	/*
 	 * Copy the upcall pcb.  This loads kernel regs.
 	 * Those not loaded individually below get their default
 	 * values here.
 	 */
 	bcopy(td0->td_pcb, pcb2, sizeof(*pcb2));
-	pcb2->pcb_flags &= ~(PCB_NPXINITDONE | PCB_NPXUSERINITDONE |
-	    PCB_KERNNPX);
+	pcb2->pcb_flags &= ~PCB_KERNNPX;
 	pcb2->pcb_save = get_pcb_user_save_pcb(pcb2);
 	bcopy(get_pcb_user_save_td(td0), pcb2->pcb_save,
 	    cpu_max_ext_state_size);
@@ -463,7 +470,6 @@ cpu_copy_thread(struct thread *td, struct thread *td0)
 	pcb2->pcb_esp = (int)td->td_frame - sizeof(void *); /* trampoline arg */
 	pcb2->pcb_ebx = (int)td;			    /* trampoline arg */
 	pcb2->pcb_eip = (int)fork_trampoline + setidt_disp;
-	pcb2->pcb_gs = rgs();
 	/*
 	 * If we didn't copy the pcb, we'd need to do the following registers:
 	 * pcb2->pcb_cr3:	cloned above.


More information about the dev-commits-src-all mailing list