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