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