aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/go-patches/0006-runtime-support-non-cooperative-preemption-on-window.patch
blob: c99ea390badda67296e21bc8329be3614cc6ebd4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
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 <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 | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index faeb6ce552..7bf9a426d1 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -1303,18 +1303,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")
 	}
@@ -1409,6 +1404,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)))
 		}