Implement Drop for AddrSpace.

This commit is contained in:
4lDO2
2023-06-26 19:58:19 +02:00
parent 829d2276fb
commit f7bffacef0
3 changed files with 17 additions and 66 deletions
+12
View File
@@ -915,6 +915,18 @@ pub struct Table {
pub utable: PageMapper,
}
impl Drop for AddrSpace {
fn drop(&mut self) {
for grant in core::mem::take(&mut self.grants).into_iter() {
// TODO: Optimize away clearing the actual page tables? Since this address space is no
// longer arc-rwlock wrapped, it cannot be referenced `External`ly by borrowing grants,
// so it should suffice to iterate over PageInfos and decrement and maybe deallocate
// the underlying pages (and send some funmaps possibly).
grant.unmap(&mut self.table.utable, ());
}
}
}
impl Drop for Table {
fn drop(&mut self) {
if self.utable.is_current() {
+2 -19
View File
@@ -616,17 +616,13 @@ impl Scheme for ProcScheme {
context.clone_entry = Some([new_ip, new_sp]);
}
let prev_addr_space = context.set_addr_space(new);
if let Some(prev_addr_space) = prev_addr_space {
maybe_cleanup_addr_space(prev_addr_space);
}
let _prev_addr_space = context.set_addr_space(new);
Ok(())
})?;
let _ = ptrace::send_event(crate::syscall::ptrace_event!(PTRACE_EVENT_ADDRSPACE_SWITCH, 0));
}
Operation::AddrSpace { addrspace } | Operation::MmapMinAddr(addrspace) => maybe_cleanup_addr_space(addrspace),
Operation::AddrSpace { addrspace } | Operation::MmapMinAddr(addrspace) => drop(addrspace),
Operation::AwaitingFiletableChange(new) => with_context_mut(handle.info.pid, |context: &mut Context| {
context.files = new;
@@ -1248,16 +1244,3 @@ fn extract_scheme_number(fd: usize) -> Result<(Arc<dyn KernelScheme>, usize)> {
Ok((scheme, number))
}
fn maybe_cleanup_addr_space(addr_space: Arc<RwLock<AddrSpace>>) {
if let Ok(mut space) = Arc::try_unwrap(addr_space).map(RwLock::into_inner) {
// We are the last reference to the address space; therefore it must be
// unmapped.
// TODO: Optimize away clearing of page tables? In that case, what about memory
// deallocation?
for grant in space.grants.into_iter() {
grant.unmap(&mut space.table.utable, ());
}
}
}
+3 -47
View File
@@ -25,44 +25,6 @@ use crate::syscall::ptrace_event;
use super::usercopy::{UserSliceWo, UserSliceRo};
fn empty<'lock>(context_lock: &'lock RwLock<Context>, mut context: RwLockWriteGuard<'lock, Context>, reaping: bool) -> RwLockWriteGuard<'lock, Context> {
// NOTE: If we do not replace the grants `Arc`, then a strange situation can appear where the
// main thread and another thread exit simultaneously before either one is reaped. If that
// happens, then the last context that runs exit will think that there is still are still
// remaining references to the grants, where there are in fact none. However, if either one is
// reaped before, then that reference will disappear, and no leak will occur.
//
// By removing the reference to the address space when the context will no longer be used, this
// problem will never occur.
let addr_space_arc = match context.addr_space.take() {
Some(a) => a,
None => return context,
};
if let Ok(mut addr_space) = Arc::try_unwrap(addr_space_arc).map(RwLock::into_inner) {
let mapper = &mut addr_space.table.utable;
for grant in addr_space.grants.into_iter() {
let unmap_result = if reaping {
log::error!("{}: {}: Grant should not exist: {:?}", context.id.into(), context.name, grant);
grant.unmap(mapper, &mut InactiveFlusher::new())
} else {
grant.unmap(mapper, PageFlushAll::new())
};
if unmap_result.file_desc.is_some() {
drop(context);
drop(unmap_result);
context = context_lock.write();
}
}
}
context
}
pub fn exit(status: usize) -> ! {
ptrace::breakpoint_callback(PTRACE_STOP_EXIT, Some(ptrace_event!(PTRACE_STOP_EXIT, status)));
@@ -119,8 +81,6 @@ pub fn exit(status: usize) -> ! {
let children = {
let mut context = context_lock.write();
context = empty(&context_lock, context, false);
context.status = context::Status::Exited(status);
context.waitpid.receive_all()
@@ -407,6 +367,7 @@ fn reap(pid: ContextId) -> Result<ContextId> {
// Spin until not running
let mut running = true;
while running {
// TODO: exit WaitCondition?
{
let contexts = context::contexts();
let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?;
@@ -417,13 +378,8 @@ fn reap(pid: ContextId) -> Result<ContextId> {
interrupt::pause();
}
let mut contexts = context::contexts_mut();
let context_lock = contexts.remove(pid).ok_or(Error::new(ESRCH))?;
{
let context = context_lock.write();
empty(&context_lock, context, true);
}
drop(context_lock);
let _ = context::contexts_mut()
.remove(pid).ok_or(Error::new(ESRCH))?;
Ok(pid)
}