ndata/
sharedmutex.rs

1//! A shareable reader-writer spinlock mutex implementation.
2//! Original spinlock logic credit: Mikhail Panfilov
3//! Reader-writer lock logic adapted for this structure.
4
5use core::cell::UnsafeCell;
6use core::hint::spin_loop;
7use core::ops::{Deref, DerefMut};
8use core::ptr;
9use core::sync::atomic::{AtomicUsize, AtomicPtr, Ordering};
10
11// Define constants for pointer types for clarity
12type LockPtr = *const AtomicUsize;
13type DataPtr<T> = *const UnsafeCell<T>;
14
15// Constants for lock states
16const UNLOCKED: usize = 0;
17const WRITE_LOCKED: usize = usize::MAX; // Sentinel for write lock. Max readers = WRITE_LOCKED - 1
18
19/// Represents the state of the SharedMutex: uninitialized, managing local data, or mirroring another mutex.
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21enum MutexState {
22    /// The mutex has not been initialized with data or mirrored yet.
23    Uninitialized,
24    /// The mutex manages its own lock and data locally.
25    Local,
26    /// The mutex mirrors the state and data of another SharedMutex via raw pointers.
27    Mirrored,
28}
29
30/// A reader-writer spinlock mutex that can potentially be shared across memory partitions.
31///
32/// This mutex uses atomic operations for locking and `UnsafeCell` for interior mutability.
33/// It allows multiple concurrent readers OR one exclusive writer.
34///
35/// # Safety
36/// This mutex relies on raw pointers for its "mirroring" functionality (`share` and `mirror` methods).
37/// This is **inherently unsafe** and imposes strict requirements on the user:
38///
39/// 1.  **Non-Movement:** The `SharedMutex` instance that calls `set` (the "original" instance)
40///     **must not be moved** in memory after `set` is called and while any mirrored instances exist.
41///     Moving the original instance will invalidate the pointers shared via `share`, leading to
42///     dangling pointers and **undefined behavior** in mirrored instances. Placing the original
43///     `SharedMutex` in a `static` variable (often managed by `GlobalSharedMutex`) is the safest way
44///     to ensure this non-movement requirement.
45/// 2.  **Pointer Validity:** The pointers shared via `share` and used by `mirror` must remain valid
46///     for the entire lifetime of the mirrored mutexes. The memory they point to (part of the
47///     original `SharedMutex`) must not be deallocated or become invalid (e.g., by dropping
48///     the original mutex prematurely).
49/// 3.  **Memory Accessibility:** The caller is responsible for ensuring that the memory partitions
50///     or contexts where mirrored mutexes operate can safely and correctly access the memory
51///     locations specified by the shared pointers. This often depends on the system architecture
52///     and memory model.
53/// 4.  **Initialization Synchronization:** Calls to `set` or `mirror` on the *same* `SharedMutex`
54///     instance must be properly synchronized if they can happen concurrently with other
55///     operations (like `lock`, `read`, or `share`). This mutex does not provide internal synchronization
56///     for its own initialization.
57///
58/// **Failure to meet these conditions will result in undefined behavior.** Use the `share`
59/// and `mirror` features with extreme caution and only when the safety requirements can be
60/// strictly guaranteed. For standard concurrent programming within a single process, prefer
61/// `std::sync::RwLock` or other safer abstractions from the standard library.
62#[derive(Debug)]
63pub struct SharedMutex<T> {
64    /// Pointer to the atomic lock state (`AtomicUsize`).
65    lock_ptr: LockPtr,
66    /// Pointer to the `UnsafeCell` containing the data `T`.
67    data_ptr: DataPtr<T>,
68    /// Tracks whether the mutex is local, mirrored, or uninitialized.
69    state: MutexState,
70    /// The storage for the lock state when the mutex is `Local`.
71    local_lock_storage: AtomicUsize,
72    /// The storage for the data (`T`) wrapped in `UnsafeCell` when the mutex is `Local`.
73    local_data_storage: Option<UnsafeCell<T>>,
74}
75
76// Default implementation creates an uninitialized mutex.
77impl<T> Default for SharedMutex<T> {
78    fn default() -> Self {
79        Self::new()
80    }
81}
82
83impl<T> SharedMutex<T> {
84    /// Creates a new, uninitialized `SharedMutex`.
85    #[inline]
86    pub const fn new() -> SharedMutex<T> {
87        SharedMutex {
88            lock_ptr: ptr::null(),
89            data_ptr: ptr::null(),
90            state: MutexState::Uninitialized,
91            local_lock_storage: AtomicUsize::new(UNLOCKED),
92            local_data_storage: None,
93        }
94    }
95
96    /// Initializes the mutex with the given data `t`, making it a "local" mutex.
97    pub fn set(&mut self, t: T) {
98        if self.state != MutexState::Uninitialized {
99            panic!("SharedMutex may only be initialized once (using set or mirror)");
100        }
101        self.local_data_storage = Some(UnsafeCell::new(t));
102        self.local_lock_storage.store(UNLOCKED, Ordering::Relaxed);
103        self.lock_ptr = &self.local_lock_storage as *const AtomicUsize;
104        self.data_ptr = self.local_data_storage.as_ref().unwrap() as *const UnsafeCell<T>;
105        self.state = MutexState::Local;
106    }
107
108    /// Returns the raw memory addresses of the lock state and the data cell.
109    pub fn share(&self) -> (u64, u64) {
110        if self.state != MutexState::Local {
111            panic!("Only a locally set SharedMutex can be shared (must be initialized with `set`)");
112        }
113        debug_assert!(!self.lock_ptr.is_null(), "Internal error: null lock_ptr in Local state for share()");
114        debug_assert!(!self.data_ptr.is_null(), "Internal error: null data_ptr in Local state for share()");
115        (self.lock_ptr as u64, self.data_ptr as u64)
116    }
117
118    /// Initializes this mutex to mirror another `SharedMutex` using raw memory addresses.
119    pub unsafe fn mirror(&mut self, lock_addr: u64, data_addr: u64) {
120        if self.state != MutexState::Uninitialized {
121            panic!("SharedMutex may only be initialized once (using set or mirror)");
122        }
123        if lock_addr == 0 || data_addr == 0 {
124            panic!("Cannot mirror using null addresses (lock_addr={}, data_addr={})", lock_addr, data_addr);
125        }
126        self.lock_ptr = lock_addr as LockPtr;
127        self.data_ptr = data_addr as DataPtr<T>;
128        self.state = MutexState::Mirrored;
129        self.local_data_storage = None;
130    }
131
132    /// Acquires an exclusive write lock, spinning until it becomes available.
133    #[inline]
134    pub fn lock(&self) -> SharedMutexGuard<'_, T> {
135        if !self.is_initialized() {
136            panic!("Cannot lock an uninitialized SharedMutex (call `set` or `mirror` first)");
137        }
138        debug_assert!(!self.lock_ptr.is_null(), "Internal error: null lock_ptr in lock()");
139        debug_assert!(!self.data_ptr.is_null(), "Internal error: null data_ptr in lock()");
140        loop {
141            match unsafe { (*self.lock_ptr).compare_exchange_weak(
142                UNLOCKED,
143                WRITE_LOCKED,
144                Ordering::Acquire,
145                Ordering::Relaxed,
146            )} {
147                Ok(_) => return SharedMutexGuard { mutex: self },
148                Err(_) => spin_loop(),
149            }
150        }
151    }
152
153    /// Acquires a shared read lock, spinning until it becomes available.
154    #[inline]
155    pub fn read(&self) -> SharedMutexReadGuard<'_, T> {
156        if !self.is_initialized() {
157            panic!("Cannot read-lock an uninitialized SharedMutex (call `set` or `mirror` first)");
158        }
159        debug_assert!(!self.lock_ptr.is_null(), "Internal error: null lock_ptr in read()");
160        debug_assert!(!self.data_ptr.is_null(), "Internal error: null data_ptr in read()");
161        loop {
162            let current_state = unsafe { (*self.lock_ptr).load(Ordering::Relaxed) };
163            if current_state == WRITE_LOCKED {
164                spin_loop();
165                continue;
166            }
167            if current_state == WRITE_LOCKED - 1 {
168                // Max readers reached, extremely unlikely.
169                spin_loop();
170                continue;
171            }
172            match unsafe { (*self.lock_ptr).compare_exchange_weak(
173                current_state,
174                current_state + 1,
175                Ordering::Acquire,
176                Ordering::Relaxed,
177            )} {
178                Ok(_) => return SharedMutexReadGuard { mutex: self },
179                Err(_) => spin_loop(),
180            }
181        }
182    }
183
184    /// Releases the exclusive write lock.
185    #[inline]
186    fn release_write_lock(&self) {
187        debug_assert!(self.is_initialized(), "Attempted to release write lock on uninitialized mutex");
188        debug_assert!(!self.lock_ptr.is_null(), "Attempted to release write lock with a null lock_ptr");
189        unsafe { (*self.lock_ptr).store(UNLOCKED, Ordering::Release); }
190    }
191
192    /// Releases a shared read lock.
193    #[inline]
194    fn release_read_lock(&self) {
195        debug_assert!(self.is_initialized(), "Attempted to release read lock on uninitialized mutex");
196        debug_assert!(!self.lock_ptr.is_null(), "Attempted to release read lock with a null lock_ptr");
197        unsafe { (*self.lock_ptr).fetch_sub(1, Ordering::Release); }
198    }
199
200    /// Checks if the mutex is currently locked.
201    #[inline]
202    pub fn is_locked(&self) -> bool {
203        if !self.is_initialized() {
204            panic!("Cannot check lock status of an uninitialized SharedMutex");
205        }
206        debug_assert!(!self.lock_ptr.is_null(), "Internal error: null lock_ptr in is_locked()");
207        unsafe { (*self.lock_ptr).load(Ordering::Acquire) != UNLOCKED }
208    }
209
210    /// Checks if the mutex has been initialized.
211    #[inline]
212    pub fn is_initialized(&self) -> bool {
213        self.state != MutexState::Uninitialized
214    }
215}
216
217/// Guard for exclusive (write) access.
218#[derive(Debug)]
219#[must_use = "if unused the Mutex will immediately unlock"]
220pub struct SharedMutexGuard<'a, T> {
221    mutex: &'a SharedMutex<T>,
222}
223
224impl<T> Deref for SharedMutexGuard<'_, T> {
225    type Target = T;
226    #[inline]
227    fn deref(&self) -> &Self::Target {
228        unsafe {
229            debug_assert!(self.mutex.is_initialized(), "WriteGuard exists for uninitialized mutex");
230            debug_assert!(!self.mutex.data_ptr.is_null(), "WriteGuard exists with null data_ptr");
231            &*(*self.mutex.data_ptr).get()
232        }
233    }
234}
235
236impl<T> DerefMut for SharedMutexGuard<'_, T> {
237    #[inline]
238    fn deref_mut(&mut self) -> &mut Self::Target {
239        unsafe {
240            debug_assert!(self.mutex.is_initialized(), "WriteGuard exists for uninitialized mutex");
241            debug_assert!(!self.mutex.data_ptr.is_null(), "WriteGuard exists with null data_ptr");
242            &mut *(*self.mutex.data_ptr).get()
243        }
244    }
245}
246
247impl<T> Drop for SharedMutexGuard<'_, T> {
248    #[inline]
249    fn drop(&mut self) {
250        if self.mutex.is_initialized() {
251            self.mutex.release_write_lock();
252        }
253    }
254}
255
256/// Guard for shared (read) access.
257#[derive(Debug)]
258#[must_use = "if unused the Mutex will immediately unlock"]
259pub struct SharedMutexReadGuard<'a, T> {
260    mutex: &'a SharedMutex<T>,
261}
262
263impl<T> Deref for SharedMutexReadGuard<'_, T> {
264    type Target = T;
265    #[inline]
266    fn deref(&self) -> &Self::Target {
267        unsafe {
268            debug_assert!(self.mutex.is_initialized(), "ReadGuard exists for uninitialized mutex");
269            debug_assert!(!self.mutex.data_ptr.is_null(), "ReadGuard exists with null data_ptr");
270            &*(*self.mutex.data_ptr).get()
271        }
272    }
273}
274
275impl<T> Drop for SharedMutexReadGuard<'_, T> {
276    #[inline]
277    fn drop(&mut self) {
278        if self.mutex.is_initialized() {
279            self.mutex.release_read_lock();
280        }
281    }
282}
283
284// SAFETY: See previous detailed comments. The reasoning for Send/Sync remains the same.
285unsafe impl<T: Send> Send for SharedMutex<T> {}
286unsafe impl<T: Send> Sync for SharedMutex<T> {}
287unsafe impl<'a, T: Send> Send for SharedMutexGuard<'a, T> {}
288unsafe impl<'a, T: Send + Sync> Sync for SharedMutexGuard<'a, T> {}
289unsafe impl<'a, T: Send> Send for SharedMutexReadGuard<'a, T> {}
290unsafe impl<'a, T: Send + Sync> Sync for SharedMutexReadGuard<'a, T> {}
291
292// =============================================================================
293// GlobalSharedMutex Implementation (No OnceCell)
294// =============================================================================
295
296// Initialization states for GlobalSharedMutex
297const GLOBAL_UNINITIALIZED: usize = 0;
298const GLOBAL_INITIALIZING: usize = 1;
299const GLOBAL_INITIALIZED: usize = 2;
300
301/// A wrapper around `SharedMutex` for convenient global static initialization and access,
302/// implemented without external dependencies like `once_cell`.
303///
304/// This uses `AtomicUsize` for state tracking and `AtomicPtr` to hold the `SharedMutex`.
305/// The `SharedMutex` is heap-allocated via `Box` and its pointer is stored.
306/// For `static` instances, the memory for the `SharedMutex` is intentionally leaked,
307/// which is a common pattern for `static`s requiring heap allocation without `Drop`
308/// being called (as `static`s don't drop by default).
309///
310/// # Example
311/// ```
312/// # use std::thread;
313/// # // Assuming TestData is defined elsewhere or in scope for the example
314/// # #[derive(Debug, Default, Clone, PartialEq)] pub struct TestData { value: i32, text: String }
315/// # // Use the actual crate name if this were in a library, e.g., `my_mutex_crate::GlobalSharedMutex`
316/// # use self::shared_mutex_with_global::{GlobalSharedMutex, SharedMutexGuard, SharedMutexReadGuard};
317///
318/// static MY_GLOBAL_DATA: GlobalSharedMutex<TestData> = GlobalSharedMutex::new();
319///
320/// fn main() {
321///     MY_GLOBAL_DATA.init(TestData { value: 10, text: "hello".to_string() });
322///
323///     thread::spawn(|| {
324///         let mut guard = MY_GLOBAL_DATA.lock();
325///         guard.value += 1;
326///         guard.text.push_str(" world");
327///     }).join().unwrap();
328///
329///     let guard = MY_GLOBAL_DATA.read();
330///     assert_eq!(guard.value, 11);
331///     assert_eq!(guard.text, "hello world");
332/// }
333/// ```
334#[derive(Debug)]
335pub struct GlobalSharedMutex<T> {
336    state: AtomicUsize,
337    ptr: AtomicPtr<SharedMutex<T>>,
338}
339
340impl<T> GlobalSharedMutex<T> {
341    /// Creates a new, uninitialized `GlobalSharedMutex`.
342    /// This function is `const`, suitable for `static` variable initialization.
343    pub const fn new() -> Self {
344        Self {
345            state: AtomicUsize::new(GLOBAL_UNINITIALIZED),
346            ptr: AtomicPtr::new(ptr::null_mut()),
347        }
348    }
349
350    /// Initializes the global mutex with the given data.
351    /// This method ensures the `SharedMutex` is initialized exactly once.
352    ///
353    /// # Panics
354    /// Panics if `init` is called more than once on the same `GlobalSharedMutex` instance.
355    pub fn init(&self, data: T) {
356        // Attempt to transition from UNINITIALIZED to INITIALIZING
357        match self.state.compare_exchange(
358            GLOBAL_UNINITIALIZED,
359            GLOBAL_INITIALIZING,
360            Ordering::Acquire, // Acquire to synchronize with other potential initializers
361            Ordering::Relaxed, // Relaxed on failure, we'll check the actual state
362        ) {
363            Ok(_) => { // Successfully transitioned to INITIALIZING, this thread does the work
364                // 1. Create the SharedMutex on the heap first.
365                //    SharedMutex::new() initializes local_data_storage to None, and pointers to null.
366                let mut boxed_sm = Box::new(SharedMutex::<T>::new());
367
368                // 2. Call `set` on the heap-allocated SharedMutex.
369                //    `set` will correctly initialize `local_data_storage` within the Box,
370                //    and `lock_ptr`/`data_ptr` will point to locations *within the Box on the heap*.
371                boxed_sm.set(data); // `data` is moved into the Boxed SharedMutex
372
373                // 3. Store the raw pointer. Box::into_raw leaks the Box.
374                self.ptr.store(Box::into_raw(boxed_sm), Ordering::Release);
375
376                // Mark as INITIALIZED
377                self.state.store(GLOBAL_INITIALIZED, Ordering::Release); // Release to publish the ptr and state
378            }
379            Err(current_state) => {
380                if current_state == GLOBAL_INITIALIZING {
381                    while self.state.load(Ordering::Acquire) == GLOBAL_INITIALIZING {
382                        core::hint::spin_loop();
383                    }
384                    if self.state.load(Ordering::Relaxed) != GLOBAL_INITIALIZED {
385                        panic!("GlobalSharedMutex failed to initialize correctly after spinning.");
386                    }
387                } else if current_state == GLOBAL_INITIALIZED {
388                    panic!("GlobalSharedMutex::init called more than once or on an already initialized mutex.");
389                } else {
390                    panic!("GlobalSharedMutex in unexpected state during init: {}", current_state);
391                }
392            }
393        }
394    }
395
396    /// Gets a reference to the underlying `SharedMutex`.
397    /// Spins if initialization is in progress.
398    /// # Panics
399    /// Panics if the `GlobalSharedMutex` has not been initialized.
400    #[inline]
401    fn get_mutex(&self) -> &SharedMutex<T> {
402        loop {
403            match self.state.load(Ordering::Acquire) {
404                GLOBAL_INITIALIZED => {
405                    let ptr = self.ptr.load(Ordering::Acquire);
406                    // SAFETY:
407                    // 1. ptr is non-null if state is INITIALIZED because init() stores it.
408                    // 2. ptr was obtained from Box::into_raw and points to a valid SharedMutex<T>.
409                    // 3. The SharedMutex<T> lives as long as the GlobalSharedMutex (leaked for statics).
410                    // 4. Access is read-only (&SharedMutex<T>), and SharedMutex itself handles internal sync.
411                    // 5. Acquire ordering ensures we see the initialized ptr.
412                    debug_assert!(!ptr.is_null(), "GlobalSharedMutex ptr is null despite being initialized");
413                    return unsafe { &*ptr };
414                }
415                GLOBAL_INITIALIZING => {
416                    spin_loop(); // Wait for initialization to complete
417                }
418                GLOBAL_UNINITIALIZED => {
419                    panic!("GlobalSharedMutex has not been initialized. Call init() first.");
420                }
421                _ => unreachable!("GlobalSharedMutex in invalid state"),
422            }
423        }
424    }
425
426    /// Acquires an exclusive write lock. See `SharedMutex::lock()`.
427    /// # Panics
428    /// Panics if `init()` has not been called.
429    pub fn lock(&self) -> SharedMutexGuard<'_, T> {
430        self.get_mutex().lock()
431    }
432
433    /// Acquires a shared read lock. See `SharedMutex::read()`.
434    /// # Panics
435    /// Panics if `init()` has not been called.
436    pub fn read(&self) -> SharedMutexReadGuard<'_, T> {
437        self.get_mutex().read()
438    }
439
440    /// Returns raw memory addresses for mirroring. See `SharedMutex::share()`.
441    /// # Panics
442    /// Panics if `init()` has not been called.
443    pub fn share(&self) -> (u64, u64) {
444        self.get_mutex().share()
445    }
446
447    /// Checks if the underlying mutex is locked. See `SharedMutex::is_locked()`.
448    /// # Panics
449    /// Panics if `init()` has not been called.
450    pub fn is_locked(&self) -> bool {
451        self.get_mutex().is_locked()
452    }
453}
454
455// SAFETY for GlobalSharedMutex<T>:
456// `GlobalSharedMutex<T>` uses `AtomicUsize` and `AtomicPtr`. These are Send/Sync.
457// The `SharedMutex<T>` pointed to is `Send + Sync` if `T: Send`.
458// The `init` method uses atomic operations to ensure safe one-time initialization and publication
459// of the `SharedMutex<T>` pointer.
460// The `get_mutex` method uses atomic loads with Acquire ordering to ensure visibility.
461// The raw pointer is obtained from `Box::into_raw`, and for static `GlobalSharedMutex` instances,
462// this memory is leaked, ensuring the pointer remains valid for the program's lifetime.
463// Therefore, `GlobalSharedMutex<T>` is `Send` and `Sync` if `T` is `Send`.
464unsafe impl<T: Send> Send for GlobalSharedMutex<T> {}
465unsafe impl<T: Send> Sync for GlobalSharedMutex<T> {}
466
467// Note: If GlobalSharedMutex instances were not 'static and could be dropped,
468// a Drop impl would be needed to call Box::from_raw to free the SharedMutex.
469// For 'static usage, leaking is the standard approach without external crates.
470
471#[cfg(test)]
472mod tests {
473    use super::*;
474    use std::sync::Arc;
475    use std::thread;
476    use std::time::Duration;
477
478    #[derive(Debug, Default, Clone, PartialEq)]
479    pub struct TestData {
480        pub value: i32,
481        pub text: String,
482    }
483
484    // ... (Original SharedMutex tests remain unchanged) ...
485    #[test]
486    fn basic_write_lock_unlock() {
487        let mut mutex = SharedMutex::new();
488        mutex.set(TestData { value: 10, text: "hello".to_string() });
489
490        {
491            let mut guard = mutex.lock(); // Write lock
492            assert_eq!(guard.value, 10);
493            guard.value = 20;
494            guard.text = "world".to_string();
495        } // Write lock released
496
497        {
498            let guard = mutex.lock(); // Re-acquire write lock
499            assert_eq!(guard.value, 20);
500            assert_eq!(guard.text, "world");
501        }
502    }
503
504    #[test]
505    fn basic_read_lock_unlock() {
506        let mut mutex = SharedMutex::new();
507        mutex.set(TestData { value: 30, text: "read test".to_string() });
508
509        {
510            let guard = mutex.read(); // Read lock
511            assert_eq!(guard.value, 30);
512            assert_eq!(guard.text, "read test");
513        } // Read lock released
514
515        // Multiple readers
516        let r1 = mutex.read();
517        let r2 = mutex.read();
518        assert_eq!(r1.value, 30);
519        assert_eq!(r2.value, 30);
520        drop(r1);
521        drop(r2);
522    }
523
524    #[test]
525    fn write_blocks_read() {
526        let mut m = SharedMutex::new();
527        m.set(TestData::default());
528        let mutex = Arc::new(m);
529
530        let writer_mutex_ref = Arc::clone(&mutex);
531        let _write_guard = writer_mutex_ref.lock();
532
533        let reader_mutex_ref = Arc::clone(&mutex);
534        let reader_thread = thread::spawn(move || {
535            let start_time = std::time::Instant::now();
536            let _read_guard = reader_mutex_ref.read();
537            assert!(start_time.elapsed() > Duration::from_millis(50), "Reader did not block for writer");
538        });
539
540        thread::sleep(Duration::from_millis(100));
541        drop(_write_guard);
542
543        reader_thread.join().unwrap();
544    }
545
546    #[test]
547    fn read_blocks_write() {
548        let mut m = SharedMutex::new();
549        m.set(TestData::default());
550        let mutex = Arc::new(m);
551
552        let reader_mutex_ref = Arc::clone(&mutex);
553        let _read_guard = reader_mutex_ref.read();
554
555        let writer_mutex_ref = Arc::clone(&mutex);
556        let writer_thread = thread::spawn(move || {
557            let start_time = std::time::Instant::now();
558            let mut _write_guard = writer_mutex_ref.lock();
559            _write_guard.value = 100;
560            assert!(start_time.elapsed() > Duration::from_millis(50), "Writer did not block for reader");
561        });
562
563        thread::sleep(Duration::from_millis(100));
564        drop(_read_guard);
565
566        writer_thread.join().unwrap();
567
568        let final_read = mutex.read();
569        assert_eq!(final_read.value, 100);
570    }
571
572    #[test]
573    fn multiple_readers_concurrently() {
574        let mut m = SharedMutex::new();
575        m.set(TestData { value: 123, text: "concurrent".to_string() });
576        let mutex = Arc::new(m);
577        let barrier = Arc::new(std::sync::Barrier::new(5));
578        let mut handles = vec![];
579
580        for _i in 0..5 {
581            let reader_mutex_ref = Arc::clone(&mutex);
582            let barrier_clone = Arc::clone(&barrier);
583            let handle = thread::spawn(move || {
584                barrier_clone.wait();
585                let guard = reader_mutex_ref.read();
586                assert_eq!(guard.value, 123);
587                assert_eq!(guard.text, "concurrent");
588                thread::sleep(Duration::from_millis(50));
589                drop(guard);
590            });
591            handles.push(handle);
592        }
593
594        for handle in handles {
595            handle.join().unwrap();
596        }
597    }
598
599    #[test]
600    fn is_locked_behavior() {
601        let mut mutex = SharedMutex::new();
602        mutex.set(TestData::default());
603
604        assert!(!mutex.is_locked(), "Should not be locked initially after set");
605
606        let r_guard = mutex.read();
607        assert!(mutex.is_locked(), "Should be locked after acquiring read lock");
608        drop(r_guard);
609        assert!(!mutex.is_locked(), "Should not be locked after read lock released");
610
611        let w_guard = mutex.lock();
612        assert!(mutex.is_locked(), "Should be locked after acquiring write lock");
613        drop(w_guard);
614        assert!(!mutex.is_locked(), "Should not be locked after write lock released");
615    }
616
617    #[test]
618    fn shared_mutex_can_be_static_like() {
619        let mut local_static_sim_owner = Box::new(SharedMutex::<i32>::new());
620        local_static_sim_owner.set(100);
621
622        let local_static_sim: &SharedMutex<i32> = &*local_static_sim_owner;
623
624        let _r = local_static_sim.read();
625        assert_eq!(*_r, 100);
626        drop(_r);
627
628        let mut _w = local_static_sim_owner.lock();
629        *_w = 200;
630        drop(_w);
631
632        let _r2 = local_static_sim.read();
633        assert_eq!(*_r2, 200);
634    }
635
636    #[test]
637    fn mirror_test() {
638        let mut original_mutex_owner = Box::new(SharedMutex::<TestData>::new());
639        original_mutex_owner.set(TestData { value: 1000, text: "original".to_string() });
640
641        let (lock_addr, data_addr) = original_mutex_owner.share();
642
643        let mut mirrored_mutex = SharedMutex::<TestData>::new();
644        unsafe {
645            mirrored_mutex.mirror(lock_addr, data_addr);
646        }
647
648        {
649            let guard = mirrored_mutex.read();
650            assert_eq!(guard.value, 1000);
651            assert_eq!(guard.text, "original");
652        }
653        {
654            let mut guard = original_mutex_owner.lock();
655            guard.value = 2000;
656            guard.text = "modified by original".to_string();
657        }
658        {
659            let guard = mirrored_mutex.read();
660            assert_eq!(guard.value, 2000);
661            assert_eq!(guard.text, "modified by original");
662        }
663        {
664            let mut guard = mirrored_mutex.lock();
665            guard.value = 3000;
666            guard.text = "modified by mirror".to_string();
667        }
668        {
669            let guard = original_mutex_owner.read();
670            assert_eq!(guard.value, 3000);
671            assert_eq!(guard.text, "modified by mirror");
672        }
673    }
674
675    #[test]
676    #[should_panic(expected = "SharedMutex may only be initialized once")]
677    fn set_twice_panics() {
678        let mut m = SharedMutex::<i32>::new();
679        m.set(10);
680        m.set(20);
681    }
682
683    #[test]
684    #[should_panic(expected = "SharedMutex may only be initialized once")]
685    unsafe fn mirror_after_set_panics() {
686        let mut m1 = SharedMutex::<i32>::new();
687        m1.set(10);
688        let (l,d) = m1.share();
689
690        let mut m2 = SharedMutex::<i32>::new();
691        m2.set(20);
692        m2.mirror(l,d);
693    }
694
695    #[test]
696    #[should_panic(expected = "Cannot lock an uninitialized SharedMutex")]
697    fn lock_uninitialized_panics() {
698        let m = SharedMutex::<i32>::new();
699        let _g = m.lock();
700    }
701
702    #[test]
703    #[should_panic(expected = "Cannot read-lock an uninitialized SharedMutex")]
704    fn read_uninitialized_panics() {
705        let m = SharedMutex::<i32>::new();
706        let _g = m.read();
707    }
708
709    #[test]
710    #[should_panic(expected = "Only a locally set SharedMutex can be shared")]
711    fn share_uninitialized_panics() {
712        let m = SharedMutex::<i32>::new();
713        m.share();
714    }
715
716    #[test]
717    #[should_panic(expected = "Only a locally set SharedMutex can be shared")]
718    unsafe fn share_mirrored_panics() {
719        let mut original = Box::new(SharedMutex::<i32>::new());
720        original.set(1);
721        let (l,d) = original.share();
722
723        let mut mirrored = SharedMutex::<i32>::new();
724        mirrored.mirror(l,d);
725        mirrored.share();
726    }
727}
728
729#[cfg(test)]
730mod global_tests {
731    // Bring items from the parent module (which includes GlobalSharedMutex, TestData via super::tests::*)
732    use super::*;
733    use std::sync::Arc;
734    use std::thread;
735    // Duration is already in scope via super::* from std::time::Duration in tests module.
736
737    // This static is specific to this test.
738    // If tests run in parallel, each test needing a unique static should define its own.
739    static GLOBAL_INT_MUTEX_FOR_BASIC_TEST: GlobalSharedMutex<i32> = GlobalSharedMutex::new();
740
741    #[test]
742    fn g_basic_init_lock_read() {
743        // For test isolation, it's often better to create a new GlobalSharedMutex instance
744        // rather than relying on a single static that might be mutated by other tests
745        // if tests were to run in parallel and share statics without care.
746        // However, this test demonstrates usage with a declared static.
747        // The `init` method itself is designed to be called once.
748        // If this test is run multiple times in the same process without restarting,
749        // the second run would panic at `init` if it's the same static instance.
750        // Cargo runs tests in a way that this is usually fine for separate test functions.
751        let test_static_mutex: GlobalSharedMutex<i32> = GlobalSharedMutex::new();
752        test_static_mutex.init(100); // Initialize this specific instance
753
754        {
755            let mut guard = test_static_mutex.lock();
756            assert_eq!(*guard, 100);
757            *guard = 200;
758        }
759        {
760            let guard = test_static_mutex.read();
761            assert_eq!(*guard, 200);
762        }
763    }
764
765    #[test]
766    #[should_panic(expected = "GlobalSharedMutex::init called more than once")]
767    fn g_double_init_panics() {
768        // This test uses the globally defined static.
769        // It's important that this test runs in an environment where it can attempt the first init.
770        // If another test already initialized GLOBAL_INT_MUTEX_FOR_BASIC_TEST, this test's behavior might change.
771        // To make it robust, we use a local instance for this specific panic test.
772        let temp_global: GlobalSharedMutex<i32> = GlobalSharedMutex::new();
773        temp_global.init(1);
774        temp_global.init(2); // Should panic
775    }
776
777    #[test]
778    #[should_panic(expected = "GlobalSharedMutex has not been initialized")]
779    fn g_lock_before_init_panics() {
780        let temp_global: GlobalSharedMutex<i32> = GlobalSharedMutex::new();
781        let _guard = temp_global.lock(); // Should panic
782    }
783
784    #[test]
785    #[should_panic(expected = "GlobalSharedMutex has not been initialized")]
786    fn g_read_before_init_panics() {
787        let temp_global: GlobalSharedMutex<i32> = GlobalSharedMutex::new();
788        let _guard = temp_global.read(); // Should panic
789    }
790
791    #[test]
792    fn g_multithreaded_access() {
793        let local_global_mutex: Arc<GlobalSharedMutex<i32>> = Arc::new(GlobalSharedMutex::new());
794        local_global_mutex.init(0);
795
796        let mut handles = vec![];
797
798        for i in 0..10 {
799            let mutex_clone = Arc::clone(&local_global_mutex);
800            let handle = thread::spawn(move || {
801                for _ in 0..100 {
802                    let mut guard = mutex_clone.lock();
803                    *guard += 1;
804                    if i == 0 && *guard % 10 == 0 {
805                        drop(guard);
806                        let r_guard = mutex_clone.read();
807                        assert!(*r_guard > 0);
808                    }
809                }
810            });
811            handles.push(handle);
812        }
813
814        for handle in handles {
815            handle.join().unwrap();
816        }
817
818        let final_guard = local_global_mutex.lock();
819        assert_eq!(*final_guard, 10 * 100);
820    }
821
822    #[test]
823    fn g_share_and_mirror_works() {
824        let local_global_owner: GlobalSharedMutex<TestData> = GlobalSharedMutex::new();
825        local_global_owner.init(TestData { value: 42, text: "global_shared".to_string() });
826
827        let (lock_addr, data_addr) = local_global_owner.share();
828        assert_ne!(lock_addr, 0);
829        assert_ne!(data_addr, 0);
830
831        let mut mirrored_mutex = SharedMutex::<TestData>::new();
832        unsafe {
833             mirrored_mutex.mirror(lock_addr, data_addr);
834        }
835
836        {
837            let guard = mirrored_mutex.read();
838            assert_eq!(guard.value, 42);
839            assert_eq!(guard.text, "global_shared");
840        }
841        {
842            let mut guard = local_global_owner.lock();
843            guard.value = 123;
844            guard.text = "modified_via_global".to_string();
845        }
846        {
847            let guard = mirrored_mutex.read();
848            assert_eq!(guard.value, 123);
849            assert_eq!(guard.text, "modified_via_global");
850        }
851         {
852            let mut guard = mirrored_mutex.lock();
853            guard.value = 456;
854            guard.text = "modified_via_mirror".to_string();
855        }
856        {
857            let guard = local_global_owner.read();
858            assert_eq!(guard.value, 456);
859            assert_eq!(guard.text, "modified_via_mirror");
860        }
861    }
862
863    #[test]
864    fn g_is_locked_behavior() {
865        let m: GlobalSharedMutex<i32> = GlobalSharedMutex::new();
866        m.init(10);
867
868        assert!(!m.is_locked());
869        let r_guard = m.read();
870        assert!(m.is_locked());
871        drop(r_guard);
872        assert!(!m.is_locked());
873
874        let w_guard = m.lock();
875        assert!(m.is_locked());
876        drop(w_guard);
877        assert!(!m.is_locked());
878    }
879
880    // Test to ensure that if one thread starts initializing, other threads wait.
881    #[test]
882    fn g_init_concurrent_access_waits() {
883        let mutex: Arc<GlobalSharedMutex<i32>> = Arc::new(GlobalSharedMutex::new());
884        let barrier = Arc::new(std::sync::Barrier::new(2));
885
886        let mutex_clone1 = Arc::clone(&mutex);
887        let barrier_clone1 = Arc::clone(&barrier);
888        let thread1 = thread::spawn(move || {
889            barrier_clone1.wait();
890            mutex_clone1.init(123); // First thread initializes
891            assert_eq!(*mutex_clone1.read(), 123);
892        });
893
894        let mutex_clone2 = Arc::clone(&mutex);
895        let barrier_clone2 = Arc::clone(&barrier);
896        let thread2 = thread::spawn(move || {
897            barrier_clone2.wait();
898            // This thread should wait if init is in progress, then successfully get the value
899            // or panic if it tries to init again (which it shouldn't with this logic).
900            // The get_mutex() will spin if state is INITIALIZING.
901            let val = *mutex_clone2.read();
902            assert_eq!(val, 123); // Should see the value initialized by thread1
903        });
904
905        thread1.join().unwrap();
906        thread2.join().unwrap();
907    }
908}
909