aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/signal_unix.go
diff options
context:
space:
mode:
authorCherry Zhang <cherryyz@google.com>2019-10-23 11:42:23 -0400
committerCherry Zhang <cherryyz@google.com>2019-10-23 22:59:54 +0000
commit758eb020f72a70e3e42814492daac8719a3be538 (patch)
tree1bbbdad699accc81f2a36c719f2bfc439a85b042 /src/runtime/signal_unix.go
parent20bba866d3aaeba728c78ff24c940b98441c791b (diff)
downloadgo-758eb020f72a70e3e42814492daac8719a3be538.tar.gz
go-758eb020f72a70e3e42814492daac8719a3be538.zip
runtime: save/fetch g register during VDSO on ARM and ARM64
On ARM and ARM64, during a VDSO call, the g register may be temporarily clobbered by the VDSO code. If a signal is received during the execution of VDSO code, we may not find a valid g reading the g register. In CL 192937, we conservatively assume g is nil. But this approach has a problem: we cannot handle the signal in this case. Further, if the signal is not a profiling signal, we'll call badsignal, which calls needm, which wants to get an extra m, but we don't have one in a non-cgo binary, which cuases the program to hang. This is even more of a problem with async preemption, where we will receive more signals than before. I ran into this problem while working on async preemption support on ARM64. In this CL, before making a VDSO call, we save the g on the gsignal stack. When we receive a signal, we will be running on the gsignal stack, so we can fetch the g from there and move on. We probably want to do the same for PPC64. Currently we rely on that the VDSO code doesn't actually clobber the g register, but this is not guaranteed and we don't have control with. Idea from discussion with Dan Cross and Austin. Should fix #34391. Change-Id: Idbefc5e4c2f4373192c2be797be0140ae08b26e3 Reviewed-on: https://go-review.googlesource.com/c/go/+/202759 Run-TryBot: Cherry Zhang <cherryyz@google.com> Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/runtime/signal_unix.go')
-rw-r--r--src/runtime/signal_unix.go10
1 files changed, 10 insertions, 0 deletions
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index d5a04b6d48..cea65282e0 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -299,6 +299,16 @@ func sigFetchG(c *sigctxt) *g {
switch GOARCH {
case "arm", "arm64":
if inVDSOPage(c.sigpc()) {
+ // Before making a VDSO call we save the g to the bottom of the
+ // signal stack. Fetch from there.
+ // TODO: in efence mode, stack is sysAlloc'd, so this wouldn't
+ // work.
+ sp := getcallersp()
+ s := spanOf(sp)
+ if s != nil && s.state == mSpanManual && s.base() < sp && sp < s.limit {
+ gp := *(**g)(unsafe.Pointer(s.base()))
+ return gp
+ }
return nil
}
}