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}