runtime: if InjectDebugCall sees "not at safe point", keep trying

Fixes #35376

Change-Id: Ib95ad336425e73cc4d412dafed0ba5e0a8130bd2
Reviewed-on: https://go-review.googlesource.com/c/go/+/205718
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
diff --git a/src/runtime/debug_test.go b/src/runtime/debug_test.go
index f77a373..722e811 100644
--- a/src/runtime/debug_test.go
+++ b/src/runtime/debug_test.go
@@ -126,7 +126,7 @@
 		return x + 1
 	}
 	args.x = 42
-	if _, err := runtime.InjectDebugCall(g, fn, &args, debugCallTKill); err != nil {
+	if _, err := runtime.InjectDebugCall(g, fn, &args, debugCallTKill, false); err != nil {
 		t.Fatal(err)
 	}
 	if args.yRet != 43 {
@@ -155,7 +155,7 @@
 		args.in[i] = i
 		want[i] = i + 1
 	}
-	if _, err := runtime.InjectDebugCall(g, fn, &args, debugCallTKill); err != nil {
+	if _, err := runtime.InjectDebugCall(g, fn, &args, debugCallTKill, false); err != nil {
 		t.Fatal(err)
 	}
 	if want != args.out {
@@ -168,7 +168,7 @@
 	defer after()
 
 	// Inject a call that performs a GC.
-	if _, err := runtime.InjectDebugCall(g, runtime.GC, nil, debugCallTKill); err != nil {
+	if _, err := runtime.InjectDebugCall(g, runtime.GC, nil, debugCallTKill, false); err != nil {
 		t.Fatal(err)
 	}
 }
@@ -179,7 +179,7 @@
 
 	// Inject a call that grows the stack. debugCallWorker checks
 	// for stack pointer breakage.
-	if _, err := runtime.InjectDebugCall(g, func() { growStack(nil) }, nil, debugCallTKill); err != nil {
+	if _, err := runtime.InjectDebugCall(g, func() { growStack(nil) }, nil, debugCallTKill, false); err != nil {
 		t.Fatal(err)
 	}
 }
@@ -215,7 +215,7 @@
 		runtime.Gosched()
 	}
 
-	_, err := runtime.InjectDebugCall(g, func() {}, nil, debugCallTKill)
+	_, err := runtime.InjectDebugCall(g, func() {}, nil, debugCallTKill, true)
 	if msg := "call not at safe point"; err == nil || err.Error() != msg {
 		t.Fatalf("want %q, got %s", msg, err)
 	}
@@ -239,7 +239,7 @@
 	}()
 	g := <-ready
 
-	p, err := runtime.InjectDebugCall(g, func() { panic("test") }, nil, debugCallTKill)
+	p, err := runtime.InjectDebugCall(g, func() { panic("test") }, nil, debugCallTKill, false)
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/src/runtime/export_debug_test.go b/src/runtime/export_debug_test.go
index 7deddd5..7ae12f6 100644
--- a/src/runtime/export_debug_test.go
+++ b/src/runtime/export_debug_test.go
@@ -20,7 +20,7 @@
 //
 // On success, InjectDebugCall returns the panic value of fn or nil.
 // If fn did not panic, its results will be available in args.
-func InjectDebugCall(gp *g, fn, args interface{}, tkill func(tid int) error) (interface{}, error) {
+func InjectDebugCall(gp *g, fn, args interface{}, tkill func(tid int) error, returnOnUnsafePoint bool) (interface{}, error) {
 	if gp.lockedm == 0 {
 		return nil, plainError("goroutine not locked to thread")
 	}
@@ -64,6 +64,12 @@
 		notetsleepg(&h.done, -1)
 		if h.err != "" {
 			switch h.err {
+			case "call not at safe point":
+				if returnOnUnsafePoint {
+					// This is for TestDebugCallUnsafePoint.
+					return nil, h.err
+				}
+				fallthrough
 			case "retry _Grunnable", "executing on Go runtime stack":
 				// These are transient states. Try to get out of them.
 				if i < 100 {