]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: wrap procyield assembly and check for 0
authorMichael Anthony Knyszek <mknyszek@google.com>
Fri, 17 Oct 2025 19:53:36 +0000 (19:53 +0000)
committerGopher Robot <gobot@golang.org>
Tue, 21 Oct 2025 03:28:51 +0000 (20:28 -0700)
procyield will currently loop infinitely if passed 0 on several
platforms. This change sidesteps this bug by renaming procyield to
procyieldAsm, and adding a wrapper named procyield that checks for
cycles == 0. The benefit of this structure is that procyield called
with a constant cycle count of 0 will be inlined and constant folded
away, the expected behavior of a procyield of 0 cycles.

A follow-up change will fix the assembly to not have this footgun
anymore.

Change-Id: I7068abfeb961bc0fa475e216836f7c0e46b38373
Reviewed-on: https://go-review.googlesource.com/c/go/+/712663
Reviewed-by: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Auto-Submit: Michael Knyszek <mknyszek@google.com>

12 files changed:
src/runtime/asm_386.s
src/runtime/asm_amd64.s
src/runtime/asm_arm.s
src/runtime/asm_arm64.s
src/runtime/asm_loong64.s
src/runtime/asm_mips64x.s
src/runtime/asm_mipsx.s
src/runtime/asm_ppc64x.s
src/runtime/asm_riscv64.s
src/runtime/asm_s390x.s
src/runtime/asm_wasm.s
src/runtime/stubs.go

index df32e90fda841613d29f8c3a218b1d86281ac7b1..a54ca110e537670a0a48fc1b5d8461e9e1d65285 100644 (file)
@@ -597,7 +597,7 @@ CALLFN(·call268435456, 268435456)
 CALLFN(·call536870912, 536870912)
 CALLFN(·call1073741824, 1073741824)
 
-TEXT runtime·procyield(SB),NOSPLIT,$0-0
+TEXT runtime·procyieldAsm(SB),NOSPLIT,$0-0
        MOVL    cycles+0(FP), AX
 again:
        PAUSE
index 525df96f0028f6452e632a59edc7a8dca57dc62a..dbf54487a7f5028be93341001939f3851c9b244d 100644 (file)
@@ -815,7 +815,7 @@ CALLFN(·call268435456, 268435456)
 CALLFN(·call536870912, 536870912)
 CALLFN(·call1073741824, 1073741824)
 
-TEXT runtime·procyield(SB),NOSPLIT,$0-0
+TEXT runtime·procyieldAsm(SB),NOSPLIT,$0-0
        MOVL    cycles+0(FP), AX
 again:
        PAUSE
index d371e80d8484aca25963b47aff1c0307e35f5d3f..9373846c74a742bb6cf7a9700a1d1163bd16508a 100644 (file)
@@ -839,7 +839,7 @@ TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-12
 TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-12
        JMP     runtime·memhash64Fallback(SB)
 
-TEXT runtime·procyield(SB),NOSPLIT|NOFRAME,$0
+TEXT runtime·procyieldAsm(SB),NOSPLIT|NOFRAME,$0
        MOVW    cycles+0(FP), R1
        MOVW    $0, R0
 yieldloop:
index a0e82ec830f74b58a0a82641884559b81103f0d7..94a5b9ee6c866554e41efefaeb46ef4c49393d4b 100644 (file)
@@ -1036,7 +1036,7 @@ aesloop:
        VMOV    V0.D[0], R0
        RET
 
-TEXT runtime·procyield(SB),NOSPLIT,$0-0
+TEXT runtime·procyieldAsm(SB),NOSPLIT,$0-0
        MOVWU   cycles+0(FP), R0
 again:
        YIELD
index 586bf89a5d37298d65280d6cb1a8da1c50c7f693..a6a5519afb6f7db0d1bbb5da66095fbd8d0dec75 100644 (file)
@@ -505,7 +505,7 @@ CALLFN(·call268435456, 268435456)
 CALLFN(·call536870912, 536870912)
 CALLFN(·call1073741824, 1073741824)
 
-TEXT runtime·procyield(SB),NOSPLIT,$0-0
+TEXT runtime·procyieldAsm(SB),NOSPLIT,$0-0
        RET
 
 // Save state of caller into g->sched.
index d4523b4a74c47c6bf7b220add5967db41ff128b9..532eca752ffc8a7cdd60d9fb9956ecfad64572f4 100644 (file)
@@ -408,7 +408,7 @@ CALLFN(·call268435456, 268435456)
 CALLFN(·call536870912, 536870912)
 CALLFN(·call1073741824, 1073741824)
 
-TEXT runtime·procyield(SB),NOSPLIT,$0-0
+TEXT runtime·procyieldAsm(SB),NOSPLIT,$0-0
        RET
 
 // Save state of caller into g->sched,
index ec352f582890722e3b86ca535e7e2aa1a317785a..2dc3f1c3ad729ac14e0161783f8fab274f245601 100644 (file)
@@ -406,7 +406,7 @@ CALLFN(·call268435456, 268435456)
 CALLFN(·call536870912, 536870912)
 CALLFN(·call1073741824, 1073741824)
 
-TEXT runtime·procyield(SB),NOSPLIT,$0-4
+TEXT runtime·procyieldAsm(SB),NOSPLIT,$0-4
        RET
 
 // Save state of caller into g->sched,
index 127010ef9713982731abcd527272b68d5f4637a9..e461764e55d21306bfee376d54c2a23c610ef1d4 100644 (file)
@@ -612,7 +612,7 @@ CALLFN(·call268435456, 268435456)
 CALLFN(·call536870912, 536870912)
 CALLFN(·call1073741824, 1073741824)
 
-TEXT runtime·procyield(SB),NOSPLIT|NOFRAME,$0-4
+TEXT runtime·procyieldAsm(SB),NOSPLIT|NOFRAME,$0-4
        MOVW    cycles+0(FP), R7
        // POWER does not have a pause/yield instruction equivalent.
        // Instead, we can lower the program priority by setting the
index efe6047419e8b32602267ca843ea6af6b1410d39..5bd16181ee2b8759772a0feb781203fdbe8afc1d 100644 (file)
@@ -367,8 +367,8 @@ TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0
        MOV     gobuf_pc(T0), T0
        JALR    ZERO, T0
 
-// func procyield(cycles uint32)
-TEXT runtime·procyield(SB),NOSPLIT,$0-0
+// func procyieldAsm(cycles uint32)
+TEXT runtime·procyieldAsm(SB),NOSPLIT,$0-0
        RET
 
 // Switch to m->g0's stack, call fn(g).
index 4cc1c0eb10488689d3769b4c9370a8e0657e5386..bb29845f5839c02e034b21eb6e767e43c9ace9f0 100644 (file)
@@ -506,7 +506,7 @@ CALLFN(·call1073741824, 1073741824)
 TEXT callfnMVC<>(SB),NOSPLIT|NOFRAME,$0-0
        MVC     $1, 0(R4), 0(R6)
 
-TEXT runtime·procyield(SB),NOSPLIT,$0-0
+TEXT runtime·procyieldAsm(SB),NOSPLIT,$0-0
        RET
 
 // Save state of caller into g->sched,
index 85aa52e0f793c328a0d4f5de677b3431d3f9b87b..c46cb4ae46413cd113a4e41313ee54c15137baeb 100644 (file)
@@ -200,7 +200,7 @@ TEXT runtime·asminit(SB), NOSPLIT, $0-0
 TEXT ·publicationBarrier(SB), NOSPLIT, $0-0
        RET
 
-TEXT runtime·procyield(SB), NOSPLIT, $0-0 // FIXME
+TEXT runtime·procyieldAsm(SB), NOSPLIT, $0-0 // FIXME
        RET
 
 TEXT runtime·breakpoint(SB), NOSPLIT, $0-0
index 20fc1c59ad933b3a30eabe2a1118ffb59a2fc9e8..1692283541372e856834c19771191ef26e1b9e30 100644 (file)
@@ -274,7 +274,23 @@ func reflectcall(stackArgsType *_type, fn, stackArgs unsafe.Pointer, stackArgsSi
 // See go.dev/issue/67401.
 //
 //go:linkname procyield
-func procyield(cycles uint32)
+//go:nosplit
+func procyield(cycles uint32) {
+       if cycles == 0 {
+               return
+       }
+       procyieldAsm(cycles)
+}
+
+// procyieldAsm is the assembly implementation of procyield.
+//
+// It may loop infinitely if called with cycles == 0. Prefer
+// procyield, which will compile down to nothing in such cases,
+// instead.
+//
+// FIXME: The implementation really should not loop infinitely if
+// the number of cycles is 0.
+func procyieldAsm(cycles uint32)
 
 type neverCallThisFunction struct{}