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