You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
2.5 KiB
92 lines
2.5 KiB
use std::fmt;
|
|
use std::fmt::Formatter;
|
|
use std::sync::atomic::{AtomicU32, Ordering};
|
|
|
|
use crate::runtime::fault::Fault;
|
|
use crate::runtime::run_thread::ThreadToken;
|
|
use crate::runtime::span::MemorySpan;
|
|
|
|
/// Records memory claims and protects from illegal access
|
|
#[derive(Debug, Default)]
|
|
struct MemoryGuard {
|
|
claims: Vec<Claim>,
|
|
counter: AtomicU32,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Eq, PartialEq, Debug, Ord, PartialOrd)]
|
|
pub struct ClaimId(pub u32);
|
|
|
|
impl fmt::Display for ClaimId {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
write!(f, "{}", self.0)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
struct Claim {
|
|
owner: ThreadToken,
|
|
span: MemorySpan,
|
|
id: ClaimId,
|
|
}
|
|
|
|
impl MemoryGuard {
|
|
pub fn new() -> Self {
|
|
Default::default()
|
|
}
|
|
|
|
/// Claim a memory area
|
|
pub fn claim(&mut self, owner: ThreadToken, span: MemorySpan) -> Result<ClaimId, Fault> {
|
|
// naive
|
|
for claim in &self.claims {
|
|
if claim.span.intersects(span) && claim.owner != owner {
|
|
return Err(Fault::MemoryLocked {
|
|
area: claim.span,
|
|
owner: claim.owner,
|
|
});
|
|
}
|
|
}
|
|
|
|
let id = self.next_id();
|
|
|
|
self.claims.push(Claim {
|
|
id,
|
|
owner,
|
|
span,
|
|
});
|
|
|
|
Ok(id)
|
|
}
|
|
|
|
/// Get a unique claim ID and increment the counter
|
|
pub fn next_id(&self) -> ClaimId {
|
|
ClaimId(self.counter.fetch_and(1, Ordering::Relaxed))
|
|
}
|
|
|
|
/// Get the next claim ID (ID is incremented after calling "next").
|
|
/// May be used for release_owned_after()
|
|
pub fn epoch(&self) -> ClaimId {
|
|
ClaimId(self.counter.load(Ordering::Relaxed))
|
|
}
|
|
|
|
/// Release a claim by claim ID
|
|
pub fn release(&mut self, owner: ThreadToken, claim: ClaimId) -> Result<(), Fault> {
|
|
match self.claims.iter().position(|c| c.id == claim && c.owner == owner) {
|
|
Some(pos) => {
|
|
self.claims.swap_remove(pos);
|
|
Ok(())
|
|
}
|
|
None => Err(Fault::ClaimNotExist { claim, owner }),
|
|
}
|
|
}
|
|
|
|
/// Release all owned by a thread (thread ends)
|
|
pub fn release_owned(&mut self, owner: ThreadToken) {
|
|
self.claims.retain(|c| c.owner != owner);
|
|
}
|
|
|
|
/// Release all owned by a thread, with claim ID >= a given value
|
|
/// (return from a subroutine)
|
|
pub fn release_owned_after(&mut self, owner: ThreadToken, epoch: ClaimId) {
|
|
self.claims.retain(|c| c.owner != owner || c.id >= epoch);
|
|
}
|
|
}
|
|
|