abi/task/
rwlock.rs

1use core::{
2    mem::{align_of, size_of},
3    ptr::drop_in_place,
4};
5use synchronization::blocking_mutex::{Mutex, raw::CriticalSectionRawMutex};
6
7pub struct RawRwLock {
8    /// Mutex to protect the lock state.
9    ///
10    /// The lock state is represented as follows:
11    /// - 0: Unlocked
12    /// - 1: Write locked (no readers allowed)
13    /// - 2 or more: Read locked (number of readers)
14    mutex: Mutex<CriticalSectionRawMutex, usize>,
15}
16
17impl Default for RawRwLock {
18    fn default() -> Self {
19        Self::new()
20    }
21}
22
23impl RawRwLock {
24    const READING: usize = 2; // Represents the state when there are readers
25    const WRITING: usize = 1; // Represents the state when there is a writer
26    const UNLOCKED: usize = 0; // Represents the state when the rwlock is unlocked
27
28    pub fn new() -> Self {
29        Self {
30            mutex: Mutex::new(Self::UNLOCKED), // Initial state: unlocked
31        }
32    }
33
34    pub fn is_valid_pointer(pointer: *const RawRwLock) -> bool {
35        !pointer.is_null() && (pointer as usize).is_multiple_of(align_of::<Self>())
36    }
37
38    /// Transforms a pointer to a reference.
39    ///
40    /// # Safety
41    ///
42    /// This function is unsafe because it dereferences a raw pointer.
43    /// The caller must ensure the pointer is valid and points to properly initialized memory.
44    pub unsafe fn from_pointer<'a>(pointer: *const RawRwLock) -> Option<&'a Self> {
45        unsafe {
46            if !Self::is_valid_pointer(pointer) {
47                return None;
48            }
49            Some(&*pointer)
50        }
51    }
52
53    /// Transforms a mutable pointer to a mutable reference.
54    ///
55    /// # Safety
56    ///
57    /// This function is unsafe because it dereferences a raw pointer.
58    /// The caller must ensure the pointer is valid and points to properly initialized memory.
59    pub unsafe fn from_mutable_pointer<'a>(pointer: *mut RawRwLock) -> Option<&'a mut Self> {
60        unsafe {
61            if !Self::is_valid_pointer(pointer) {
62                return None;
63            }
64            Some(&mut *pointer)
65        }
66    }
67
68    pub fn read(&self) -> bool {
69        unsafe {
70            self.mutex.lock_mut(|state| {
71                // Can't read if there's a writer (state == 1)
72
73                match *state {
74                    Self::WRITING => return false, // Write lock prevents reading
75                    Self::UNLOCKED => *state = Self::READING, // Unlocked, can read
76                    _ => *state += 1,              // Already has readers, can add more
77                }
78
79                true
80            })
81        }
82    }
83
84    pub fn write(&self) -> bool {
85        unsafe {
86            self.mutex.lock_mut(|state| {
87                // Can only write if completely unlocked
88                if *state != Self::UNLOCKED {
89                    return false;
90                }
91
92                *state = Self::WRITING; // Write lock
93                true
94            })
95        }
96    }
97
98    pub fn unlock(&self) -> bool {
99        unsafe {
100            self.mutex.lock_mut(|state| {
101                match *state {
102                    Self::UNLOCKED => false, // Not locked
103                    Self::WRITING => {
104                        // Write lock - unlock completely
105                        *state = Self::UNLOCKED;
106                        true
107                    }
108                    n if n >= 2 => {
109                        // Read lock - decrement reader count
110                        *state -= 1;
111                        if *state == Self::WRITING {
112                            // This shouldn't happen, but fix it
113                            *state = Self::UNLOCKED;
114                        }
115                        true
116                    }
117                    _ => false,
118                }
119            })
120        }
121    }
122}
123
124#[unsafe(no_mangle)]
125pub static RAW_RWLOCK_SIZE: usize = size_of::<RawRwLock>();
126
127/// This function is used to initialize a rwlock.
128///
129/// # Safety
130///
131/// This function is unsafe because it dereferences raw pointers.
132///
133/// # Errors
134///
135/// This function may return an error if the rwlock is not initialized.
136#[unsafe(no_mangle)]
137pub unsafe extern "C" fn xila_initialize_rwlock(rwlock: *mut RawRwLock) -> bool {
138    unsafe {
139        if rwlock.is_null() {
140            return false;
141        }
142
143        if !(rwlock as usize).is_multiple_of(align_of::<RawRwLock>()) {
144            return false;
145        }
146
147        rwlock.write(RawRwLock::new());
148
149        true
150    }
151}
152
153/// Read lock a rwlock.
154///
155/// # Safety
156///
157/// The caller must ensure:
158/// - `rwlock` points to a valid, initialized `Raw_rwlock_type`
159/// - The rwlock remains valid for the duration of the call
160#[unsafe(no_mangle)]
161pub unsafe extern "C" fn xila_read_rwlock(rwlock: *mut RawRwLock) -> bool {
162    unsafe {
163        let rwlock = match RawRwLock::from_mutable_pointer(rwlock) {
164            Some(rwlock) => rwlock,
165            None => return false,
166        };
167
168        rwlock.read()
169    }
170}
171
172/// Write lock a rwlock.
173///
174/// # Safety
175///
176/// The caller must ensure:
177/// - `rwlock` points to a valid, initialized `Raw_rwlock_type`
178/// - The rwlock remains valid for the duration of the call
179#[unsafe(no_mangle)]
180pub unsafe extern "C" fn xila_write_rwlock(rwlock: *mut RawRwLock) -> bool {
181    unsafe {
182        let rwlock = match RawRwLock::from_mutable_pointer(rwlock) {
183            Some(rwlock) => rwlock,
184            None => return false,
185        };
186
187        rwlock.write()
188    }
189}
190
191/// Unlock a rwlock.
192///
193/// # Safety
194///
195/// The caller must ensure:
196/// - `rwlock` points to a valid, initialized `Raw_rwlock_type`
197/// - The rwlock remains valid for the duration of the call
198/// - The current task owns the lock (either read or write)
199#[unsafe(no_mangle)]
200pub unsafe extern "C" fn xila_unlock_rwlock(rwlock: *mut RawRwLock) -> bool {
201    unsafe {
202        let rwlock = match RawRwLock::from_mutable_pointer(rwlock) {
203            Some(rwlock) => rwlock,
204            None => return false,
205        };
206
207        rwlock.unlock()
208    }
209}
210
211/// Destroy a rwlock.
212///
213/// # Safety
214///
215/// The caller must ensure:
216/// - `rwlock` points to a valid, initialized `Raw_rwlock_type` allocated with Box
217/// - The rwlock is not currently locked
218/// - No other threads are waiting on the rwlock
219#[unsafe(no_mangle)]
220pub unsafe extern "C" fn xila_destroy_rwlock(rwlock: *mut RawRwLock) -> bool {
221    unsafe {
222        let _ = match RawRwLock::from_mutable_pointer(rwlock) {
223            Some(rw_lock) => rw_lock,
224            None => return false,
225        };
226
227        drop_in_place(rwlock); // Drop the rwlock, releasing resources
228
229        true // RwLock is dropped here
230    }
231}