]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: support non-cooperative preemption on windows/arm64
authorJason A. Donenfeld <Jason@zx2c4.com>
Tue, 23 Nov 2021 19:57:24 +0000 (20:57 +0100)
committerJason A. Donenfeld <Jason@zx2c4.com>
Thu, 25 Nov 2021 00:07:28 +0000 (00:07 +0000)
This adds support for injecting asynchronous preemption calls on
windows/arm64. This code exactly follows sigctxt.pushCall for POSIX OSes
on arm64.

Fixes #49759.

Change-Id: Id35ff6bc105c1db9d7ed2918d3ecab0e4e9a9431
Reviewed-on: https://go-review.googlesource.com/c/go/+/366735
Trust: Jason A. Donenfeld <Jason@zx2c4.com>
Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Patrik Nyblom <pnyb@google.com>
src/runtime/os_windows.go

index a85971c6a92fdba4f6a883f3c58d707978d891f3..15953ffa0c8e5f8a3348050f4c944a75b3b414b3 100644 (file)
@@ -1306,18 +1306,13 @@ func setThreadCPUProfiler(hz int32) {
        atomic.Store((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
 }
 
-const preemptMSupported = GOARCH != "arm64"
+const preemptMSupported = true
 
 // suspendLock protects simultaneous SuspendThread operations from
 // suspending each other.
 var suspendLock mutex
 
 func preemptM(mp *m) {
-       if !preemptMSupported {
-               // TODO: Implement call injection
-               return
-       }
-
        if mp == getg().m {
                throw("self-preempt")
        }
@@ -1412,6 +1407,17 @@ func preemptM(mp *m) {
                                *(*uint32)(unsafe.Pointer(sp)) = uint32(c.lr())
                                c.set_lr(newpc - 1)
                                c.set_ip(targetPC)
+
+                       case "arm64":
+                               // Push LR. The injected call is responsible
+                               // for restoring LR. gentraceback is aware of
+                               // this extra slot. See sigctxt.pushCall in
+                               // signal_arm64.go.
+                               sp := c.sp() - 16 // SP needs 16-byte alignment
+                               c.set_sp(sp)
+                               *(*uint64)(unsafe.Pointer(sp)) = uint64(c.lr())
+                               c.set_lr(newpc)
+                               c.set_ip(targetPC)
                        }
                        stdcall2(_SetThreadContext, thread, uintptr(unsafe.Pointer(c)))
                }