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 { 118 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失败的话,子线程不会执行。 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 // TODO: 注意!这里设置tty的操作不符合Linux的行为!(毕竟创建进程不一定要fork,也可以用clone来创建) 170 // 正确做法应该是在实现进程组之后去管理前台进程组。 171 pcb.sig_info_mut() 172 .set_tty(current_pcb.sig_info_irqsave().tty()); 173 174 let mut args = KernelCloneArgs::new(); 175 args.flags = clone_flags; 176 args.exit_signal = Signal::SIGCHLD; 177 Self::copy_process(¤t_pcb, &pcb, args, current_trapframe).map_err(|e| { 178 error!( 179 "fork: Failed to copy process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}", 180 current_pcb.pid(), 181 pcb.pid(), 182 e 183 ); 184 e 185 })?; 186 ProcessManager::add_pcb(pcb.clone()); 187 188 // 向procfs注册进程 189 procfs_register_pid(pcb.pid()).unwrap_or_else(|e| { 190 panic!( 191 "fork: Failed to register pid to procfs, pid: [{:?}]. Error: {:?}", 192 pcb.pid(), 193 e 194 ) 195 }); 196 197 pcb.sched_info().set_on_cpu(Some(smp_get_processor_id())); 198 199 ProcessManager::wakeup(&pcb).unwrap_or_else(|e| { 200 panic!( 201 "fork: Failed to wakeup new process, pid: [{:?}]. Error: {:?}", 202 pcb.pid(), 203 e 204 ) 205 }); 206 207 return Ok(pcb.pid()); 208 } 209 210 fn copy_flags( 211 clone_flags: &CloneFlags, 212 new_pcb: &Arc<ProcessControlBlock>, 213 ) -> Result<(), SystemError> { 214 if clone_flags.contains(CloneFlags::CLONE_VM) { 215 new_pcb.flags().insert(ProcessFlags::VFORK); 216 } 217 *new_pcb.flags.get_mut() = *ProcessManager::current_pcb().flags(); 218 return Ok(()); 219 } 220 221 /// 拷贝进程的地址空间 222 /// 223 /// ## 参数 224 /// 225 /// - `clone_vm`: 是否与父进程共享地址空间。true表示共享 226 /// - `new_pcb`: 新进程的pcb 227 /// 228 /// ## 返回值 229 /// 230 /// - 成功:返回Ok(()) 231 /// - 失败:返回Err(SystemError) 232 /// 233 /// ## Panic 234 /// 235 /// - 如果当前进程没有用户地址空间,则panic 236 #[inline(never)] 237 fn copy_mm( 238 clone_flags: &CloneFlags, 239 current_pcb: &Arc<ProcessControlBlock>, 240 new_pcb: &Arc<ProcessControlBlock>, 241 ) -> Result<(), SystemError> { 242 let old_address_space = current_pcb.basic().user_vm().unwrap_or_else(|| { 243 panic!( 244 "copy_mm: Failed to get address space of current process, current pid: [{:?}]", 245 current_pcb.pid() 246 ) 247 }); 248 249 if clone_flags.contains(CloneFlags::CLONE_VM) { 250 unsafe { new_pcb.basic_mut().set_user_vm(Some(old_address_space)) }; 251 return Ok(()); 252 } 253 let new_address_space = old_address_space.write_irqsave().try_clone().unwrap_or_else(|e| { 254 panic!( 255 "copy_mm: Failed to clone address space of current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}", 256 current_pcb.pid(), new_pcb.pid(), e 257 ) 258 }); 259 unsafe { new_pcb.basic_mut().set_user_vm(Some(new_address_space)) }; 260 return Ok(()); 261 } 262 263 #[inline(never)] 264 fn copy_files( 265 clone_flags: &CloneFlags, 266 current_pcb: &Arc<ProcessControlBlock>, 267 new_pcb: &Arc<ProcessControlBlock>, 268 ) -> Result<(), SystemError> { 269 // 如果不共享文件描述符表,则拷贝文件描述符表 270 if !clone_flags.contains(CloneFlags::CLONE_FILES) { 271 let new_fd_table = current_pcb.basic().fd_table().unwrap().read().clone(); 272 let new_fd_table = Arc::new(RwLock::new(new_fd_table)); 273 new_pcb.basic_mut().set_fd_table(Some(new_fd_table)); 274 } else { 275 // 如果共享文件描述符表,则直接拷贝指针 276 new_pcb 277 .basic_mut() 278 .set_fd_table(current_pcb.basic().fd_table().clone()); 279 } 280 281 return Ok(()); 282 } 283 284 #[allow(dead_code)] 285 fn copy_sighand( 286 clone_flags: &CloneFlags, 287 current_pcb: &Arc<ProcessControlBlock>, 288 new_pcb: &Arc<ProcessControlBlock>, 289 ) -> Result<(), SystemError> { 290 // // 将信号的处理函数设置为default(除了那些被手动屏蔽的) 291 if clone_flags.contains(CloneFlags::CLONE_CLEAR_SIGHAND) { 292 flush_signal_handlers(new_pcb.clone(), false); 293 } 294 295 if clone_flags.contains(CloneFlags::CLONE_SIGHAND) { 296 new_pcb.sig_struct_irqsave().handlers = current_pcb.sig_struct_irqsave().handlers; 297 } 298 return Ok(()); 299 } 300 301 /// 拷贝进程信息 302 /// 303 /// ## panic: 304 /// 某一步拷贝失败时会引发panic 305 /// 例如:copy_mm等失败时会触发panic 306 /// 307 /// ## 参数 308 /// 309 /// - clone_flags 标志位 310 /// - current_pcb 拷贝源pcb 311 /// - pcb 目标pcb 312 /// 313 /// ## return 314 /// - 发生错误时返回Err(SystemError) 315 #[inline(never)] 316 pub fn copy_process( 317 current_pcb: &Arc<ProcessControlBlock>, 318 pcb: &Arc<ProcessControlBlock>, 319 clone_args: KernelCloneArgs, 320 current_trapframe: &TrapFrame, 321 ) -> Result<(), SystemError> { 322 let clone_flags = clone_args.flags; 323 // 不允许与不同namespace的进程共享根目录 324 if (clone_flags == (CloneFlags::CLONE_NEWNS | CloneFlags::CLONE_FS)) 325 || clone_flags == (CloneFlags::CLONE_NEWUSER | CloneFlags::CLONE_FS) 326 { 327 return Err(SystemError::EINVAL); 328 } 329 330 // 线程组必须共享信号,分离线程只能在线程组内启动。 331 if clone_flags.contains(CloneFlags::CLONE_THREAD) 332 && !clone_flags.contains(CloneFlags::CLONE_SIGHAND) 333 { 334 return Err(SystemError::EINVAL); 335 } 336 337 // 共享信号处理器意味着共享vm。 338 // 线程组也意味着共享vm。阻止这种情况可以简化其他代码。 339 if clone_flags.contains(CloneFlags::CLONE_SIGHAND) 340 && !clone_flags.contains(CloneFlags::CLONE_VM) 341 { 342 return Err(SystemError::EINVAL); 343 } 344 345 // TODO: 处理CLONE_PARENT 与 SIGNAL_UNKILLABLE的情况 346 347 // 如果新进程使用不同的 pid 或 namespace, 348 // 则不允许它与分叉任务共享线程组。 349 if clone_flags.contains(CloneFlags::CLONE_THREAD) 350 && clone_flags.contains(CloneFlags::CLONE_NEWUSER | CloneFlags::CLONE_NEWPID) 351 { 352 return Err(SystemError::EINVAL); 353 // TODO: 判断新进程与当前进程namespace是否相同,不同则返回错误 354 } 355 356 // 如果新进程将处于不同的time namespace, 357 // 则不能让它共享vm或线程组。 358 if clone_flags.contains(CloneFlags::CLONE_THREAD | CloneFlags::CLONE_VM) { 359 // TODO: 判断time namespace,不同则返回错误 360 } 361 362 if clone_flags.contains(CloneFlags::CLONE_PIDFD) 363 && clone_flags.contains(CloneFlags::CLONE_DETACHED | CloneFlags::CLONE_THREAD) 364 { 365 return Err(SystemError::EINVAL); 366 } 367 368 // TODO: 克隆前应该锁信号处理,等待克隆完成后再处理 369 370 // 克隆架构相关 371 let guard = current_pcb.arch_info_irqsave(); 372 unsafe { pcb.arch_info().clone_from(&guard) }; 373 drop(guard); 374 375 // 为内核线程设置WorkerPrivate 376 if current_pcb.flags().contains(ProcessFlags::KTHREAD) { 377 *pcb.worker_private() = 378 Some(WorkerPrivate::KernelThread(KernelThreadPcbPrivate::new())); 379 } 380 381 // 设置clear_child_tid,在线程结束时将其置0以通知父进程 382 if clone_flags.contains(CloneFlags::CLONE_CHILD_CLEARTID) { 383 pcb.thread.write_irqsave().clear_child_tid = Some(clone_args.child_tid); 384 } 385 386 // 设置child_tid,意味着子线程能够知道自己的id 387 if clone_flags.contains(CloneFlags::CLONE_CHILD_SETTID) { 388 pcb.thread.write_irqsave().set_child_tid = Some(clone_args.child_tid); 389 } 390 391 // 将子进程/线程的id存储在用户态传进的地址中 392 if clone_flags.contains(CloneFlags::CLONE_PARENT_SETTID) { 393 let mut writer = UserBufferWriter::new( 394 clone_args.parent_tid.data() as *mut i32, 395 core::mem::size_of::<i32>(), 396 true, 397 )?; 398 399 writer.copy_one_to_user(&(pcb.pid().0 as i32), 0)?; 400 } 401 402 sched_fork(pcb).unwrap_or_else(|e| { 403 panic!( 404 "fork: Failed to set sched info from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}", 405 current_pcb.pid(), pcb.pid(), e 406 ) 407 }); 408 409 // 拷贝标志位 410 Self::copy_flags(&clone_flags, pcb).unwrap_or_else(|e| { 411 panic!( 412 "fork: Failed to copy flags from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}", 413 current_pcb.pid(), pcb.pid(), e 414 ) 415 }); 416 417 // 拷贝用户地址空间 418 Self::copy_mm(&clone_flags, current_pcb, pcb).unwrap_or_else(|e| { 419 panic!( 420 "fork: Failed to copy mm from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}", 421 current_pcb.pid(), pcb.pid(), e 422 ) 423 }); 424 425 // 拷贝文件描述符表 426 Self::copy_files(&clone_flags, current_pcb, pcb).unwrap_or_else(|e| { 427 panic!( 428 "fork: Failed to copy files from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}", 429 current_pcb.pid(), pcb.pid(), e 430 ) 431 }); 432 433 // 拷贝信号相关数据 434 Self::copy_sighand(&clone_flags, current_pcb, pcb).unwrap_or_else(|e| { 435 panic!( 436 "fork: Failed to copy sighand from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}", 437 current_pcb.pid(), pcb.pid(), e 438 ) 439 }); 440 441 // 拷贝线程 442 Self::copy_thread(current_pcb, pcb, clone_args,current_trapframe).unwrap_or_else(|e| { 443 panic!( 444 "fork: Failed to copy thread from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}", 445 current_pcb.pid(), pcb.pid(), e 446 ) 447 }); 448 449 // 设置线程组id、组长 450 if clone_flags.contains(CloneFlags::CLONE_THREAD) { 451 pcb.thread.write_irqsave().group_leader = 452 current_pcb.thread.read_irqsave().group_leader.clone(); 453 unsafe { 454 let ptr = pcb.as_ref() as *const ProcessControlBlock as *mut ProcessControlBlock; 455 (*ptr).tgid = current_pcb.tgid; 456 } 457 } else { 458 pcb.thread.write_irqsave().group_leader = Arc::downgrade(pcb); 459 unsafe { 460 let ptr = pcb.as_ref() as *const ProcessControlBlock as *mut ProcessControlBlock; 461 (*ptr).tgid = pcb.tgid; 462 } 463 } 464 465 // CLONE_PARENT re-uses the old parent 466 if clone_flags.contains(CloneFlags::CLONE_PARENT | CloneFlags::CLONE_THREAD) { 467 *pcb.real_parent_pcb.write_irqsave() = 468 current_pcb.real_parent_pcb.read_irqsave().clone(); 469 470 if clone_flags.contains(CloneFlags::CLONE_THREAD) { 471 pcb.exit_signal.store(Signal::INVALID, Ordering::SeqCst); 472 } else { 473 let leader = current_pcb.thread.read_irqsave().group_leader(); 474 if unlikely(leader.is_none()) { 475 panic!( 476 "fork: Failed to get leader of current process, current pid: [{:?}]", 477 current_pcb.pid() 478 ); 479 } 480 481 pcb.exit_signal.store( 482 leader.unwrap().exit_signal.load(Ordering::SeqCst), 483 Ordering::SeqCst, 484 ); 485 } 486 } else { 487 // 新创建的进程,设置其父进程为当前进程 488 *pcb.real_parent_pcb.write_irqsave() = Arc::downgrade(current_pcb); 489 pcb.exit_signal 490 .store(clone_args.exit_signal, Ordering::SeqCst); 491 } 492 493 // todo: 增加线程组相关的逻辑。 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/fork.c#2437 494 495 sched_cgroup_fork(pcb); 496 497 Ok(()) 498 } 499 } 500