From f7bffacef05301757cd9ca4b5f5c1898442bb55d Mon Sep 17 00:00:00 2001
From: 4lDO2 <4lDO2@protonmail.com>
Date: Mon, 26 Jun 2023 19:58:19 +0200
Subject: [PATCH] Implement Drop for AddrSpace.

---
 src/context/memory.rs  | 12 ++++++++++
 src/scheme/proc.rs     | 21 ++----------------
 src/syscall/process.rs | 50 +++---------------------------------------
 3 files changed, 17 insertions(+), 66 deletions(-)

diff --git a/src/context/memory.rs b/src/context/memory.rs
index b3f3820f..c34d20f5 100644
--- a/src/context/memory.rs
+++ b/src/context/memory.rs
@@ -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() {
diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs
index 52c3fba4..6dbcf111 100644
--- a/src/scheme/proc.rs
+++ b/src/scheme/proc.rs
@@ -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, ());
-        }
-    }
-
-}
diff --git a/src/syscall/process.rs b/src/syscall/process.rs
index 76b2f7b8..1284d317 100644
--- a/src/syscall/process.rs
+++ b/src/syscall/process.rs
@@ -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)
 }
-- 
GitLab