Date: Wed, 20 Feb 2019 02:40:38 +0000 (UTC) From: Bruce Evans <bde@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r344332 - head/sys/x86/x86 Message-ID: <201902200240.x1K2ec5b075465@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: bde Date: Wed Feb 20 02:40:38 2019 New Revision: 344332 URL: https://svnweb.freebsd.org/changeset/base/344332 Log: Fix hangs in r341810 waiting for AP startup. idle_td is dereferenced without thread-locking it to make its contents is invariant, and was accessed without telling the compiler that its contents is invariant. Some compilers optimized accesses to the supposedly invariant contents by moving the critical checks for changes outside of the loop that waits for changes. Fix this using atomic ops. This bug only showed up for the following configuration: a Turion2 system, amd64 kernels, compiled by gcc, and SCHED_4BSD. clang fails to do the optimization with all CFLAGS that I tried, because it doesn't fully optimize the '__asm __volatile' for cpu_spinwait() although this asm has no memory clobber. gcc only does the optimization with most CFLAGS. I mostly used -Os with all compilers. i386 works because gcc -m32 -Os only moves 1 or the 2 accesses outside of the loop. Non-Turion2 systems and SCHED_ULE worked due to different timing (when all APs start before the BP checks them outside of the loop). Reviewed by: kib Modified: head/sys/x86/x86/mp_x86.c Modified: head/sys/x86/x86/mp_x86.c ============================================================================== --- head/sys/x86/x86/mp_x86.c Wed Feb 20 02:14:41 2019 (r344331) +++ head/sys/x86/x86/mp_x86.c Wed Feb 20 02:40:38 2019 (r344332) @@ -1088,8 +1088,8 @@ smp_after_idle_runnable(void *arg __unused) for (cpu = 1; cpu < mp_ncpus; cpu++) { idle_td = pcpu_find(cpu)->pc_idlethread; - while (idle_td->td_lastcpu == NOCPU && - idle_td->td_oncpu == NOCPU) + while (atomic_load_int(&idle_td->td_lastcpu) == NOCPU && + atomic_load_int(&idle_td->td_oncpu) == NOCPU) cpu_spinwait(); kmem_free((vm_offset_t)bootstacks[cpu], kstack_pages * PAGE_SIZE);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201902200240.x1K2ec5b075465>