11module sync
22
3+ import time
4+
35@[noreturn]
46fn cpanic (res int ) {
57 panic (unsafe { tos_clone (& u8 (C.strerror (res))) })
@@ -15,3 +17,72 @@ fn should_be_zero(res int) {
1517 cpanic (res)
1618 }
1719}
20+
21+ // SpinLock is a mutual exclusion lock that busy-waits (spins) when locked.
22+ // When one thread holds the lock, any other thread attempting to acquire it
23+ // will loop repeatedly until the lock becomes available.
24+ pub struct SpinLock {
25+ mut :
26+ locked u8 // Lock state: 0 = unlocked, 1 = locked
27+ padding [63 ]u8 // Cache line padding (fills to 64 bytes total)
28+ }
29+
30+ // new_spin_lock creates and returns a new SpinLock instance initialized to unlocked state
31+ pub fn new_spin_lock () & SpinLock {
32+ mut the_lock := & SpinLock{
33+ locked: 0
34+ }
35+ // Ensure initialization visibility across threads
36+ C.atomic_thread_fence (C.memory_order_release)
37+ return the_lock
38+ }
39+
40+ // lock acquires the spin lock. If the lock is currently held by another thread,
41+ // this function will spin (busy-wait) until the lock becomes available.
42+ @[inline]
43+ pub fn (s &SpinLock) lock () {
44+ // Expected value starts as unlocked (0)
45+ mut expected := u8 (0 )
46+ mut spin_count := 0
47+ max_spins := 100
48+ base_delay := 100 // nanosecond
49+ max_delay := 10000 // nanoseconds (10μs)
50+
51+ // Busy-wait until lock is acquired
52+ for {
53+ // Attempt atomic compare-and-swap:
54+ // Succeeds if current value matches expected (0),
55+ // then swaps to locked (1)
56+ if C.atomic_compare_exchange_weak_byte (& s.locked, & expected, 1 ) {
57+ // Prevent critical section reordering
58+ C.atomic_thread_fence (C.memory_order_acquire)
59+ return
60+ }
61+
62+ spin_count++
63+ // Exponential backoff after max_spins
64+ if spin_count > max_spins {
65+ // Calculate delay with cap: 100ns to 10μs
66+ exponent := int_min (spin_count / max_spins, 10 )
67+ delay := int_min (base_delay * (1 << exponent), max_delay)
68+ time.sleep (delay * time.nanosecond)
69+ } else {
70+ // Reduce power/bus contention during spinning
71+ C.cpu_relax ()
72+ }
73+
74+ // Refresh lock state before next attempt
75+ expected = C.atomic_load_byte (& s.locked)
76+ }
77+ }
78+
79+ // unlock releases the spin lock, making it available to other threads.
80+ // IMPORTANT: Must only be called by the thread that currently holds the lock.
81+ @[inline]
82+ pub fn (s &SpinLock) unlock () {
83+ // Ensure critical section completes before release
84+ C.atomic_thread_fence (C.memory_order_release)
85+
86+ // Atomically reset to unlocked state
87+ C.atomic_store_byte (& s.locked, 0 )
88+ }
0 commit comments