diff --git a/kernel/src/device/tty/mod.rs b/kernel/src/device/tty/mod.rs index c982faa9c..200e16042 100644 --- a/kernel/src/device/tty/mod.rs +++ b/kernel/src/device/tty/mod.rs @@ -15,7 +15,7 @@ use crate::{ prelude::*, process::{ signal::{signals::kernel::KernelSignal, PollHandle, Pollable}, - JobControl, Process, Terminal, + JobControl, Terminal, }, }; @@ -211,21 +211,3 @@ pub fn new_job_control_and_ldisc() -> (Arc, Arc) { pub fn get_n_tty() -> &'static Arc { N_TTY.get().unwrap() } - -/// Open `N_TTY` as the controlling terminal for the process. This method should -/// only be called when creating the init process. -pub fn open_ntty_as_controlling_terminal(process: &Process) -> Result<()> { - let tty = get_n_tty(); - - let session = &process.session().unwrap(); - let process_group = process.process_group().unwrap(); - - session.set_terminal(|| { - tty.job_control.set_session(session); - Ok(tty.clone()) - })?; - - tty.job_control.set_foreground(Some(&process_group))?; - - Ok(()) -} diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 0608ff20d..a202944fb 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -35,7 +35,7 @@ use ostd::{ boot::boot_info, cpu::{CpuId, CpuSet, PinCurrentCpu}, }; -use process::Process; +use process::{spawn_init_process, Process}; use sched::SchedPolicy; use crate::{prelude::*, thread::kernel_thread::ThreadOptions}; @@ -151,7 +151,7 @@ fn init_thread() { let karg: KCmdlineArg = boot_info().kernel_cmdline.as_str().into(); - let initproc = Process::spawn_user_process( + let initproc = spawn_init_process( karg.get_initproc_path().unwrap(), karg.get_initproc_argv().to_vec(), karg.get_initproc_envp().to_vec(), diff --git a/kernel/src/process/clone.rs b/kernel/src/process/clone.rs index 3facb9ddd..f4f4c4e2c 100644 --- a/kernel/src/process/clone.rs +++ b/kernel/src/process/clone.rs @@ -8,8 +8,9 @@ use super::{ posix_thread::{AsPosixThread, PosixThreadBuilder, ThreadName}, process_table, process_vm::ProcessVm, + rlimit::ResourceLimits, signal::{constants::SIGCHLD, sig_disposition::SigDispositions, sig_num::SigNum}, - Credentials, Process, ProcessBuilder, + Credentials, Pid, Process, }; use crate::{ cpu::LinuxAbi, @@ -17,6 +18,7 @@ use crate::{ fs::{file_table::FileTable, thread_info::ThreadFsInfo}, prelude::*, process::posix_thread::allocate_posix_tid, + sched::Nice, thread::{AsThread, Tid}, }; @@ -299,13 +301,13 @@ fn clone_child_process( let clone_flags = clone_args.flags; - // clone vm + // Clone the virtual memory space let child_process_vm = { let parent_process_vm = process.vm(); clone_vm(parent_process_vm, clone_flags)? }; - // clone user space + // Clone the user context let child_user_ctx = Arc::new(clone_user_ctx( parent_context, clone_args.stack, @@ -314,22 +316,25 @@ fn clone_child_process( clone_flags, )); - // clone file table + // Clone the file table let child_file_table = clone_files(thread_local.borrow_file_table().unwrap(), clone_flags); - // clone fs + // Clone the filesystem information let child_fs = clone_fs(posix_thread.fs(), clone_flags); - // clone sig dispositions + // Clone signal dispositions let child_sig_dispositions = clone_sighand(process.sig_dispositions(), clone_flags); - // clone system V semaphore + // Clone System V semaphore clone_sysvsem(clone_flags)?; - // inherit parent's sig mask + // Inherit the parent's signal mask let child_sig_mask = posix_thread.sig_mask().load(Ordering::Relaxed).into(); - // inherit parent's nice value + // Inherit the parent's resource limits + let child_resource_limits = process.resource_limits().clone(); + + // Inherit the parent's nice value let child_nice = process.nice().load(Ordering::Relaxed); let child_tid = allocate_posix_tid(); @@ -358,16 +363,16 @@ fn clone_child_process( child_thread_builder = clone_child_settid(child_thread_builder, clone_args.child_tid, clone_flags); - let mut process_builder = - ProcessBuilder::new(child_tid, &child_elf_path, posix_thread.weak_process()); - - process_builder - .main_thread_builder(child_thread_builder) - .process_vm(child_process_vm) - .sig_dispositions(child_sig_dispositions) - .nice(child_nice); - - process_builder.build()? + create_child_process( + child_tid, + posix_thread.weak_process(), + &child_elf_path, + child_process_vm, + child_resource_limits, + child_nice, + child_sig_dispositions, + child_thread_builder, + ) }; if let Some(sig) = clone_args.exit_signal { @@ -510,6 +515,32 @@ fn clone_sysvsem(clone_flags: CloneFlags) -> Result<()> { Ok(()) } +fn create_child_process( + pid: Pid, + parent: Weak, + executable_path: &str, + process_vm: ProcessVm, + resource_limits: ResourceLimits, + nice: Nice, + sig_dispositions: Arc>, + thread_builder: PosixThreadBuilder, +) -> Arc { + let child_proc = Process::new( + pid, + parent, + executable_path.to_string(), + process_vm, + resource_limits, + nice, + sig_dispositions, + ); + + let child_task = thread_builder.process(Arc::downgrade(&child_proc)).build(); + child_proc.tasks().lock().insert(child_task).unwrap(); + + child_proc +} + fn set_parent_and_group(parent: &Process, child: &Arc) { // Lock order: process table -> children -> group of process // -> group inner -> session inner diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index ea31cf80d..2350b5519 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -23,7 +23,8 @@ pub use clone::{clone_child, CloneArgs, CloneFlags}; pub use credentials::{Credentials, Gid, Uid}; pub use kill::{kill, kill_all, kill_group, tgkill}; pub use process::{ - ExitCode, JobControl, Pgid, Pid, Process, ProcessBuilder, ProcessGroup, Session, Sid, Terminal, + spawn_init_process, ExitCode, JobControl, Pgid, Pid, Process, ProcessGroup, Session, Sid, + Terminal, }; pub use process_filter::ProcessFilter; pub use process_vm::{ diff --git a/kernel/src/process/posix_thread/builder.rs b/kernel/src/process/posix_thread/builder.rs index 86a414207..40a84325d 100644 --- a/kernel/src/process/posix_thread/builder.rs +++ b/kernel/src/process/posix_thread/builder.rs @@ -1,7 +1,5 @@ // SPDX-License-Identifier: MPL-2.0 -#![expect(dead_code)] - use ostd::{ cpu::{context::UserContext, CpuSet}, sync::RwArc, @@ -94,11 +92,6 @@ impl PosixThreadBuilder { self } - pub fn sched_policy(mut self, sched_policy: SchedPolicy) -> Self { - self.sched_policy = sched_policy; - self - } - pub fn build(self) -> Arc { let Self { tid, diff --git a/kernel/src/process/posix_thread/mod.rs b/kernel/src/process/posix_thread/mod.rs index 445f98709..ae226c8a7 100644 --- a/kernel/src/process/posix_thread/mod.rs +++ b/kernel/src/process/posix_thread/mod.rs @@ -38,7 +38,7 @@ pub mod thread_table; pub use builder::PosixThreadBuilder; pub use exit::{do_exit, do_exit_group}; pub use name::{ThreadName, MAX_THREAD_NAME_LEN}; -pub use posix_thread_ext::{create_posix_task_from_executable, AsPosixThread}; +pub use posix_thread_ext::AsPosixThread; pub use robust_list::RobustListHead; pub use thread_local::{AsThreadLocal, FileTableRefMut, ThreadLocal}; diff --git a/kernel/src/process/posix_thread/posix_thread_ext.rs b/kernel/src/process/posix_thread/posix_thread_ext.rs index 46625ba40..039854f57 100644 --- a/kernel/src/process/posix_thread/posix_thread_ext.rs +++ b/kernel/src/process/posix_thread/posix_thread_ext.rs @@ -1,17 +1,9 @@ // SPDX-License-Identifier: MPL-2.0 -use ostd::{cpu::context::UserContext, task::Task, user::UserContextApi}; +use ostd::task::Task; -use super::{builder::PosixThreadBuilder, name::ThreadName, PosixThread}; -use crate::{ - fs::{ - fs_resolver::{FsPath, AT_FDCWD}, - thread_info::ThreadFsInfo, - }, - prelude::*, - process::{process_vm::ProcessVm, program_loader::ProgramToLoad, Credentials, Process}, - thread::{AsThread, Thread, Tid}, -}; +use super::PosixThread; +use crate::thread::{AsThread, Thread}; /// A trait to provide the `as_posix_thread` method for tasks and threads. pub trait AsPosixThread { @@ -30,37 +22,3 @@ impl AsPosixThread for Task { self.as_thread()?.as_posix_thread() } } - -/// Creates a task for running an executable file. -/// -/// This function should _only_ be used to create the init user task. -pub fn create_posix_task_from_executable( - tid: Tid, - credentials: Credentials, - process_vm: &ProcessVm, - executable_path: &str, - process: Weak, - argv: Vec, - envp: Vec, -) -> Result> { - let fs = ThreadFsInfo::default(); - let (_, elf_load_info) = { - let fs_resolver = fs.resolver().read(); - let fs_path = FsPath::new(AT_FDCWD, executable_path)?; - let elf_file = fs.resolver().read().lookup(&fs_path)?; - let program_to_load = - ProgramToLoad::build_from_file(elf_file, &fs_resolver, argv, envp, 1)?; - process_vm.clear_and_map(); - program_to_load.load_to_vm(process_vm, &fs_resolver)? - }; - - let mut user_ctx = UserContext::default(); - user_ctx.set_instruction_pointer(elf_load_info.entry_point() as _); - user_ctx.set_stack_pointer(elf_load_info.user_stack_top() as _); - let thread_name = Some(ThreadName::new_from_executable_path(executable_path)?); - let thread_builder = PosixThreadBuilder::new(tid, Arc::new(user_ctx), credentials) - .thread_name(thread_name) - .process(process) - .fs(Arc::new(fs)); - Ok(thread_builder.build()) -} diff --git a/kernel/src/process/process/builder.rs b/kernel/src/process/process/builder.rs deleted file mode 100644 index 08df1a577..000000000 --- a/kernel/src/process/process/builder.rs +++ /dev/null @@ -1,167 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -#![expect(dead_code)] - -use super::{Pid, Process}; -use crate::{ - prelude::*, - process::{ - posix_thread::{create_posix_task_from_executable, PosixThreadBuilder}, - process_vm::ProcessVm, - rlimit::ResourceLimits, - signal::sig_disposition::SigDispositions, - Credentials, - }, - sched::Nice, -}; - -pub struct ProcessBuilder<'a> { - // Essential parts - pid: Pid, - executable_path: &'a str, - parent: Weak, - - // Optional parts - main_thread_builder: Option, - argv: Option>, - envp: Option>, - process_vm: Option, - resource_limits: Option, - sig_dispositions: Option>>, - credentials: Option, - nice: Option, -} - -impl<'a> ProcessBuilder<'a> { - pub fn new(pid: Pid, executable_path: &'a str, parent: Weak) -> Self { - ProcessBuilder { - pid, - executable_path, - parent, - main_thread_builder: None, - argv: None, - envp: None, - process_vm: None, - resource_limits: None, - sig_dispositions: None, - credentials: None, - nice: None, - } - } - - pub fn main_thread_builder(&mut self, builder: PosixThreadBuilder) -> &mut Self { - self.main_thread_builder = Some(builder); - self - } - - pub fn process_vm(&mut self, process_vm: ProcessVm) -> &mut Self { - self.process_vm = Some(process_vm); - self - } - - pub fn resource_limits(&mut self, resource_limits: ResourceLimits) -> &mut Self { - self.resource_limits = Some(resource_limits); - self - } - - pub fn sig_dispositions(&mut self, sig_dispositions: Arc>) -> &mut Self { - self.sig_dispositions = Some(sig_dispositions); - self - } - - pub fn argv(&mut self, argv: Vec) -> &mut Self { - self.argv = Some(argv); - self - } - - pub fn envp(&mut self, envp: Vec) -> &mut Self { - self.envp = Some(envp); - self - } - - pub fn credentials(&mut self, credentials: Credentials) -> &mut Self { - self.credentials = Some(credentials); - self - } - - pub fn nice(&mut self, nice: Nice) -> &mut Self { - self.nice = Some(nice); - self - } - - fn check_build(&self) -> Result<()> { - if self.main_thread_builder.is_some() { - debug_assert!(self.parent.upgrade().is_some()); - debug_assert!(self.argv.is_none()); - debug_assert!(self.envp.is_none()); - debug_assert!(self.credentials.is_none()); - } - - if self.main_thread_builder.is_none() { - debug_assert!(self.parent.upgrade().is_none()); - debug_assert!(self.argv.is_some()); - debug_assert!(self.envp.is_some()); - debug_assert!(self.credentials.is_some()); - } - - Ok(()) - } - - pub fn build(self) -> Result> { - self.check_build()?; - let Self { - pid, - executable_path, - parent, - main_thread_builder, - argv, - envp, - process_vm, - resource_limits, - sig_dispositions, - credentials, - nice, - } = self; - - let process_vm = process_vm.or_else(|| Some(ProcessVm::alloc())).unwrap(); - - let resource_limits = resource_limits - .or_else(|| Some(ResourceLimits::default())) - .unwrap(); - - let sig_dispositions = sig_dispositions - .or_else(|| Some(Arc::new(Mutex::new(SigDispositions::new())))) - .unwrap(); - - let nice = nice.or_else(|| Some(Nice::default())).unwrap(); - - let process = Process::new( - pid, - parent, - executable_path.to_string(), - process_vm, - resource_limits, - nice, - sig_dispositions, - ); - - let task = if let Some(thread_builder) = main_thread_builder { - let builder = thread_builder.process(Arc::downgrade(&process)); - builder.build() - } else { - create_posix_task_from_executable( - pid, - credentials.unwrap(), - process.vm(), - executable_path, - Arc::downgrade(&process), - argv.unwrap(), - envp.unwrap(), - )? - }; - - process.tasks().lock().insert(task).unwrap(); - - Ok(process) - } -} diff --git a/kernel/src/process/process/init_proc.rs b/kernel/src/process/process/init_proc.rs new file mode 100644 index 000000000..69adda5ea --- /dev/null +++ b/kernel/src/process/process/init_proc.rs @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: MPL-2.0 + +//! This module defines functions related to spawning the init process. + +use ostd::{cpu::context::UserContext, task::Task, user::UserContextApi}; + +use super::{Process, Terminal}; +use crate::{ + device::tty::get_n_tty, + fs::{ + fs_resolver::{FsPath, AT_FDCWD}, + thread_info::ThreadFsInfo, + }, + prelude::*, + process::{ + posix_thread::{allocate_posix_tid, PosixThreadBuilder, ThreadName}, + process_table, + process_vm::ProcessVm, + rlimit::ResourceLimits, + signal::sig_disposition::SigDispositions, + Credentials, ProgramToLoad, + }, + sched::Nice, + thread::Tid, +}; + +/// Creates and schedules the init process to run. +pub fn spawn_init_process( + executable_path: &str, + argv: Vec, + envp: Vec, +) -> Result> { + // Ensure the path for init process executable is absolute. + debug_assert!(executable_path.starts_with('/')); + + let process = create_init_process(executable_path, argv, envp)?; + + set_session_and_group(&process); + + open_ntty_as_controlling_terminal(&process)?; + + process.run(); + + Ok(process) +} + +fn create_init_process( + executable_path: &str, + argv: Vec, + envp: Vec, +) -> Result> { + let pid = allocate_posix_tid(); + let parent = Weak::new(); + let process_vm = ProcessVm::alloc(); + let resource_limits = ResourceLimits::default(); + let nice = Nice::default(); + let sig_dispositions = Arc::new(Mutex::new(SigDispositions::default())); + + let init_proc = Process::new( + pid, + parent, + executable_path.to_string(), + process_vm, + resource_limits, + nice, + sig_dispositions, + ); + + let init_task = create_init_task( + pid, + init_proc.vm(), + executable_path, + Arc::downgrade(&init_proc), + argv, + envp, + )?; + init_proc.tasks().lock().insert(init_task).unwrap(); + + Ok(init_proc) +} + +fn set_session_and_group(process: &Arc) { + // Locking order: session table -> group table -> process table -> process group + let mut session_table_mut = process_table::session_table_mut(); + let mut group_table_mut = process_table::group_table_mut(); + let mut process_table_mut = process_table::process_table_mut(); + + // Create a new process group and session for the process + process.set_new_session( + &mut process.process_group.lock(), + &mut session_table_mut, + &mut group_table_mut, + ); + + // Add the new process to the global table + process_table_mut.insert(process.pid(), process.clone()); +} + +/// Creates the init task from the given executable file. +fn create_init_task( + tid: Tid, + process_vm: &ProcessVm, + executable_path: &str, + process: Weak, + argv: Vec, + envp: Vec, +) -> Result> { + let credentials = Credentials::new_root(); + let fs = ThreadFsInfo::default(); + let (_, elf_load_info) = { + let fs_resolver = fs.resolver().read(); + let fs_path = FsPath::new(AT_FDCWD, executable_path)?; + let elf_file = fs.resolver().read().lookup(&fs_path)?; + let program_to_load = + ProgramToLoad::build_from_file(elf_file, &fs_resolver, argv, envp, 1)?; + process_vm.clear_and_map(); + program_to_load.load_to_vm(process_vm, &fs_resolver)? + }; + + let mut user_ctx = UserContext::default(); + user_ctx.set_instruction_pointer(elf_load_info.entry_point() as _); + user_ctx.set_stack_pointer(elf_load_info.user_stack_top() as _); + let thread_name = Some(ThreadName::new_from_executable_path(executable_path)?); + let thread_builder = PosixThreadBuilder::new(tid, Arc::new(user_ctx), credentials) + .thread_name(thread_name) + .process(process) + .fs(Arc::new(fs)); + Ok(thread_builder.build()) +} + +/// Opens `N_TTY` as the controlling terminal for the process. +fn open_ntty_as_controlling_terminal(process: &Process) -> Result<()> { + let tty = get_n_tty(); + + let session = &process.session().unwrap(); + let process_group = process.process_group().unwrap(); + + session.set_terminal(|| { + tty.job_control().set_session(session); + Ok(tty.clone()) + })?; + + tty.job_control().set_foreground(Some(&process_group))?; + + Ok(()) +} diff --git a/kernel/src/process/process/mod.rs b/kernel/src/process/process/mod.rs index 15b7b54b1..bb88c9ad3 100644 --- a/kernel/src/process/process/mod.rs +++ b/kernel/src/process/process/mod.rs @@ -4,7 +4,7 @@ use core::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use self::timer_manager::PosixTimerManager; use super::{ - posix_thread::{allocate_posix_tid, AsPosixThread}, + posix_thread::AsPosixThread, process_table, process_vm::{Heap, InitStackReader, ProcessVm, ProcessVmarGuard}, rlimit::ResourceLimits, @@ -15,17 +15,15 @@ use super::{ }, status::ProcessStatus, task_set::TaskSet, - Credentials, }; use crate::{ - device::tty::open_ntty_as_controlling_terminal, prelude::*, sched::{AtomicNice, Nice}, thread::{AsThread, Thread}, time::clocks::ProfClock, }; -mod builder; +mod init_proc; mod job_control; mod process_group; mod session; @@ -33,7 +31,7 @@ mod terminal; mod timer_manager; use atomic_integer_wrapper::define_atomic_version_of_integer_like_type; -pub use builder::ProcessBuilder; +pub use init_proc::spawn_init_process; pub use job_control::JobControl; use ostd::{sync::WaitQueue, task::Task}; pub use process_group::ProcessGroup; @@ -184,7 +182,7 @@ impl Process { Some(Task::current()?.as_posix_thread()?.process()) } - fn new( + pub(super) fn new( pid: Pid, parent: Weak, executable_path: String, @@ -222,57 +220,8 @@ impl Process { }) } - /// init a user process and run the process - pub fn spawn_user_process( - executable_path: &str, - argv: Vec, - envp: Vec, - ) -> Result> { - // spawn user process should give an absolute path - debug_assert!(executable_path.starts_with('/')); - let process = Process::create_user_process(executable_path, argv, envp)?; - - open_ntty_as_controlling_terminal(&process)?; - - process.run(); - Ok(process) - } - - fn create_user_process( - executable_path: &str, - argv: Vec, - envp: Vec, - ) -> Result> { - let process = { - let pid = allocate_posix_tid(); - let parent = Weak::new(); - let credentials = Credentials::new_root(); - - let mut builder = ProcessBuilder::new(pid, executable_path, parent); - builder.argv(argv).envp(envp).credentials(credentials); - builder.build()? - }; - - // Lock order: session table -> group table -> process table -> group of process - let mut session_table_mut = process_table::session_table_mut(); - let mut group_table_mut = process_table::group_table_mut(); - let mut process_table_mut = process_table::process_table_mut(); - - // Create a new process group and a new session for the new process - process.set_new_session( - &mut process.process_group.lock(), - &mut session_table_mut, - &mut group_table_mut, - ); - - // Insert the new process to the global table - process_table_mut.insert(process.pid(), process.clone()); - - Ok(process) - } - - /// start to run current process - pub fn run(&self) { + /// Runs the process. + pub(super) fn run(&self) { let tasks = self.tasks.lock(); // when run the process, the process should has only one thread debug_assert!(tasks.as_slice().len() == 1); diff --git a/kernel/src/process/rlimit.rs b/kernel/src/process/rlimit.rs index a2312d7a5..947cd20a3 100644 --- a/kernel/src/process/rlimit.rs +++ b/kernel/src/process/rlimit.rs @@ -26,6 +26,7 @@ const INIT_RLIMIT_MEMLOCK: u64 = 8 * 1024 * 1024; // https://github.com/torvalds/linux/blob/fac04efc5c793dccbd07e2d59af9f90b7fc0dca4/include/uapi/linux/mqueue.h#L26 const INIT_RLIMIT_MSGQUEUE: u64 = 819200; +#[derive(Clone)] pub struct ResourceLimits { rlimits: [RLimit64; RLIMIT_COUNT], } @@ -169,3 +170,14 @@ impl Default for RLimit64 { } } } + +impl Clone for RLimit64 { + fn clone(&self) -> Self { + let (cur, max) = self.get_cur_and_max(); + Self { + cur: AtomicU64::new(cur), + max: AtomicU64::new(max), + lock: SpinLock::new(()), + } + } +}