use crate::rt::object;
use crate::rt::{thread, Access, Synchronize, VersionVec};
use std::sync::atomic::Ordering::{Acquire, Release};
#[derive(Debug, Copy, Clone)]
pub(crate) struct Mutex {
state: object::Ref<State>,
}
#[derive(Debug)]
pub(super) struct State {
seq_cst: bool,
lock: Option<thread::Id>,
last_access: Option<Access>,
synchronize: Synchronize,
}
impl Mutex {
pub(crate) fn new(seq_cst: bool) -> Mutex {
super::execution(|execution| {
let state = execution.objects.insert(State {
seq_cst,
lock: None,
last_access: None,
synchronize: Synchronize::new(),
});
Mutex { state }
})
}
pub(crate) fn acquire_lock(&self) {
self.state.branch_acquire(self.is_locked());
assert!(self.post_acquire(), "expected to be able to acquire lock");
}
pub(crate) fn try_acquire_lock(&self) -> bool {
self.state.branch_opaque();
self.post_acquire()
}
pub(crate) fn release_lock(&self) {
super::execution(|execution| {
let state = self.state.get_mut(&mut execution.objects);
state.lock = None;
state
.synchronize
.sync_store(&mut execution.threads, Release);
if state.seq_cst {
execution.threads.seq_cst();
}
let thread_id = execution.threads.active_id();
for (id, thread) in execution.threads.iter_mut() {
if id == thread_id {
continue;
}
let obj = thread
.operation
.as_ref()
.map(|operation| operation.object());
if obj == Some(self.state.erase()) {
thread.set_runnable();
}
}
});
}
fn post_acquire(&self) -> bool {
super::execution(|execution| {
let state = self.state.get_mut(&mut execution.objects);
let thread_id = execution.threads.active_id();
if state.lock.is_some() {
return false;
}
state.lock = Some(thread_id);
dbg!(state.synchronize.sync_load(&mut execution.threads, Acquire));
if state.seq_cst {
execution.threads.seq_cst();
}
for (id, thread) in execution.threads.iter_mut() {
if id == thread_id {
continue;
}
let obj = thread
.operation
.as_ref()
.map(|operation| operation.object());
if obj == Some(self.state.erase()) {
thread.set_blocked();
}
}
true
})
}
fn is_locked(&self) -> bool {
super::execution(|execution| self.state.get(&execution.objects).lock.is_some())
}
}
impl State {
pub(crate) fn last_dependent_access(&self) -> Option<&Access> {
self.last_access.as_ref()
}
pub(crate) fn set_last_access(&mut self, path_id: usize, version: &VersionVec) {
Access::set_or_create(&mut self.last_access, path_id, version);
}
}