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