monitor/mon/space/unmapper.rs
1use std::{panic::catch_unwind, sync::mpsc::Sender, thread::JoinHandle};
2
3use super::MapInfo;
4use crate::mon::get_monitor;
5
6/// Manages a background thread that unmaps mappings.
7pub struct Unmapper {
8 sender: Sender<UnmapCommand>,
9 _thread: JoinHandle<()>,
10}
11
12#[derive(Copy, Clone, Debug)]
13pub enum UnmapCommand {
14 SpaceUnmap(MapInfo),
15}
16
17impl Unmapper {
18 /// Make a new unmapper.
19 pub fn new() -> Self {
20 let (sender, receiver) = std::sync::mpsc::channel();
21 Self {
22 _thread: std::thread::Builder::new()
23 .name("unmapper".to_string())
24 .spawn(move || loop {
25 match receiver.recv() {
26 Ok(info) => {
27 tracing::debug!("unmapper command {:?}", info);
28 if catch_unwind(|| {
29 let monitor = get_monitor();
30 match info {
31 UnmapCommand::SpaceUnmap(info) => {
32 let mut space = monitor.space.lock().unwrap();
33 space.handle_drop(info);
34 }
35 }
36 })
37 .is_err()
38 {
39 tracing::error!(
40 "clean_call panicked -- exiting map cleaner thread"
41 );
42 break;
43 }
44 }
45 Err(_) => {
46 // If receive fails, we can't recover, but this probably doesn't happen
47 // since the sender won't get dropped since this
48 // struct is used in the MapMan static.
49 break;
50 }
51 }
52 })
53 .unwrap(),
54 sender,
55 }
56 }
57
58 /// Enqueue a mapping to be unmapped.
59 pub(super) fn background_unmap_info(&self, info: MapInfo) {
60 // If the receiver is down, this will fail, but that also shouldn't happen, unless the
61 // call to clean_call above panics. In any case, handle this gracefully.
62 if self.sender.send(UnmapCommand::SpaceUnmap(info)).is_err() {
63 tracing::warn!("failed to enqueue Unmap {:?} onto cleaner thread", info);
64 }
65 }
66}