diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-12-05 23:09:51 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-12-05 23:09:51 +0000 |
commit | c43137e800bb9ca2ecda0a6b6189e0eb5c22f0d7 (patch) | |
tree | df5d750d82dff84b98ec03163cc8c2b2552a559a /libgo/go/runtime/proc.go | |
parent | e4a9a572770b48375561c7ca424eb94eb45a9fcb (diff) |
runtime: add precise stack scan support
This CL adds support of precise stack scan using stack maps to
the runtime. The stack maps are generated by the compiler (if
supported). Each safepoint is associated with a (real or dummy)
landing pad, and its "type info" in the exception table is a
pointer to the stack map. When a stack is scanned, the stack map
is found by the stack unwinding code by inspecting the exception
table (LSDA).
For precise stack scan we need to unwind the stack. There are
three cases:
- If a goroutine is scanning its own stack, it can unwind the
stack and scan the frames.
- If a goroutine is scanning another, stopped, goroutine, it
cannot directly unwind the target stack. We handle this by
switching (runtime.gogo) to the target g, letting it unwind
and scan the stack, and switch back.
- If we are scanning a goroutine that is blocked in a syscall,
we send a signal to the target goroutine's thread, and let the
signal handler unwind and scan the stack. Extra care is needed
as this races with enter/exit syscall.
Currently this is only implemented on linux.
Reviewed-on: https://go-review.googlesource.com/c/140518
From-SVN: r266832
Diffstat (limited to 'libgo/go/runtime/proc.go')
-rw-r--r-- | libgo/go/runtime/proc.go | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go index bb16924e01c..ef166cb9d28 100644 --- a/libgo/go/runtime/proc.go +++ b/libgo/go/runtime/proc.go @@ -528,6 +528,8 @@ func schedinit() { sched.maxmcount = 10000 + usestackmaps = probestackmaps() + mallocinit() mcommoninit(_g_.m) cpuinit() // must run before alginit @@ -891,7 +893,49 @@ loop: case _Gcopystack: // Stack being switched. Go around again. - case _Grunnable, _Gsyscall, _Gwaiting: + case _Gsyscall: + if usestackmaps { + // Claim goroutine by setting scan bit. + // Racing with execution or readying of gp. + // The scan bit keeps them from running + // the goroutine until we're done. + if castogscanstatus(gp, s, s|_Gscan) { + if gp.scanningself { + // Don't try to scan the stack + // if the goroutine is going to do + // it itself. + // FIXME: can this happen? + restartg(gp) + break + } + if !gp.gcscandone { + // Send a signal to let the goroutine scan + // itself. This races with enter/exitsyscall. + // If the goroutine is not stopped at a safepoint, + // it will not scan the stack and we'll try again. + mp := gp.m + noteclear(&mp.scannote) + gp.scangcw = uintptr(unsafe.Pointer(gcw)) + tgkill(getpid(), _pid_t(mp.procid), _SIGURG) + + // Wait for gp to scan its own stack. + notesleep(&mp.scannote) + + if !gp.gcscandone { + // The signal delivered at a bad time. + // Try again. + restartg(gp) + break + } + } + restartg(gp) + break loop + } + break + } + fallthrough + + case _Grunnable, _Gwaiting: // Claim goroutine by setting scan bit. // Racing with execution or readying of gp. // The scan bit keeps them from running @@ -954,6 +998,11 @@ loop: // The GC requests that this routine be moved from a scanmumble state to a mumble state. func restartg(gp *g) { + if gp.scang != 0 || gp.scangcw != 0 { + print("g ", gp.goid, "is being scanned scang=", gp.scang, " scangcw=", gp.scangcw, "\n") + throw("restartg: being scanned") + } + s := readgstatus(gp) switch s { default: |