Skip to main content

os/task/
id.rs

1use super::ProcessControlBlock;
2use crate::config::{KERNEL_STACK_SIZE, PAGE_SIZE, TRAMPOLINE, TRAP_CONTEXT_BASE, USER_STACK_SIZE};
3use crate::mm::{KERNEL_SPACE, MapPermission, PhysPageNum, VirtAddr};
4use crate::sync::UPSafeCell;
5use alloc::{
6    sync::{Arc, Weak},
7    vec::Vec,
8};
9use lazy_static::*;
10
11pub struct RecycleAllocator {
12    current: usize,
13    recycled: Vec<usize>,
14}
15
16impl RecycleAllocator {
17    pub fn new() -> Self {
18        Self::new_start(0)
19    }
20    pub fn new_start(current: usize) -> Self {
21        RecycleAllocator {
22            current,
23            recycled: Vec::new(),
24        }
25    }
26    pub fn alloc(&mut self) -> usize {
27        if let Some(id) = self.recycled.pop() {
28            id
29        } else {
30            self.current += 1;
31            self.current - 1
32        }
33    }
34    pub fn dealloc(&mut self, id: usize) {
35        assert!(id < self.current);
36        assert!(
37            !self.recycled.iter().any(|i| *i == id),
38            "id {} has been deallocated!",
39            id
40        );
41        self.recycled.push(id);
42    }
43}
44
45lazy_static! {
46    static ref PID_ALLOCATOR: UPSafeCell<RecycleAllocator> =
47        unsafe { UPSafeCell::new(RecycleAllocator::new_start(1)) };
48    static ref KSTACK_ALLOCATOR: UPSafeCell<RecycleAllocator> =
49        unsafe { UPSafeCell::new(RecycleAllocator::new()) };
50}
51
52pub const IDLE_PID: usize = 1;
53
54pub struct PidHandle(pub usize);
55
56pub fn pid_alloc() -> PidHandle {
57    PidHandle(PID_ALLOCATOR.exclusive_access().alloc())
58}
59
60impl Drop for PidHandle {
61    fn drop(&mut self) {
62        PID_ALLOCATOR.exclusive_access().dealloc(self.0);
63    }
64}
65
66/// Return (bottom, top) of a kernel stack in kernel space.
67pub fn kernel_stack_position(kstack_id: usize) -> (usize, usize) {
68    let top = TRAMPOLINE - kstack_id * (KERNEL_STACK_SIZE + PAGE_SIZE);
69    let bottom = top - KERNEL_STACK_SIZE;
70    (bottom, top)
71}
72
73pub struct KernelStack(pub usize);
74
75pub fn kstack_alloc() -> KernelStack {
76    let kstack_id = KSTACK_ALLOCATOR.exclusive_access().alloc();
77    let (kstack_bottom, kstack_top) = kernel_stack_position(kstack_id);
78    KERNEL_SPACE.exclusive_access().insert_framed_area(
79        kstack_bottom.into(),
80        kstack_top.into(),
81        MapPermission::R | MapPermission::W,
82    );
83    KernelStack(kstack_id)
84}
85
86impl Drop for KernelStack {
87    fn drop(&mut self) {
88        let (kernel_stack_bottom, _) = kernel_stack_position(self.0);
89        let kernel_stack_bottom_va: VirtAddr = kernel_stack_bottom.into();
90        KERNEL_SPACE
91            .exclusive_access()
92            .remove_area_with_start_vpn(kernel_stack_bottom_va.into());
93        KSTACK_ALLOCATOR.exclusive_access().dealloc(self.0);
94    }
95}
96
97impl KernelStack {
98    #[allow(unused)]
99    pub fn push_on_top<T>(&self, value: T) -> *mut T
100    where
101        T: Sized,
102    {
103        let kernel_stack_top = self.get_top();
104        let ptr_mut = (kernel_stack_top - core::mem::size_of::<T>()) as *mut T;
105        unsafe {
106            *ptr_mut = value;
107        }
108        ptr_mut
109    }
110    pub fn get_top(&self) -> usize {
111        let (_, kernel_stack_top) = kernel_stack_position(self.0);
112        kernel_stack_top
113    }
114}
115
116pub struct TaskUserRes {
117    pub tid: usize,
118    pub ustack_base: usize,
119    pub process: Weak<ProcessControlBlock>,
120}
121
122fn trap_cx_bottom_from_tid(tid: usize) -> usize {
123    TRAP_CONTEXT_BASE - tid * PAGE_SIZE
124}
125
126fn ustack_bottom_from_tid(ustack_base: usize, tid: usize) -> usize {
127    ustack_base + tid * (PAGE_SIZE + USER_STACK_SIZE)
128}
129
130impl TaskUserRes {
131    pub fn new(
132        process: Arc<ProcessControlBlock>,
133        ustack_base: usize,
134        alloc_user_res: bool,
135    ) -> Self {
136        let tid = process.inner_exclusive_access().alloc_tid();
137        let task_user_res = Self {
138            tid,
139            ustack_base,
140            process: Arc::downgrade(&process),
141        };
142        if alloc_user_res {
143            task_user_res.alloc_user_res();
144        }
145        task_user_res
146    }
147
148    pub fn alloc_user_res(&self) {
149        let process = self.process.upgrade().unwrap();
150        let mut process_inner = process.inner_exclusive_access();
151        // alloc user stack
152        let ustack_bottom = ustack_bottom_from_tid(self.ustack_base, self.tid);
153        let ustack_top = ustack_bottom + USER_STACK_SIZE;
154        process_inner.memory_set.insert_framed_area(
155            ustack_bottom.into(),
156            ustack_top.into(),
157            MapPermission::R | MapPermission::W | MapPermission::U,
158        );
159        // alloc trap_cx
160        let trap_cx_bottom = trap_cx_bottom_from_tid(self.tid);
161        let trap_cx_top = trap_cx_bottom + PAGE_SIZE;
162        process_inner.memory_set.insert_framed_area(
163            trap_cx_bottom.into(),
164            trap_cx_top.into(),
165            MapPermission::R | MapPermission::W,
166        );
167    }
168
169    fn dealloc_user_res(&self) {
170        // dealloc tid
171        let process = self.process.upgrade().unwrap();
172        let mut process_inner = process.inner_exclusive_access();
173        // dealloc ustack manually
174        let ustack_bottom_va: VirtAddr = ustack_bottom_from_tid(self.ustack_base, self.tid).into();
175        process_inner
176            .memory_set
177            .remove_area_with_start_vpn(ustack_bottom_va.into());
178        // dealloc trap_cx manually
179        let trap_cx_bottom_va: VirtAddr = trap_cx_bottom_from_tid(self.tid).into();
180        process_inner
181            .memory_set
182            .remove_area_with_start_vpn(trap_cx_bottom_va.into());
183    }
184
185    #[allow(unused)]
186    pub fn alloc_tid(&mut self) {
187        self.tid = self
188            .process
189            .upgrade()
190            .unwrap()
191            .inner_exclusive_access()
192            .alloc_tid();
193    }
194
195    pub fn dealloc_tid(&self) {
196        let process = self.process.upgrade().unwrap();
197        let mut process_inner = process.inner_exclusive_access();
198        process_inner.dealloc_tid(self.tid);
199    }
200
201    pub fn trap_cx_user_va(&self) -> usize {
202        trap_cx_bottom_from_tid(self.tid)
203    }
204
205    pub fn trap_cx_ppn(&self) -> PhysPageNum {
206        let process = self.process.upgrade().unwrap();
207        let process_inner = process.inner_exclusive_access();
208        let trap_cx_bottom_va: VirtAddr = trap_cx_bottom_from_tid(self.tid).into();
209        process_inner
210            .memory_set
211            .translate(trap_cx_bottom_va.into())
212            .unwrap()
213            .ppn()
214    }
215
216    pub fn ustack_base(&self) -> usize {
217        self.ustack_base
218    }
219    pub fn ustack_top(&self) -> usize {
220        ustack_bottom_from_tid(self.ustack_base, self.tid) + USER_STACK_SIZE
221    }
222}
223
224impl Drop for TaskUserRes {
225    fn drop(&mut self) {
226        self.dealloc_tid();
227        self.dealloc_user_res();
228    }
229}