@@ -17,9 +17,270 @@ extern crate std;
17
17
#[ cfg( feature = "std" ) ]
18
18
use std:: ffi:: CStr ;
19
19
20
+ use core:: cell:: UnsafeCell ;
20
21
use core:: ffi:: { c_char, c_int, c_void} ;
21
22
use core:: ptr:: NonNull ;
22
23
use core:: slice;
24
+ use core:: sync:: atomic:: { AtomicBool , Ordering } ;
25
+
26
+ /// A generic spin mutex that uses CPU-specific pause instructions for efficient busy-waiting.
27
+ ///
28
+ /// This is a low-level synchronization primitive that spins on a busy loop rather than
29
+ /// blocking the thread. It's most appropriate for very short critical sections where
30
+ /// the cost of context switching would be higher than busy-waiting.
31
+ ///
32
+ /// The generic parameter `P` allows customization of the pause behavior:
33
+ /// - `true` enables CPU-specific pause instructions (recommended for most use cases)
34
+ /// - `false` disables pause instructions (may be useful in some specialized scenarios)
35
+ ///
36
+ /// # Examples
37
+ ///
38
+ /// ```rust
39
+ /// use fork_union::*;
40
+ ///
41
+ /// // Create a spin mutex with pause instructions enabled
42
+ /// let mutex = BasicSpinMutex::<i32, true>::new(42);
43
+ ///
44
+ /// // Lock, access data, and unlock
45
+ /// {
46
+ /// let mut guard = mutex.lock();
47
+ /// *guard = 100;
48
+ /// } // Lock is automatically released when guard goes out of scope
49
+ ///
50
+ /// // Verify the value was changed
51
+ /// assert_eq!(*mutex.lock(), 100);
52
+ /// ```
53
+ ///
54
+ /// # Performance Characteristics
55
+ ///
56
+ /// - **Very fast for short critical sections** - no syscalls or context switches
57
+ /// - **CPU-efficient busy-waiting** - uses pause instructions when `P = true`
58
+ /// - **Memory efficient** - only requires a single atomic bool plus the protected data
59
+ /// - **Can cause high CPU usage** - spins continuously until lock is acquired
60
+ /// - **Not fair** - no guarantee of acquisition order
61
+ ///
62
+ /// # When to Use
63
+ ///
64
+ /// Use `BasicSpinMutex` when:
65
+ /// - Critical sections are very short (microseconds)
66
+ /// - Lock contention is low
67
+ /// - You need the absolute minimum latency
68
+ /// - You're in a no_std environment
69
+ ///
70
+ /// Avoid `BasicSpinMutex` when:
71
+ /// - Critical sections are long (milliseconds or more)
72
+ /// - Lock contention is high
73
+ /// - You need fairness guarantees
74
+ /// - Power consumption is a concern
75
+ pub struct BasicSpinMutex < T , const PAUSE : bool > {
76
+ locked : AtomicBool ,
77
+ data : UnsafeCell < T > ,
78
+ }
79
+
80
+ impl < T , const PAUSE : bool > BasicSpinMutex < T , PAUSE > {
81
+ /// Creates a new spin mutex in the unlocked state.
82
+ ///
83
+ /// # Arguments
84
+ ///
85
+ /// * `data` - The value to be protected by the mutex
86
+ ///
87
+ /// # Examples
88
+ ///
89
+ /// ```rust
90
+ /// use fork_union::*;
91
+ ///
92
+ /// let mutex = BasicSpinMutex::<i32, true>::new(0);
93
+ /// ```
94
+ pub const fn new ( data : T ) -> Self {
95
+ Self {
96
+ locked : AtomicBool :: new ( false ) ,
97
+ data : UnsafeCell :: new ( data) ,
98
+ }
99
+ }
100
+
101
+ /// Acquires the lock, returning a guard that provides access to the protected data.
102
+ ///
103
+ /// This method will spin until the lock is acquired. If the lock is already held,
104
+ /// it will busy-wait using CPU-specific pause instructions (if `PAUSE = true`).
105
+ ///
106
+ /// # Examples
107
+ ///
108
+ /// ```rust
109
+ /// use fork_union::*;
110
+ ///
111
+ /// let mutex = BasicSpinMutex::<i32, true>::new(0);
112
+ /// let mut guard = mutex.lock();
113
+ /// *guard = 42;
114
+ /// ```
115
+ pub fn lock ( & self ) -> BasicSpinMutexGuard < T , PAUSE > {
116
+ while self
117
+ . locked
118
+ . compare_exchange_weak ( false , true , Ordering :: Acquire , Ordering :: Relaxed )
119
+ . is_err ( )
120
+ {
121
+ // Busy-wait with pause instructions if enabled
122
+ if PAUSE {
123
+ core:: hint:: spin_loop ( ) ;
124
+ }
125
+ }
126
+ BasicSpinMutexGuard { mutex : self }
127
+ }
128
+
129
+ /// Attempts to acquire the lock without blocking.
130
+ ///
131
+ /// Returns `Some(guard)` if the lock was successfully acquired, or `None` if
132
+ /// the lock is currently held by another thread.
133
+ ///
134
+ /// # Examples
135
+ ///
136
+ /// ```rust
137
+ /// use fork_union::*;
138
+ ///
139
+ /// let mutex = BasicSpinMutex::<i32, true>::new(0);
140
+ ///
141
+ /// if let Some(mut guard) = mutex.try_lock() {
142
+ /// *guard = 42;
143
+ /// println!("Lock acquired and value set");
144
+ /// } else {
145
+ /// println!("Lock is currently held by another thread");
146
+ /// };
147
+ /// ```
148
+ pub fn try_lock ( & self ) -> Option < BasicSpinMutexGuard < T , PAUSE > > {
149
+ if self
150
+ . locked
151
+ . compare_exchange ( false , true , Ordering :: Acquire , Ordering :: Relaxed )
152
+ . is_ok ( )
153
+ {
154
+ Some ( BasicSpinMutexGuard { mutex : self } )
155
+ } else {
156
+ None
157
+ }
158
+ }
159
+
160
+ /// Checks if the mutex is currently locked.
161
+ ///
162
+ /// This method provides a non-blocking way to check the lock state, but should
163
+ /// be used carefully as the state can change immediately after this call returns.
164
+ ///
165
+ /// # Examples
166
+ ///
167
+ /// ```rust
168
+ /// use fork_union::*;
169
+ ///
170
+ /// let mutex = BasicSpinMutex::<i32, true>::new(0);
171
+ /// assert!(!mutex.is_locked());
172
+ ///
173
+ /// {
174
+ /// let _guard = mutex.lock();
175
+ /// assert!(mutex.is_locked());
176
+ /// }
177
+ ///
178
+ /// assert!(!mutex.is_locked());
179
+ /// ```
180
+ pub fn is_locked ( & self ) -> bool {
181
+ self . locked . load ( Ordering :: Acquire )
182
+ }
183
+
184
+ /// Consumes the mutex and returns the protected data.
185
+ ///
186
+ /// This method bypasses the locking mechanism entirely since we have exclusive
187
+ /// ownership of the mutex.
188
+ ///
189
+ /// # Examples
190
+ ///
191
+ /// ```rust
192
+ /// use fork_union::*;
193
+ ///
194
+ /// let mutex = BasicSpinMutex::<i32, true>::new(42);
195
+ /// let data = mutex.into_inner();
196
+ /// assert_eq!(data, 42);
197
+ /// ```
198
+ pub fn into_inner ( self ) -> T {
199
+ self . data . into_inner ( )
200
+ }
201
+
202
+ /// Gets a mutable reference to the protected data.
203
+ ///
204
+ /// Since this requires a mutable reference to the mutex, no locking is needed
205
+ /// as we have exclusive access.
206
+ ///
207
+ /// # Examples
208
+ ///
209
+ /// ```rust
210
+ /// use fork_union::*;
211
+ ///
212
+ /// let mut mutex = BasicSpinMutex::<i32, true>::new(0);
213
+ /// *mutex.get_mut() = 42;
214
+ /// assert_eq!(*mutex.lock(), 42);
215
+ /// ```
216
+ pub fn get_mut ( & mut self ) -> & mut T {
217
+ self . data . get_mut ( )
218
+ }
219
+ }
220
+
221
+ // Safety: BasicSpinMutex can be sent between threads if T can be sent
222
+ unsafe impl < T : Send , const PAUSE : bool > Send for BasicSpinMutex < T , PAUSE > { }
223
+ // Safety: BasicSpinMutex can be shared between threads if T can be sent
224
+ unsafe impl < T : Send , const PAUSE : bool > Sync for BasicSpinMutex < T , PAUSE > { }
225
+
226
+ /// A guard providing access to the data protected by a `BasicSpinMutex`.
227
+ ///
228
+ /// The lock is automatically released when this guard is dropped.
229
+ pub struct BasicSpinMutexGuard < ' a , T , const PAUSE : bool > {
230
+ mutex : & ' a BasicSpinMutex < T , PAUSE > ,
231
+ }
232
+
233
+ impl < ' a , T , const PAUSE : bool > BasicSpinMutexGuard < ' a , T , PAUSE > {
234
+ /// Returns a reference to the protected data.
235
+ ///
236
+ /// This method is rarely needed since the guard implements `Deref`.
237
+ pub fn get ( & self ) -> & T {
238
+ unsafe { & * self . mutex . data . get ( ) }
239
+ }
240
+
241
+ /// Returns a mutable reference to the protected data.
242
+ ///
243
+ /// This method is rarely needed since the guard implements `DerefMut`.
244
+ pub fn get_mut ( & mut self ) -> & mut T {
245
+ unsafe { & mut * self . mutex . data . get ( ) }
246
+ }
247
+ }
248
+
249
+ impl < ' a , T , const PAUSE : bool > core:: ops:: Deref for BasicSpinMutexGuard < ' a , T , PAUSE > {
250
+ type Target = T ;
251
+
252
+ fn deref ( & self ) -> & Self :: Target {
253
+ unsafe { & * self . mutex . data . get ( ) }
254
+ }
255
+ }
256
+
257
+ impl < ' a , T , const PAUSE : bool > core:: ops:: DerefMut for BasicSpinMutexGuard < ' a , T , PAUSE > {
258
+ fn deref_mut ( & mut self ) -> & mut Self :: Target {
259
+ unsafe { & mut * self . mutex . data . get ( ) }
260
+ }
261
+ }
262
+
263
+ impl < ' a , T , const PAUSE : bool > Drop for BasicSpinMutexGuard < ' a , T , PAUSE > {
264
+ fn drop ( & mut self ) {
265
+ self . mutex . locked . store ( false , Ordering :: Release ) ;
266
+ }
267
+ }
268
+
269
+ /// A type alias for the most commonly used spin mutex configuration.
270
+ ///
271
+ /// This is equivalent to `BasicSpinMutex<T, true>`, which enables CPU-specific
272
+ /// pause instructions for efficient busy-waiting.
273
+ ///
274
+ /// # Examples
275
+ ///
276
+ /// ```rust
277
+ /// use fork_union::*;
278
+ ///
279
+ /// let mutex = SpinMutex::new(42);
280
+ /// let mut guard = mutex.lock();
281
+ /// *guard = 100;
282
+ /// ```
283
+ pub type SpinMutex < T > = BasicSpinMutex < T , true > ;
23
284
24
285
/// A "prong" - the tip of a "fork" - pinning a "task" to a "thread" and "memory" location.
25
286
///
0 commit comments