mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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>
This commit is contained in:
parent
20bba866d3
commit
758eb020f7
5 changed files with 122 additions and 0 deletions
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue