Working version
This commit is contained in:
@@ -1,2 +1,19 @@
|
|||||||
# access-cell
|
# access-cell
|
||||||
A synchronous, single-threaded Mutex<T> anti-locking system
|
A synchronous, single-threaded Mutex<T> anti-locking system
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let value = Arc::new(AccessCell::new(0));
|
||||||
|
|
||||||
|
value.access({
|
||||||
|
let value = value.clone();
|
||||||
|
|
||||||
|
move |_| {
|
||||||
|
// normally this would cause a deadlock
|
||||||
|
value.access(|v| {
|
||||||
|
*v = 10;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(*value.access_ref(), 10);
|
||||||
|
```
|
||||||
|
|||||||
+66
-8
@@ -1,14 +1,72 @@
|
|||||||
pub fn add(left: u64, right: u64) -> u64 {
|
use std::{
|
||||||
left + right
|
cell::{Cell, UnsafeCell},
|
||||||
|
collections::VecDeque,
|
||||||
|
sync::Mutex,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct AccessCell<T> {
|
||||||
|
value: UnsafeCell<T>,
|
||||||
|
running: Cell<bool>,
|
||||||
|
queue: Mutex<VecDeque<Box<dyn FnOnce(&mut T)>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AccessCell<T> {
|
||||||
|
pub fn new(value: T) -> Self {
|
||||||
|
Self {
|
||||||
|
value: UnsafeCell::new(value),
|
||||||
|
running: Cell::new(false),
|
||||||
|
queue: Mutex::new(VecDeque::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn access(&self, f: impl FnOnce(&mut T) + 'static) {
|
||||||
|
// already inside → enqueue
|
||||||
|
if self.running.get() {
|
||||||
|
self.queue.lock().unwrap().push_back(Box::new(f));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// first entrant = executor
|
||||||
|
self.running.set(true);
|
||||||
|
|
||||||
|
// call current
|
||||||
|
f(self.access_mut());
|
||||||
|
|
||||||
|
// drain queued re-entrant calls
|
||||||
|
while let Some(job) = self.queue.lock().unwrap().pop_front() {
|
||||||
|
let value = self.access_mut();
|
||||||
|
job(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.running.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn access_mut(&self) -> &mut T {
|
||||||
|
unsafe { &mut *self.value.get() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn access_ref(&self) -> &T {
|
||||||
|
unsafe { &*self.value.get() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_works() {
|
fn test_access() {
|
||||||
let result = add(2, 2);
|
let value = std::sync::Arc::new(crate::AccessCell::new(0));
|
||||||
assert_eq!(result, 4);
|
|
||||||
|
value.access({
|
||||||
|
let value = value.clone();
|
||||||
|
|
||||||
|
move |_| {
|
||||||
|
// normally this would cause a deadlock
|
||||||
|
value.access(|v| {
|
||||||
|
*v = 10;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(*value.access_ref(), 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user