Skip to content

Commit 7cb6017

Browse files
committed
chore: use atomics instead of artisinal assembly
1 parent 93f5e68 commit 7cb6017

File tree

1 file changed

+12
-47
lines changed

1 file changed

+12
-47
lines changed

src/runtime/runtime_rp2350.go

Lines changed: 12 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
package runtime
44

55
import (
6-
"device/arm"
76
"device/rp"
7+
"sync/atomic"
88
)
99

1010
const (
@@ -18,57 +18,22 @@ const (
1818

1919
// Due to hardware errata RP2350-E2 spinlocks are emulated in software as in pico-sdk.
2020
type spinLock struct {
21-
// state field must be first field so its address is the same as the struct address.
22-
state uint8
23-
id uint8
24-
uint16 // Padding to prevent false sharing
21+
atomic.Uint32
2522
}
2623

2724
func (l *spinLock) Lock() {
28-
// Original reference:
29-
// https://github.com/raspberrypi/pico-sdk/blob/2.2.0/src/rp2_common/hardware_sync_spin_lock/include/hardware/sync/spin_lock.h#L112
30-
31-
// r0 is automatically filled with the pointer value "l" here.
32-
// We create a variable to permit access to the state byte (l.state) and
33-
// avoid a memory fault when accessing it in assembly.
34-
state := &l.state
35-
_ = state
36-
37-
// Set the loop start point.
38-
arm.Asm("1:")
39-
// Exclusively load (lock) the state byte and put its value in r2.
40-
arm.Asm("ldaexb r2, [r0]")
41-
// Set the r1 register to '1' for later use.
42-
arm.Asm("movs r1, #1")
43-
// Check if the lock was already taken (r2 != 0).
44-
arm.Asm("cmp r2, #0")
45-
// Jump back to the loop start ("1:") if the lock is already held.
46-
arm.Asm("bne 1b")
47-
48-
// Attempt to store '1' into the lock state byte.
49-
// The return code (0 for success, 1 for failure) is placed in r2.
50-
arm.Asm("strexb r2, r1, [r0]")
51-
// Check if the result was successful (r2 == 0).
52-
arm.Asm("cmp r2, #0")
53-
// Jump back to the loop start ("1:") if the lock was not acquired.
54-
arm.Asm("bne 1b")
55-
56-
// Memory barrier to ensure everyone knows we're holding the lock now.
57-
arm.Asm("dmb")
25+
// Try to replace 0 with 1. Once we succeed, the lock has been acquired.
26+
for !l.Uint32.CompareAndSwap(0, 1) {
27+
spinLoopWait()
28+
}
5829
}
5930

6031
func (l *spinLock) Unlock() {
61-
// Original reference:
62-
// https://github.com/raspberrypi/pico-sdk/blob/2.2.0/src/rp2_common/hardware_sync_spin_lock/include/hardware/sync/spin_lock.h#L197
32+
// Safety check: the spinlock should have been locked.
33+
if schedulerAsserts && l.Uint32.Load() != 1 {
34+
runtimePanic("unlock of unlocked spinlock")
35+
}
6336

64-
// r0 is automatically filled with the pointer value l here.
65-
// We create a variable to permit access to the state byte (l.state) and
66-
// avoid a memory fault when accessing it in assembly.
67-
state := &l.state
68-
_ = state
69-
// Fill r1 with 0 and store it to the state byte address in r0. stlb
70-
// requires a register as a source so we can't use a literal 0 directly.
71-
arm.Asm("movs r1, #0")
72-
// Release the pseudo-spinlock by writing 0 to and releasing l.state.
73-
arm.Asm("stlb r1, [r0]")
37+
// Unlock the lock. Simply write 0, because we already know it is locked.
38+
l.Uint32.Store(0)
7439
}

0 commit comments

Comments
 (0)