3
3
package runtime
4
4
5
5
import (
6
- "device/arm"
7
6
"device/rp"
7
+ "sync/atomic"
8
8
)
9
9
10
10
const (
@@ -18,57 +18,22 @@ const (
18
18
19
19
// Due to hardware errata RP2350-E2 spinlocks are emulated in software as in pico-sdk.
20
20
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
25
22
}
26
23
27
24
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
+ }
58
29
}
59
30
60
31
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
+ }
63
36
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 )
74
39
}
0 commit comments