diff options
Diffstat (limited to 'src/no_threads.rs')
| -rwxr-xr-x | src/no_threads.rs | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/src/no_threads.rs b/src/no_threads.rs new file mode 100755 index 0000000..f831f5f --- /dev/null +++ b/src/no_threads.rs @@ -0,0 +1,122 @@ +use core::cell::Cell; + +pub struct Mutex { + // This platform has no threads, so we can use a Cell here. + locked: Cell<bool>, +} + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} // no threads on this platform + +impl Mutex { + #[inline] + pub const fn new() -> Mutex { + Mutex { + locked: Cell::new(false), + } + } + + /// Locks the mutex + /// + /// # Safety + /// + /// UB occurs if the mutex is already locked by the current thread and the + /// `unsafe_lock` feature is enabled. + #[inline] + pub unsafe fn lock(&self) { + if self.locked.replace(true) { + if cfg!(feature = "unsafe_lock") { + // safety: it's UB to lock this when it's already locked + unsafe { core::hint::unreachable_unchecked() }; + } else { + panic!("deadlock on a platform with no threads"); + } + } + } + + /// If the mutex is unlocked, it is locked, and this function returns + /// `true'. Otherwise, `false` is returned. + #[inline] + pub unsafe fn try_lock(&self) -> bool { + self.locked.replace(true) == false + } + + /// Unlocks the mutex + /// + /// # Safety + /// + /// UB occurs if the mutex is already unlocked or if it has been locked on + /// a different thread. + #[inline] + pub unsafe fn unlock(&self) { + self.locked.set(false); + } + + #[inline] + pub unsafe fn is_locked(&self) -> bool { + self.locked.get() + } +} + +pub struct RwLock { + // This platform has no threads, so we can use a Cell here. + mode: Cell<isize>, +} + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} // no threads on this platform + +impl RwLock { + #[inline] + pub const fn new() -> RwLock { + RwLock { mode: Cell::new(0) } + } + + #[inline] + pub unsafe fn read(&self) { + let m = self.mode.get(); + if m >= 0 { + self.mode.set(m + 1); + } else { + unsafe { core::hint::unreachable_unchecked() }; + } + } + + #[inline] + pub unsafe fn try_read(&self) -> bool { + let m = self.mode.get(); + if m >= 0 { + self.mode.set(m + 1); + true + } else { + false + } + } + + #[inline] + pub unsafe fn write(&self) { + if self.mode.replace(isize::MAX) != 0 { + unsafe { core::hint::unreachable_unchecked() }; + } + } + + #[inline] + pub unsafe fn try_write(&self) -> bool { + if self.mode.get() == 0 { + self.mode.set(-1); + true + } else { + false + } + } + + #[inline] + pub unsafe fn read_unlock(&self) { + self.mode.set(self.mode.get() - 1); + } + + #[inline] + pub unsafe fn write_unlock(&self) { + assert_eq!(self.mode.replace(0), -1); + } +} |
