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