xref: /DragonOS/kernel/src/process/syscall.rs (revision a03c4f9dee5705207325c56629c0ccd219168f10)
1 use core::ffi::c_void;
2 
3 use alloc::{string::String, vec::Vec};
4 
5 use super::{abi::WaitOption, fork::CloneFlags, Pid, ProcessManager, ProcessState};
6 use crate::{
7     arch::{interrupt::TrapFrame, sched::sched, CurrentIrqArch},
8     exception::InterruptArch,
9     filesystem::vfs::MAX_PATHLEN,
10     process::ProcessControlBlock,
11     syscall::{
12         user_access::{
13             check_and_clone_cstr, check_and_clone_cstr_array, UserBufferReader, UserBufferWriter,
14         },
15         Syscall, SystemError,
16     },
17 };
18 
19 impl Syscall {
20     pub fn fork(frame: &mut TrapFrame) -> Result<usize, SystemError> {
21         let r = ProcessManager::fork(frame, CloneFlags::empty()).map(|pid| pid.into());
22         return r;
23     }
24 
25     pub fn vfork(frame: &mut TrapFrame) -> Result<usize, SystemError> {
26         ProcessManager::fork(
27             frame,
28             CloneFlags::CLONE_VM | CloneFlags::CLONE_FS | CloneFlags::CLONE_SIGNAL,
29         )
30         .map(|pid| pid.into())
31     }
32 
33     pub fn execve(
34         path: *const u8,
35         argv: *const *const u8,
36         envp: *const *const u8,
37         frame: &mut TrapFrame,
38     ) -> Result<(), SystemError> {
39         // kdebug!(
40         //     "execve path: {:?}, argv: {:?}, envp: {:?}\n",
41         //     path,
42         //     argv,
43         //     envp
44         // );
45         if path.is_null() {
46             return Err(SystemError::EINVAL);
47         }
48 
49         let x = || {
50             let path: String = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
51             let argv: Vec<String> = check_and_clone_cstr_array(argv)?;
52             let envp: Vec<String> = check_and_clone_cstr_array(envp)?;
53             Ok((path, argv, envp))
54         };
55         let r: Result<(String, Vec<String>, Vec<String>), SystemError> = x();
56         if let Err(e) = r {
57             panic!("Failed to execve: {:?}", e);
58         }
59         let (path, argv, envp) = r.unwrap();
60         ProcessManager::current_pcb()
61             .basic_mut()
62             .set_name(ProcessControlBlock::generate_name(&path, &argv));
63 
64         Self::do_execve(path, argv, envp, frame)?;
65 
66         // 关闭设置了O_CLOEXEC的文件描述符
67         let fd_table = ProcessManager::current_pcb().fd_table();
68         fd_table.write().close_on_exec();
69 
70         return Ok(());
71     }
72 
73     pub fn wait4(
74         pid: i64,
75         wstatus: *mut i32,
76         options: i32,
77         rusage: *mut c_void,
78     ) -> Result<usize, SystemError> {
79         let ret = WaitOption::from_bits(options as u32);
80         let options = match ret {
81             Some(options) => options,
82             None => {
83                 return Err(SystemError::EINVAL);
84             }
85         };
86 
87         let mut _rusage_buf =
88             UserBufferReader::new::<c_void>(rusage, core::mem::size_of::<c_void>(), true)?;
89 
90         let mut wstatus_buf =
91             UserBufferWriter::new::<i32>(wstatus, core::mem::size_of::<i32>(), true)?;
92 
93         let cur_pcb = ProcessManager::current_pcb();
94         let rd_childen = cur_pcb.children.read();
95 
96         if pid > 0 {
97             let pid = Pid(pid as usize);
98             let child_pcb = rd_childen.get(&pid).ok_or(SystemError::ECHILD)?.clone();
99             drop(rd_childen);
100 
101             loop {
102                 // 获取退出码
103                 match child_pcb.sched_info().state() {
104                     ProcessState::Runnable => {
105                         if options.contains(WaitOption::WNOHANG)
106                             || options.contains(WaitOption::WNOWAIT)
107                         {
108                             if !wstatus.is_null() {
109                                 wstatus_buf.copy_one_to_user(&WaitOption::WCONTINUED.bits(), 0)?;
110                             }
111                             return Ok(0);
112                         }
113                     }
114                     ProcessState::Blocked(_) => {
115                         // 指定WUNTRACED则等待暂停的进程,不指定则返回0
116                         if !options.contains(WaitOption::WUNTRACED)
117                             || options.contains(WaitOption::WNOWAIT)
118                         {
119                             if !wstatus.is_null() {
120                                 wstatus_buf.copy_one_to_user(&WaitOption::WSTOPPED.bits(), 0)?;
121                             }
122                             return Ok(0);
123                         }
124                     }
125                     ProcessState::Exited(status) => {
126                         if !wstatus.is_null() {
127                             wstatus_buf.copy_one_to_user(
128                                 &(status | WaitOption::WEXITED.bits() as usize),
129                                 0,
130                             )?;
131                         }
132                         return Ok(pid.into());
133                     }
134                 };
135 
136                 // 等待指定进程
137                 child_pcb.wait_queue.sleep();
138             }
139         } else if pid < -1 {
140             // TODO 判断是否pgid == -pid(等待指定组任意进程)
141             // 暂时不支持
142             return Err(SystemError::EINVAL);
143         } else if pid == 0 {
144             // TODO 判断是否pgid == current_pgid(等待当前组任意进程)
145             // 暂时不支持
146             return Err(SystemError::EINVAL);
147         } else {
148             // 等待任意子进程(这两)
149             let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
150             for (pid, pcb) in rd_childen.iter() {
151                 if pcb.sched_info().state().is_exited() {
152                     if !wstatus.is_null() {
153                         wstatus_buf.copy_one_to_user(&0, 0)?;
154                     }
155                     return Ok(pid.clone().into());
156                 } else {
157                     unsafe { pcb.wait_queue.sleep_without_schedule() };
158                 }
159             }
160             drop(irq_guard);
161             sched();
162         }
163 
164         return Ok(0);
165     }
166 
167     /// # 退出进程
168     ///
169     /// ## 参数
170     ///
171     /// - status: 退出状态
172     pub fn exit(status: usize) -> ! {
173         ProcessManager::exit(status);
174     }
175 
176     /// @brief 获取当前进程的pid
177     pub fn getpid() -> Result<Pid, SystemError> {
178         let current_pcb = ProcessManager::current_pcb();
179         return Ok(current_pcb.pid());
180     }
181 
182     /// @brief 获取指定进程的pgid
183     ///
184     /// @param pid 指定一个进程号
185     ///
186     /// @return 成功,指定进程的进程组id
187     /// @return 错误,不存在该进程
188     pub fn getpgid(mut pid: Pid) -> Result<Pid, SystemError> {
189         if pid == Pid(0) {
190             let current_pcb = ProcessManager::current_pcb();
191             pid = current_pcb.pid();
192         }
193         let target_proc = ProcessManager::find(pid).ok_or(SystemError::ESRCH)?;
194         return Ok(target_proc.basic().pgid());
195     }
196     /// @brief 获取当前进程的父进程id
197 
198     /// 若为initproc则ppid设置为0
199     pub fn getppid() -> Result<Pid, SystemError> {
200         let current_pcb = ProcessManager::current_pcb();
201         return Ok(current_pcb.basic().ppid());
202     }
203 }
204