• Austin Clements's avatar
    runtime: reset spinning in mspinning if work was ready()ed · b0b1a660
    Austin Clements authored
    This fixes a bug where the runtime ready()s a goroutine while setting
    up a new M that's initially marked as spinning, causing the scheduler
    to later panic when it finds work in the run queue of a P associated
    with a spinning M. Specifically, the sequence of events that can lead
    to this is:
    
    1) sysmon calls handoffp to hand off a P stolen from a syscall.
    
    2) handoffp sees no pending work on the P, so it calls startm with
       spinning set.
    
    3) startm calls newm, which in turn calls allocm to allocate a new M.
    
    4) allocm "borrows" the P we're handing off in order to do allocation
       and performs this allocation.
    
    5) This allocation may assist the garbage collector, and this assist
       may detect the end of concurrent mark and ready() the main GC
       goroutine to signal this.
    
    6) This ready()ing puts the GC goroutine on the run queue of the
       borrowed P.
    
    7) newm starts the OS thread, which runs mstart and subsequently
       mstart1, which marks the M spinning because startm was called with
       spinning set.
    
    8) mstart1 enters the scheduler, which panics because there's work on
       the run queue, but the M is marked spinning.
    
    To fix this, before marking the M spinning in step 7, add a check to
    see if work was been added to the P's run queue. If this is the case,
    undo the spinning instead.
    
    Fixes #10573.
    
    Change-Id: I4670495ae00582144a55ce88c45ae71de597cfa5
    Reviewed-on: https://go-review.googlesource.com/9332Reviewed-by: default avatarRuss Cox <rsc@golang.org>
    Run-TryBot: Austin Clements <austin@google.com>
    b0b1a660
proc1.go 92.5 KB