os/ipc/
shared_memory.rs

1//! 共享内存模块
2//!
3//! 提供共享物理页的分配与映射到当前进程用户空间的能力。
4
5use alloc::{sync::Arc, vec::Vec};
6
7use crate::{
8    config::PAGE_SIZE,
9    kernel::current_cpu,
10    mm::{
11        frame_allocator::{FrameTracker, alloc_frames},
12        page_table::{PagingError, UniversalPTEFlag},
13    },
14};
15
16/// 共享内存表:简单管理若干共享段
17pub struct SharedMemoryTable {
18    memory: Vec<Arc<SharedMemory>>,
19}
20
21impl SharedMemoryTable {
22    /// 创建共享内存表
23    pub fn new() -> Self {
24        Self { memory: Vec::new() }
25    }
26
27    /// 新建共享段并登记,返回 Arc 句柄
28    pub fn create(&mut self, pages: usize) -> Arc<SharedMemory> {
29        let shm = Arc::new(SharedMemory::new(pages));
30        self.memory.push(shm.clone());
31        shm
32    }
33
34    /// 简单移除(若还被其他地方持有 Arc,不会真正释放)
35    pub fn remove(&mut self, shm: &Arc<SharedMemory>) -> bool {
36        if let Some(i) = self.memory.iter().position(|x| Arc::ptr_eq(x, shm)) {
37            self.memory.swap_remove(i);
38            // XXX: 是不是还应取消在当前进程用户空间上的映射
39            true
40        } else {
41            false
42        }
43    }
44
45    /// 当前已登记的共享段数量
46    pub fn len(&self) -> usize {
47        self.memory.len()
48    }
49
50    pub fn is_empty(&self) -> bool {
51        self.memory.is_empty()
52    }
53}
54
55/// 共享内存:持有一组物理页(FrameTracker)
56pub struct SharedMemory {
57    frames: Vec<FrameTracker>,
58    len: usize,
59}
60
61impl SharedMemory {
62    /// 分配 pages 个物理页作为共享段
63    pub fn new(pages: usize) -> Self {
64        let frames = alloc_frames(pages).expect("unable to alloc shared memory");
65        SharedMemory {
66            frames,
67            len: pages * PAGE_SIZE,
68        }
69    }
70
71    /// 共享段字节数
72    pub fn len(&self) -> usize {
73        self.len
74    }
75
76    pub fn is_empty(&self) -> bool {
77        self.len == 0
78    }
79
80    /// 将共享段映射到当前进程用户空间
81    /// 返回
82    /// - Ok(usize) 成功;Err(PagingError) 失败
83    pub fn map_to_user(self) -> Result<usize, PagingError> {
84        let current = {
85            let cpu = current_cpu().lock();
86            cpu.current_task
87                .as_ref()
88                .expect("map_to_user_at: no current task")
89                .clone()
90        };
91        let mut task = current.lock();
92        let space = task
93            .memory_space
94            .as_mut()
95            .expect("map_to_user_at: task has no user memory space");
96
97        let flags = UniversalPTEFlag::READABLE
98            | UniversalPTEFlag::WRITEABLE
99            | UniversalPTEFlag::USER_ACCESSIBLE
100            | UniversalPTEFlag::VALID;
101
102        space.lock().mmap(0, self.len, flags)
103    }
104}