Commit d446ba99 authored by Austin Clements's avatar Austin Clements

runtime: document stack barrier synchronization rules

Change-Id: I545e53561f37bceabd26d814d272cecc3ff19847
Reviewed-on: https://go-review.googlesource.com/18024Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent f90b48e0
...@@ -102,6 +102,26 @@ ...@@ -102,6 +102,26 @@
// enabling write barriers globally during the concurrent scan phase. // enabling write barriers globally during the concurrent scan phase.
// However, traditionally, write barriers are not enabled during this // However, traditionally, write barriers are not enabled during this
// phase. // phase.
//
// Synchronization
// ---------------
//
// For the most part, accessing and modifying stack barriers is
// synchronized around GC safe points. Installing stack barriers
// forces the G to a safe point, while all other operations that
// modify stack barriers run on the G and prevent it from reaching a
// safe point.
//
// Subtlety arises when a G may be tracebacked when *not* at a safe
// point. This happens during sigprof. For this, each G has a "stack
// barrier lock" (see gcLockStackBarriers, gcUnlockStackBarriers).
// Operations that manipulate stack barriers acquire this lock, while
// sigprof tries to acquire it and simply skips the traceback if it
// can't acquire it. There is one exception for performance and
// complexity reasons: hitting a stack barrier manipulates the stack
// barrier list without acquiring the stack barrier lock. For this,
// gentraceback performs a special fix up if the traceback starts in
// the stack barrier function.
package runtime package runtime
...@@ -321,6 +341,8 @@ func setNextBarrierPC(pc uintptr) { ...@@ -321,6 +341,8 @@ func setNextBarrierPC(pc uintptr) {
// //
//go:nosplit //go:nosplit
func gcLockStackBarriers(gp *g) { func gcLockStackBarriers(gp *g) {
// Disable preemption so scanstack cannot run while the caller
// is manipulating the stack barriers.
acquirem() acquirem()
for !atomic.Cas(&gp.stackLock, 0, 1) { for !atomic.Cas(&gp.stackLock, 0, 1) {
osyield() osyield()
......
...@@ -233,7 +233,7 @@ type g struct { ...@@ -233,7 +233,7 @@ type g struct {
sched gobuf sched gobuf
syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc
syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc
stkbar []stkbar // stack barriers, from low to high stkbar []stkbar // stack barriers, from low to high (see top of mstkbar.go)
stkbarPos uintptr // index of lowest stack barrier not hit stkbarPos uintptr // index of lowest stack barrier not hit
stktopsp uintptr // expected sp at top of stack, to check in traceback stktopsp uintptr // expected sp at top of stack, to check in traceback
param unsafe.Pointer // passed parameter on wakeup param unsafe.Pointer // passed parameter on wakeup
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment