]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: make gcTestMoveStackOnNextCall not double the stack
authorAustin Clements <austin@google.com>
Thu, 1 Apr 2021 20:50:53 +0000 (16:50 -0400)
committerAustin Clements <austin@google.com>
Fri, 2 Apr 2021 01:14:00 +0000 (01:14 +0000)
Currently, gcTestMoveStackOnNextCall doubles the stack allocation on
each call because stack movement always doubles the stack. That's
rather unfortunate if you're doing a bunch of stack movement tests in
a row that don't actually have to grow the stack because you'll
quickly hit the stack size limit even though you're hardly using any
of the stack.

Fix this by adding a special stack poison value for
gcTestMoveStackOnNextCall that newstack recognizes and inhibits the
allocation doubling.

Change-Id: Iace7055a0f33cb48dc97b8f4b46e45304bee832c
Reviewed-on: https://go-review.googlesource.com/c/go/+/306672
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>

src/runtime/gc_test.go
src/runtime/mgc.go
src/runtime/stack.go

index 273f399864b90f9c1ff45384914a676ac8cdf69b..5e7c6c574fe1937777f3af9a3c508917088d9452 100644 (file)
@@ -242,6 +242,23 @@ func moveStackCheck(t *testing.T, new *int, old uintptr) bool {
        return true
 }
 
+func TestGCTestMoveStackRepeatedly(t *testing.T) {
+       // Move the stack repeatedly to make sure we're not doubling
+       // it each time.
+       for i := 0; i < 100; i++ {
+               runtime.GCTestMoveStackOnNextCall()
+               moveStack1(false)
+       }
+}
+
+//go:noinline
+func moveStack1(x bool) {
+       // Make sure this function doesn't get auto-nosplit.
+       if x {
+               println("x")
+       }
+}
+
 func TestGCTestIsReachable(t *testing.T) {
        var all, half []unsafe.Pointer
        var want uint64
index f0c03b5102855858e4ff3e39d17d6f7ffec0800c..4895fa5ef69d4a48a735e9f0af411a7c4d555cfd 100644 (file)
@@ -2352,7 +2352,7 @@ func fmtNSAsMS(buf []byte, ns uint64) []byte {
 // there's a preemption between this call and the next.
 func gcTestMoveStackOnNextCall() {
        gp := getg()
-       gp.stackguard0 = getcallersp()
+       gp.stackguard0 = stackForceMove
 }
 
 // gcTestIsReachable performs a GC and returns a bit set where bit i
index d971e5e26f8e544259606e8a73522c2bf0e4afa7..5c7fadc2d297c9318e6d022e9cc3e15d4ea8e412 100644 (file)
@@ -132,6 +132,10 @@ const (
        // Stored into g->stackguard0 to cause split stack check failure.
        // Must be greater than any real sp.
        stackFork = uintptrMask & -1234
+
+       // Force a stack movement. Used for debugging.
+       // 0xfffffeed in hex.
+       stackForceMove = uintptrMask & -275
 )
 
 // Global pool of spans that have free stacks.
@@ -1054,11 +1058,18 @@ func newstack() {
        // recheck the bounds on return.)
        if f := findfunc(gp.sched.pc); f.valid() {
                max := uintptr(funcMaxSPDelta(f))
-               for newsize-oldsize < max+_StackGuard {
+               for newsize-gp.sched.sp < max+_StackGuard {
                        newsize *= 2
                }
        }
 
+       if gp.stackguard0 == stackForceMove {
+               // Forced stack movement used for debugging.
+               // Don't double the stack (or we may quickly run out
+               // if this is done repeatedly).
+               newsize = oldsize
+       }
+
        if newsize > maxstacksize || newsize > maxstackceiling {
                if maxstacksize < maxstackceiling {
                        print("runtime: goroutine stack exceeds ", maxstacksize, "-byte limit\n")