From f7e34e705c533cca0970f1c6d1eafc2666a6a947 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 23 Nov 2021 20:57:24 +0100 Subject: [PATCH] runtime: support non-cooperative preemption on windows/arm64 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 Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Cherry Mui Reviewed-by: Austin Clements Reviewed-by: Patrik Nyblom --- src/runtime/os_windows.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index a85971c6a9..15953ffa0c 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -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))) } -- 2.50.0