1use super::TaskControlBlock;
2use super::id::RecycleAllocator;
3use super::manager::insert_into_pid2process;
4use super::{PidHandle, pid_alloc};
5use super::{SignalFlags, add_task};
6use crate::fs::{File, Stdin, Stdout};
7use crate::mm::{KERNEL_SPACE, MemorySet, translated_refmut};
8use crate::sync::{Condvar, Mutex, Semaphore, UPSafeCell};
9use crate::trap::{TrapContext, trap_handler};
10use alloc::string::String;
11use alloc::sync::{Arc, Weak};
12use alloc::vec;
13use alloc::vec::Vec;
14use core::cell::RefMut;
15
16pub struct ProcessControlBlock {
17 pub pid: PidHandle,
19 inner: UPSafeCell<ProcessControlBlockInner>,
21}
22
23pub struct ProcessControlBlockInner {
24 pub is_zombie: bool,
25 pub memory_set: MemorySet,
26 pub parent: Option<Weak<ProcessControlBlock>>,
27 pub children: Vec<Arc<ProcessControlBlock>>,
28 pub exit_code: i32,
29 pub fd_table: Vec<Option<Arc<dyn File + Send + Sync>>>,
30 pub signals: SignalFlags,
31 pub tasks: Vec<Option<Arc<TaskControlBlock>>>,
32 pub task_res_allocator: RecycleAllocator,
33 pub mutex_list: Vec<Option<Arc<dyn Mutex>>>,
34 pub semaphore_list: Vec<Option<Arc<Semaphore>>>,
35 pub condvar_list: Vec<Option<Arc<Condvar>>>,
36}
37
38impl ProcessControlBlockInner {
39 #[allow(unused)]
40 pub fn get_user_token(&self) -> usize {
41 self.memory_set.token()
42 }
43
44 pub fn alloc_fd(&mut self) -> usize {
45 if let Some(fd) = (0..self.fd_table.len()).find(|fd| self.fd_table[*fd].is_none()) {
46 fd
47 } else {
48 self.fd_table.push(None);
49 self.fd_table.len() - 1
50 }
51 }
52
53 pub fn alloc_tid(&mut self) -> usize {
54 self.task_res_allocator.alloc()
55 }
56
57 pub fn dealloc_tid(&mut self, tid: usize) {
58 self.task_res_allocator.dealloc(tid)
59 }
60
61 pub fn thread_count(&self) -> usize {
62 self.tasks.len()
63 }
64
65 pub fn get_task(&self, tid: usize) -> Arc<TaskControlBlock> {
66 self.tasks[tid].as_ref().unwrap().clone()
67 }
68}
69
70impl ProcessControlBlock {
71 pub fn inner_exclusive_access(&self) -> RefMut<'_, ProcessControlBlockInner> {
72 self.inner.exclusive_access()
73 }
74
75 pub fn new(elf_data: &[u8]) -> Arc<Self> {
76 let (memory_set, ustack_base, entry_point) = MemorySet::from_elf(elf_data);
78 let pid_handle = pid_alloc();
80 let process = Arc::new(Self {
81 pid: pid_handle,
82 inner: unsafe {
83 UPSafeCell::new(ProcessControlBlockInner {
84 is_zombie: false,
85 memory_set,
86 parent: None,
87 children: Vec::new(),
88 exit_code: 0,
89 fd_table: vec![
90 Some(Arc::new(Stdin)),
92 Some(Arc::new(Stdout)),
94 Some(Arc::new(Stdout)),
96 ],
97 signals: SignalFlags::empty(),
98 tasks: Vec::new(),
99 task_res_allocator: RecycleAllocator::new(),
100 mutex_list: Vec::new(),
101 semaphore_list: Vec::new(),
102 condvar_list: Vec::new(),
103 })
104 },
105 });
106 let task = Arc::new(TaskControlBlock::new(
108 Arc::clone(&process),
109 ustack_base,
110 true,
111 ));
112 let task_inner = task.inner_exclusive_access();
114 let trap_cx = task_inner.get_trap_cx();
115 let ustack_top = task_inner.res.as_ref().unwrap().ustack_top();
116 let kstack_top = task.kstack.get_top();
117 drop(task_inner);
118 *trap_cx = TrapContext::app_init_context(
119 entry_point,
120 ustack_top,
121 KERNEL_SPACE.exclusive_access().token(),
122 kstack_top,
123 trap_handler as usize,
124 );
125 let mut process_inner = process.inner_exclusive_access();
127 process_inner.tasks.push(Some(Arc::clone(&task)));
128 drop(process_inner);
129 insert_into_pid2process(process.getpid(), Arc::clone(&process));
130 add_task(task);
132 process
133 }
134
135 pub fn exec(self: &Arc<Self>, elf_data: &[u8], args: Vec<String>) {
137 assert_eq!(self.inner_exclusive_access().thread_count(), 1);
138 let (memory_set, ustack_base, entry_point) = MemorySet::from_elf(elf_data);
140 let new_token = memory_set.token();
141 self.inner_exclusive_access().memory_set = memory_set;
143 let task = self.inner_exclusive_access().get_task(0);
146 let mut task_inner = task.inner_exclusive_access();
147 task_inner.res.as_mut().unwrap().ustack_base = ustack_base;
148 task_inner.res.as_mut().unwrap().alloc_user_res();
149 task_inner.trap_cx_ppn = task_inner.res.as_mut().unwrap().trap_cx_ppn();
150 let mut user_sp = task_inner.res.as_mut().unwrap().ustack_top();
152 user_sp -= (args.len() + 1) * core::mem::size_of::<usize>();
153 let argv_base = user_sp;
154 let mut argv: Vec<_> = (0..=args.len())
155 .map(|arg| {
156 translated_refmut(
157 new_token,
158 (argv_base + arg * core::mem::size_of::<usize>()) as *mut usize,
159 )
160 })
161 .collect();
162 *argv[args.len()] = 0;
163 for i in 0..args.len() {
164 user_sp -= args[i].len() + 1;
165 *argv[i] = user_sp;
166 let mut p = user_sp;
167 for c in args[i].as_bytes() {
168 *translated_refmut(new_token, p as *mut u8) = *c;
169 p += 1;
170 }
171 *translated_refmut(new_token, p as *mut u8) = 0;
172 }
173 user_sp -= user_sp % core::mem::size_of::<usize>();
175 let mut trap_cx = TrapContext::app_init_context(
177 entry_point,
178 user_sp,
179 KERNEL_SPACE.exclusive_access().token(),
180 task.kstack.get_top(),
181 trap_handler as usize,
182 );
183 trap_cx.x[10] = args.len();
184 trap_cx.x[11] = argv_base;
185 *task_inner.get_trap_cx() = trap_cx;
186 }
187
188 pub fn fork(self: &Arc<Self>) -> Arc<Self> {
190 let mut parent = self.inner_exclusive_access();
191 assert_eq!(parent.thread_count(), 1);
192 let memory_set = MemorySet::from_existed_user(&parent.memory_set);
194 let pid = pid_alloc();
196 let mut new_fd_table: Vec<Option<Arc<dyn File + Send + Sync>>> = Vec::new();
198 for fd in parent.fd_table.iter() {
199 if let Some(file) = fd {
200 new_fd_table.push(Some(file.clone()));
201 } else {
202 new_fd_table.push(None);
203 }
204 }
205 let child = Arc::new(Self {
207 pid,
208 inner: unsafe {
209 UPSafeCell::new(ProcessControlBlockInner {
210 is_zombie: false,
211 memory_set,
212 parent: Some(Arc::downgrade(self)),
213 children: Vec::new(),
214 exit_code: 0,
215 fd_table: new_fd_table,
216 signals: SignalFlags::empty(),
217 tasks: Vec::new(),
218 task_res_allocator: RecycleAllocator::new(),
219 mutex_list: Vec::new(),
220 semaphore_list: Vec::new(),
221 condvar_list: Vec::new(),
222 })
223 },
224 });
225 parent.children.push(Arc::clone(&child));
227 let task = Arc::new(TaskControlBlock::new(
229 Arc::clone(&child),
230 parent
231 .get_task(0)
232 .inner_exclusive_access()
233 .res
234 .as_ref()
235 .unwrap()
236 .ustack_base(),
237 false,
240 ));
241 let mut child_inner = child.inner_exclusive_access();
243 child_inner.tasks.push(Some(Arc::clone(&task)));
244 drop(child_inner);
245 let task_inner = task.inner_exclusive_access();
247 let trap_cx = task_inner.get_trap_cx();
248 trap_cx.kernel_sp = task.kstack.get_top();
249 drop(task_inner);
250 insert_into_pid2process(child.getpid(), Arc::clone(&child));
251 add_task(task);
253 child
254 }
255
256 pub fn getpid(&self) -> usize {
257 self.pid.0
258 }
259}