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(¤t_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