xref: /DragonOS/kernel/src/process/fork.rs (revision 971462be94ba0a5c74af7a5f9653dfabd4932a63)
1 use alloc::{string::ToString, sync::Arc};
2 
3 use crate::{
4     arch::interrupt::TrapFrame,
5     filesystem::procfs::procfs_register_pid,
6     ipc::signal::flush_signal_handlers,
7     libs::rwlock::RwLock,
8     mm::VirtAddr,
9     process::ProcessFlags,
10     syscall::{user_access::UserBufferWriter, SystemError},
11 };
12 
13 use super::{
14     kthread::{KernelThreadPcbPrivate, WorkerPrivate},
15     KernelStack, Pid, ProcessControlBlock, ProcessManager,
16 };
17 
18 bitflags! {
19     /// 进程克隆标志
20     pub struct CloneFlags: u64 {
21         /// 在进程间共享虚拟内存空间
22         const CLONE_VM = 0x00000100;
23         /// 在进程间共享文件系统信息
24         const CLONE_FS = 0x00000200;
25         /// 共享打开的文件
26         const CLONE_FILES = 0x00000400;
27         /// 克隆时,与父进程共享信号处理结构体
28         const CLONE_SIGHAND = 0x00000800;
29         /// 返回进程的文件描述符
30         const CLONE_PIDFD = 0x00001000;
31         /// 使克隆对象成为父进程的跟踪对象
32         const CLONE_PTRACE = 0x00002000;
33         /// 在执行 exec() 或 _exit() 之前挂起父进程的执行
34         const CLONE_VFORK = 0x00004000;
35         /// 使克隆对象的父进程为调用进程的父进程
36         const CLONE_PARENT = 0x00008000;
37         /// 拷贝线程
38         const CLONE_THREAD = 0x00010000;
39         /// 创建一个新的命名空间,其中包含独立的文件系统挂载点层次结构。
40         const CLONE_NEWNS =	0x00020000;
41         /// 与父进程共享 System V 信号量。
42         const CLONE_SYSVSEM = 0x00040000;
43         /// 设置其线程本地存储
44         const CLONE_SETTLS = 0x00080000;
45         /// 设置partent_tid地址为子进程线程 ID
46         const CLONE_PARENT_SETTID = 0x00100000;
47         /// 在子进程中设置一个清除线程 ID 的用户空间地址
48         const CLONE_CHILD_CLEARTID = 0x00200000;
49         /// 创建一个新线程,将其设置为分离状态
50         const CLONE_DETACHED = 0x00400000;
51         /// 使其在创建者进程或线程视角下成为无法跟踪的。
52         const CLONE_UNTRACED = 0x00800000;
53         /// 设置其子进程线程 ID
54         const CLONE_CHILD_SETTID = 0x01000000;
55         /// 将其放置在一个新的 cgroup 命名空间中
56         const CLONE_NEWCGROUP = 0x02000000;
57         /// 将其放置在一个新的 UTS 命名空间中
58         const CLONE_NEWUTS = 0x04000000;
59         /// 将其放置在一个新的 IPC 命名空间中
60         const CLONE_NEWIPC = 0x08000000;
61         /// 将其放置在一个新的用户命名空间中
62         const CLONE_NEWUSER = 0x10000000;
63         /// 将其放置在一个新的 PID 命名空间中
64         const CLONE_NEWPID = 0x20000000;
65         /// 将其放置在一个新的网络命名空间中
66         const CLONE_NEWNET = 0x40000000;
67         /// 在新的 I/O 上下文中运行它
68         const CLONE_IO = 0x80000000;
69         /// 克隆时,与父进程共享信号结构体
70         const CLONE_SIGNAL = 0x00010000 | 0x00000800;
71         /// 克隆时,将原本被设置为SIG_IGNORE的信号,设置回SIG_DEFAULT
72         const CLONE_CLEAR_SIGHAND = 0x100000000;
73     }
74 }
75 
76 /// ## clone与clone3系统调用的参数载体
77 ///
78 /// 因为这两个系统调用的参数很多,所以有这样一个载体更灵活
79 ///
80 /// 仅仅作为参数传递
81 #[derive(Debug, Clone, Copy)]
82 pub struct KernelCloneArgs {
83     pub flags: CloneFlags,
84 
85     // 下列属性均来自用户空间
86     pub pidfd: VirtAddr,
87     pub child_tid: VirtAddr,
88     pub parent_tid: VirtAddr,
89     pub set_tid: VirtAddr,
90 
91     pub exit_signal: i32,
92 
93     pub stack: usize,
94     // clone3用到
95     pub stack_size: usize,
96     pub tls: usize,
97 
98     pub set_tid_size: usize,
99     pub cgroup: i32,
100 
101     pub io_thread: bool,
102     pub kthread: bool,
103     pub idle: bool,
104     pub func: VirtAddr,
105     pub fn_arg: VirtAddr,
106     // cgrp 和 cset?
107 }
108 
109 impl KernelCloneArgs {
110     pub fn new() -> Self {
111         let null_addr = VirtAddr::new(0);
112         Self {
113             flags: unsafe { CloneFlags::from_bits_unchecked(0) },
114             pidfd: null_addr,
115             child_tid: null_addr,
116             parent_tid: null_addr,
117             set_tid: null_addr,
118             exit_signal: 0,
119             stack: 0,
120             stack_size: 0,
121             tls: 0,
122             set_tid_size: 0,
123             cgroup: 0,
124             io_thread: false,
125             kthread: false,
126             idle: false,
127             func: null_addr,
128             fn_arg: null_addr,
129         }
130     }
131 }
132 
133 impl ProcessManager {
134     /// 创建一个新进程
135     ///
136     /// ## 参数
137     ///
138     /// - `current_trapframe`: 当前进程的trapframe
139     /// - `clone_flags`: 进程克隆标志
140     ///
141     /// ## 返回值
142     ///
143     /// - 成功:返回新进程的pid
144     /// - 失败:返回Err(SystemError),fork失败的话,子线程不会执行。
145     ///
146     /// ## Safety
147     ///
148     /// - fork失败的话,子线程不会执行。
149     pub fn fork(
150         current_trapframe: &mut TrapFrame,
151         clone_flags: CloneFlags,
152     ) -> Result<Pid, SystemError> {
153         let current_pcb = ProcessManager::current_pcb();
154         let new_kstack = KernelStack::new()?;
155         let name = current_pcb.basic().name().to_string();
156         let pcb = ProcessControlBlock::new(name, new_kstack);
157 
158         let mut args = KernelCloneArgs::new();
159         args.flags = clone_flags;
160         Self::copy_process(&current_pcb, &pcb, args, current_trapframe)?;
161 
162         ProcessManager::add_pcb(pcb.clone());
163 
164         // 向procfs注册进程
165         procfs_register_pid(pcb.pid()).unwrap_or_else(|e| {
166             panic!(
167                 "fork: Failed to register pid to procfs, pid: [{:?}]. Error: {:?}",
168                 pcb.pid(),
169                 e
170             )
171         });
172 
173         ProcessManager::wakeup(&pcb).unwrap_or_else(|e| {
174             panic!(
175                 "fork: Failed to wakeup new process, pid: [{:?}]. Error: {:?}",
176                 pcb.pid(),
177                 e
178             )
179         });
180 
181         return Ok(pcb.pid());
182     }
183 
184     fn copy_flags(
185         clone_flags: &CloneFlags,
186         new_pcb: &Arc<ProcessControlBlock>,
187     ) -> Result<(), SystemError> {
188         if clone_flags.contains(CloneFlags::CLONE_VM) {
189             new_pcb.flags().insert(ProcessFlags::VFORK);
190         }
191         *new_pcb.flags.lock() = ProcessManager::current_pcb().flags().clone();
192         return Ok(());
193     }
194 
195     /// 拷贝进程的地址空间
196     ///
197     /// ## 参数
198     ///
199     /// - `clone_vm`: 是否与父进程共享地址空间。true表示共享
200     /// - `new_pcb`: 新进程的pcb
201     ///
202     /// ## 返回值
203     ///
204     /// - 成功:返回Ok(())
205     /// - 失败:返回Err(SystemError)
206     ///
207     /// ## Panic
208     ///
209     /// - 如果当前进程没有用户地址空间,则panic
210     fn copy_mm(
211         clone_flags: &CloneFlags,
212         current_pcb: &Arc<ProcessControlBlock>,
213         new_pcb: &Arc<ProcessControlBlock>,
214     ) -> Result<(), SystemError> {
215         let old_address_space = current_pcb.basic().user_vm().unwrap_or_else(|| {
216             panic!(
217                 "copy_mm: Failed to get address space of current process, current pid: [{:?}]",
218                 current_pcb.pid()
219             )
220         });
221 
222         if clone_flags.contains(CloneFlags::CLONE_VM) {
223             unsafe { new_pcb.basic_mut().set_user_vm(Some(old_address_space)) };
224             return Ok(());
225         }
226         let new_address_space = old_address_space.write().try_clone().unwrap_or_else(|e| {
227             panic!(
228                 "copy_mm: Failed to clone address space of current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
229                 current_pcb.pid(), new_pcb.pid(), e
230             )
231         });
232         unsafe { new_pcb.basic_mut().set_user_vm(Some(new_address_space)) };
233         return Ok(());
234     }
235 
236     fn copy_files(
237         clone_flags: &CloneFlags,
238         current_pcb: &Arc<ProcessControlBlock>,
239         new_pcb: &Arc<ProcessControlBlock>,
240     ) -> Result<(), SystemError> {
241         // 如果不共享文件描述符表,则拷贝文件描述符表
242         if !clone_flags.contains(CloneFlags::CLONE_FILES) {
243             let new_fd_table = current_pcb.basic().fd_table().unwrap().read().clone();
244             let new_fd_table = Arc::new(RwLock::new(new_fd_table));
245             new_pcb.basic_mut().set_fd_table(Some(new_fd_table));
246         } else {
247             // 如果共享文件描述符表,则直接拷贝指针
248             new_pcb
249                 .basic_mut()
250                 .set_fd_table(current_pcb.basic().fd_table().clone());
251         }
252 
253         return Ok(());
254     }
255 
256     #[allow(dead_code)]
257     fn copy_sighand(
258         clone_flags: &CloneFlags,
259         current_pcb: &Arc<ProcessControlBlock>,
260         new_pcb: &Arc<ProcessControlBlock>,
261     ) -> Result<(), SystemError> {
262         // // 将信号的处理函数设置为default(除了那些被手动屏蔽的)
263         if clone_flags.contains(CloneFlags::CLONE_CLEAR_SIGHAND) {
264             flush_signal_handlers(new_pcb.clone(), false);
265         }
266 
267         if clone_flags.contains(CloneFlags::CLONE_SIGHAND) {
268             (*new_pcb.sig_struct()).handlers = current_pcb.sig_struct().handlers.clone();
269         }
270         return Ok(());
271     }
272 
273     /// 拷贝进程信息
274     ///
275     /// ## panic:
276     /// 某一步拷贝失败时会引发panic
277     /// 例如:copy_mm等失败时会触发panic
278     ///
279     /// ## 参数
280     ///
281     /// - clone_flags 标志位
282     /// - des_pcb 目标pcb
283     /// - src_pcb 拷贝源pcb
284     ///
285     /// ## return
286     /// - 发生错误时返回Err(SystemError)
287     pub fn copy_process(
288         current_pcb: &Arc<ProcessControlBlock>,
289         pcb: &Arc<ProcessControlBlock>,
290         clone_args: KernelCloneArgs,
291         current_trapframe: &mut TrapFrame,
292     ) -> Result<(), SystemError> {
293         let clone_flags = clone_args.flags;
294         // 不允许与不同namespace的进程共享根目录
295         if (clone_flags == (CloneFlags::CLONE_NEWNS | CloneFlags::CLONE_FS))
296             || clone_flags == (CloneFlags::CLONE_NEWUSER | CloneFlags::CLONE_FS)
297         {
298             return Err(SystemError::EINVAL);
299         }
300 
301         // 线程组必须共享信号,分离线程只能在线程组内启动。
302         if clone_flags.contains(CloneFlags::CLONE_THREAD)
303             && !clone_flags.contains(CloneFlags::CLONE_SIGHAND)
304         {
305             return Err(SystemError::EINVAL);
306         }
307 
308         // 共享信号处理器意味着共享vm。
309         // 线程组也意味着共享vm。阻止这种情况可以简化其他代码。
310         if clone_flags.contains(CloneFlags::CLONE_SIGHAND)
311             && !clone_flags.contains(CloneFlags::CLONE_VM)
312         {
313             return Err(SystemError::EINVAL);
314         }
315 
316         // TODO: 处理CLONE_PARENT 与 SIGNAL_UNKILLABLE的情况
317 
318         // 如果新进程使用不同的 pid 或 namespace,
319         // 则不允许它与分叉任务共享线程组。
320         if clone_flags.contains(CloneFlags::CLONE_THREAD) {
321             if clone_flags.contains(CloneFlags::CLONE_NEWUSER | CloneFlags::CLONE_NEWPID) {
322                 return Err(SystemError::EINVAL);
323             }
324             // TODO: 判断新进程与当前进程namespace是否相同,不同则返回错误
325         }
326 
327         // 如果新进程将处于不同的time namespace,
328         // 则不能让它共享vm或线程组。
329         if clone_flags.contains(CloneFlags::CLONE_THREAD | CloneFlags::CLONE_VM) {
330             // TODO: 判断time namespace,不同则返回错误
331         }
332 
333         if clone_flags.contains(CloneFlags::CLONE_PIDFD)
334             && clone_flags.contains(CloneFlags::CLONE_DETACHED | CloneFlags::CLONE_THREAD)
335         {
336             return Err(SystemError::EINVAL);
337         }
338 
339         // TODO: 克隆前应该锁信号处理,等待克隆完成后再处理
340 
341         // 克隆架构相关
342         *pcb.arch_info() = current_pcb.arch_info_irqsave().clone();
343 
344         // 为内核线程设置WorkerPrivate
345         if current_pcb.flags().contains(ProcessFlags::KTHREAD) {
346             *pcb.worker_private() =
347                 Some(WorkerPrivate::KernelThread(KernelThreadPcbPrivate::new()));
348         }
349 
350         // 设置clear_child_tid,在线程结束时将其置0以通知父进程
351         if clone_flags.contains(CloneFlags::CLONE_CHILD_CLEARTID) {
352             pcb.thread.write().clear_child_tid = Some(clone_args.child_tid);
353         }
354 
355         // 设置child_tid,意味着子线程能够知道自己的id
356         if clone_flags.contains(CloneFlags::CLONE_CHILD_SETTID) {
357             pcb.thread.write().set_child_tid = Some(clone_args.child_tid);
358         }
359 
360         // 将子进程/线程的id存储在用户态传进的地址中
361         if clone_flags.contains(CloneFlags::CLONE_PARENT_SETTID) {
362             let mut writer = UserBufferWriter::new(
363                 clone_args.parent_tid.data() as *mut i32,
364                 core::mem::size_of::<i32>(),
365                 true,
366             )?;
367 
368             writer.copy_one_to_user(&(pcb.pid().0 as i32), 0)?;
369         }
370 
371         // 拷贝标志位
372         Self::copy_flags(&clone_flags, &pcb).unwrap_or_else(|e| {
373             panic!(
374                 "fork: Failed to copy flags from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
375                 current_pcb.pid(), pcb.pid(), e
376             )
377         });
378 
379         // 拷贝用户地址空间
380         Self::copy_mm(&clone_flags, &current_pcb, &pcb).unwrap_or_else(|e| {
381             panic!(
382                 "fork: Failed to copy mm from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
383                 current_pcb.pid(), pcb.pid(), e
384             )
385         });
386 
387         // 拷贝文件描述符表
388         Self::copy_files(&clone_flags, &current_pcb, &pcb).unwrap_or_else(|e| {
389             panic!(
390                 "fork: Failed to copy files from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
391                 current_pcb.pid(), pcb.pid(), e
392             )
393         });
394 
395         // todo: 拷贝信号相关数据
396 
397         // 拷贝线程
398         Self::copy_thread(&current_pcb, &pcb, clone_args,&current_trapframe).unwrap_or_else(|e| {
399             panic!(
400                 "fork: Failed to copy thread from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
401                 current_pcb.pid(), pcb.pid(), e
402             )
403         });
404 
405         Ok(())
406     }
407 }
408