concurrent, realtime write data structure.
at main 6.4 kB view raw
1// std::mem::forget creates issues because you can run a lock function without running the unlock function 2// i deal with this by tracking for Reader and Writer if they are locked currently. If a new locked is aquired 3// while it's still locked it panics. If Reader or Writer are dropped while locked it also panics. 4// 5// This could be circumvented by leaking Reader or Writer, but this doesn't lead to issues as then it's impossible 6// to aquire a new Reader or Writer, because then the count also wasn't decremented. 7// 8// This panics more often than UB would occur without this detection, but this exact specs is a implementation detail 9// and users just shouldn't forget the Guards. 10 11#![no_std] 12 13extern crate alloc; 14 15use core::{ 16 marker::PhantomData, 17 ops::{Deref, DerefMut}, 18 ptr::NonNull, 19}; 20 21mod shared; 22 23use shared::{Ptr, Shared}; 24 25pub struct Reader<T> { 26 shared: NonNull<Shared<T>>, 27 locked: bool, 28 _owned: PhantomData<T>, 29} 30 31impl<T> Reader<T> { 32 pub fn try_read(&mut self) -> Option<ReadGuard<'_, T>> { 33 if self.locked { 34 self.locked = false; // don't also panic in the destructor 35 panic!("ReadGuard was forgotten"); 36 } 37 let shared = self.get_shared(); 38 let value = shared.try_read(); 39 // SAFETY: try_read returned Some to allowed to get a shared ref 40 let value = value.map(|v| unsafe { &*v.get() }); 41 if let Some(value) = value { 42 // only set locked if locking actually was successful 43 self.locked = true; 44 Some(ReadGuard { 45 reader: self, 46 value, 47 }) 48 } else { 49 None 50 } 51 } 52 53 fn get_shared(&self) -> &Shared<T> { 54 // SAFETY: the shared is always valid 55 unsafe { self.shared.as_ref() } 56 } 57 58 pub fn get_writer(&mut self) -> Option<Writer<T>> { 59 let shared = self.get_shared(); 60 if shared.try_create_other() { 61 Some(Writer { 62 shared: self.shared, 63 locked: false, 64 _owned: PhantomData, 65 }) 66 } else { 67 None 68 } 69 } 70} 71 72unsafe impl<T: Send + Sync> Send for Reader<T> {} 73 74impl<T: Clone> Reader<T> { 75 pub fn new(value: T) -> Self { 76 Self { 77 shared: Shared::new(value), 78 _owned: PhantomData, 79 locked: false, 80 } 81 } 82} 83 84impl<T: Default> Default for Reader<T> { 85 fn default() -> Self { 86 Self { 87 shared: Shared::new_default(), 88 _owned: PhantomData, 89 locked: false, 90 } 91 } 92} 93 94impl<T> Drop for Reader<T> { 95 fn drop(&mut self) { 96 // SAFETY: ptr is valid and not used after this 97 unsafe { 98 Shared::drop(self.shared); 99 } 100 assert!(!self.locked, "ReadGuard was forgotten") 101 } 102} 103 104pub struct ReadGuard<'a, T> { 105 reader: &'a mut Reader<T>, 106 value: &'a T, 107} 108 109impl<T> Deref for ReadGuard<'_, T> { 110 type Target = T; 111 112 fn deref(&self) -> &Self::Target { 113 self.value 114 } 115} 116 117impl<T> Drop for ReadGuard<'_, T> { 118 fn drop(&mut self) { 119 self.reader.locked = false; 120 self.reader.get_shared().remove_current_read(); 121 } 122} 123 124pub struct Writer<T> { 125 shared: NonNull<Shared<T>>, 126 _owned: PhantomData<T>, 127 locked: bool, 128} 129 130impl<T> Writer<T> { 131 fn get_shared(&self) -> &Shared<T> { 132 // SAFETY: the shared is always valid 133 unsafe { self.shared.as_ref() } 134 } 135 136 pub fn write(&mut self) -> WriteGuard<'_, T> { 137 if self.locked { 138 self.locked = false; // don't also panic in the destructor 139 panic!("WriteGuard was forgotten"); 140 } 141 // locking here is always successfull, so we set it unconditionally 142 self.locked = true; 143 let shared = self.get_shared(); 144 // SAFETY: won't be called again while the mut ref is still live, as the write method needs a mut ref 145 let pre_res = unsafe { shared.write() }; 146 // SAFETY: was just locked 147 let value = unsafe { &mut *pre_res.0.get() }; 148 let ptr = pre_res.1; 149 150 WriteGuard { 151 writer: self, 152 value, 153 next_read: ptr, 154 } 155 } 156} 157 158impl<T> Drop for Writer<T> { 159 fn drop(&mut self) { 160 // SAFETY: ptr is valid and not used after this 161 unsafe { 162 Shared::drop(self.shared); 163 } 164 assert!(!self.locked, "WriteGuard was forgotten") 165 } 166} 167 168unsafe impl<T: Send + Sync> Send for Writer<T> {} 169 170/// The data should always be replaced completely. Incremental updates can lead to the reader seeing inconsistent data, 171/// as the data structure uses two copies of the data internally and alternates between writing to both of them. 172/// The copies will start to diverge when doing changes instead of replacing it. 173/// 174/// I still offer DerefMut instead of just taking a new T, because this allows reusing allocations inside of T instead of 175/// dropping and reallocing. This is important for realtime usecases. 176pub struct WriteGuard<'a, T> { 177 writer: &'a mut Writer<T>, 178 value: &'a mut T, 179 // if some: set the next_read bit to the ptr value for unlocking 180 // if none: set the read_allowed bit. The next_read bit is already correct 181 next_read: Option<Ptr>, 182} 183 184// i don't really want this. I would prefer to only write, but i need a mut ref to be able to write rt-safe. 185// and for DerefMut i need Deref. 186impl<T> Deref for WriteGuard<'_, T> { 187 type Target = T; 188 189 fn deref(&self) -> &Self::Target { 190 self.value 191 } 192} 193 194impl<T> DerefMut for WriteGuard<'_, T> { 195 fn deref_mut(&mut self) -> &mut Self::Target { 196 self.value 197 } 198} 199 200impl<T> Drop for WriteGuard<'_, T> { 201 fn drop(&mut self) { 202 self.writer.get_shared().unlock_write(self.next_read); 203 self.writer.locked = false; 204 } 205} 206 207#[cfg(test)] 208mod internal_tests { 209 use crate::Reader; 210 211 #[test] 212 fn drop_tests() { 213 let mut reader: Reader<u32> = Reader::default(); 214 assert!(reader.get_shared().is_unique()); 215 let writer = reader.get_writer().unwrap(); 216 assert!(!writer.get_shared().is_unique()); 217 assert!(!reader.get_shared().is_unique()); 218 219 drop(writer); 220 assert!(reader.get_shared().is_unique()); 221 222 let writer = reader.get_writer().unwrap(); 223 224 drop(reader); 225 assert!(writer.get_shared().is_unique()); 226 } 227}