mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-20 13:06:33 +00:00
Move functions related to spawning the init process to a seperate module
This commit is contained in:
@ -15,7 +15,7 @@ use crate::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
process::{
|
process::{
|
||||||
signal::{signals::kernel::KernelSignal, PollHandle, Pollable},
|
signal::{signals::kernel::KernelSignal, PollHandle, Pollable},
|
||||||
JobControl, Process, Terminal,
|
JobControl, Terminal,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -211,21 +211,3 @@ pub fn new_job_control_and_ldisc() -> (Arc<JobControl>, Arc<LineDiscipline>) {
|
|||||||
pub fn get_n_tty() -> &'static Arc<Tty> {
|
pub fn get_n_tty() -> &'static Arc<Tty> {
|
||||||
N_TTY.get().unwrap()
|
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(())
|
|
||||||
}
|
|
||||||
|
@ -35,7 +35,7 @@ use ostd::{
|
|||||||
boot::boot_info,
|
boot::boot_info,
|
||||||
cpu::{CpuId, CpuSet, PinCurrentCpu},
|
cpu::{CpuId, CpuSet, PinCurrentCpu},
|
||||||
};
|
};
|
||||||
use process::Process;
|
use process::{spawn_init_process, Process};
|
||||||
use sched::SchedPolicy;
|
use sched::SchedPolicy;
|
||||||
|
|
||||||
use crate::{prelude::*, thread::kernel_thread::ThreadOptions};
|
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 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_path().unwrap(),
|
||||||
karg.get_initproc_argv().to_vec(),
|
karg.get_initproc_argv().to_vec(),
|
||||||
karg.get_initproc_envp().to_vec(),
|
karg.get_initproc_envp().to_vec(),
|
||||||
|
@ -8,8 +8,9 @@ use super::{
|
|||||||
posix_thread::{AsPosixThread, PosixThreadBuilder, ThreadName},
|
posix_thread::{AsPosixThread, PosixThreadBuilder, ThreadName},
|
||||||
process_table,
|
process_table,
|
||||||
process_vm::ProcessVm,
|
process_vm::ProcessVm,
|
||||||
|
rlimit::ResourceLimits,
|
||||||
signal::{constants::SIGCHLD, sig_disposition::SigDispositions, sig_num::SigNum},
|
signal::{constants::SIGCHLD, sig_disposition::SigDispositions, sig_num::SigNum},
|
||||||
Credentials, Process, ProcessBuilder,
|
Credentials, Pid, Process,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
cpu::LinuxAbi,
|
cpu::LinuxAbi,
|
||||||
@ -17,6 +18,7 @@ use crate::{
|
|||||||
fs::{file_table::FileTable, thread_info::ThreadFsInfo},
|
fs::{file_table::FileTable, thread_info::ThreadFsInfo},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::posix_thread::allocate_posix_tid,
|
process::posix_thread::allocate_posix_tid,
|
||||||
|
sched::Nice,
|
||||||
thread::{AsThread, Tid},
|
thread::{AsThread, Tid},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -299,13 +301,13 @@ fn clone_child_process(
|
|||||||
|
|
||||||
let clone_flags = clone_args.flags;
|
let clone_flags = clone_args.flags;
|
||||||
|
|
||||||
// clone vm
|
// Clone the virtual memory space
|
||||||
let child_process_vm = {
|
let child_process_vm = {
|
||||||
let parent_process_vm = process.vm();
|
let parent_process_vm = process.vm();
|
||||||
clone_vm(parent_process_vm, clone_flags)?
|
clone_vm(parent_process_vm, clone_flags)?
|
||||||
};
|
};
|
||||||
|
|
||||||
// clone user space
|
// Clone the user context
|
||||||
let child_user_ctx = Arc::new(clone_user_ctx(
|
let child_user_ctx = Arc::new(clone_user_ctx(
|
||||||
parent_context,
|
parent_context,
|
||||||
clone_args.stack,
|
clone_args.stack,
|
||||||
@ -314,22 +316,25 @@ fn clone_child_process(
|
|||||||
clone_flags,
|
clone_flags,
|
||||||
));
|
));
|
||||||
|
|
||||||
// clone file table
|
// Clone the file table
|
||||||
let child_file_table = clone_files(thread_local.borrow_file_table().unwrap(), clone_flags);
|
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);
|
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);
|
let child_sig_dispositions = clone_sighand(process.sig_dispositions(), clone_flags);
|
||||||
|
|
||||||
// clone system V semaphore
|
// Clone System V semaphore
|
||||||
clone_sysvsem(clone_flags)?;
|
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();
|
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_nice = process.nice().load(Ordering::Relaxed);
|
||||||
|
|
||||||
let child_tid = allocate_posix_tid();
|
let child_tid = allocate_posix_tid();
|
||||||
@ -358,16 +363,16 @@ fn clone_child_process(
|
|||||||
child_thread_builder =
|
child_thread_builder =
|
||||||
clone_child_settid(child_thread_builder, clone_args.child_tid, clone_flags);
|
clone_child_settid(child_thread_builder, clone_args.child_tid, clone_flags);
|
||||||
|
|
||||||
let mut process_builder =
|
create_child_process(
|
||||||
ProcessBuilder::new(child_tid, &child_elf_path, posix_thread.weak_process());
|
child_tid,
|
||||||
|
posix_thread.weak_process(),
|
||||||
process_builder
|
&child_elf_path,
|
||||||
.main_thread_builder(child_thread_builder)
|
child_process_vm,
|
||||||
.process_vm(child_process_vm)
|
child_resource_limits,
|
||||||
.sig_dispositions(child_sig_dispositions)
|
child_nice,
|
||||||
.nice(child_nice);
|
child_sig_dispositions,
|
||||||
|
child_thread_builder,
|
||||||
process_builder.build()?
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(sig) = clone_args.exit_signal {
|
if let Some(sig) = clone_args.exit_signal {
|
||||||
@ -510,6 +515,32 @@ fn clone_sysvsem(clone_flags: CloneFlags) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_child_process(
|
||||||
|
pid: Pid,
|
||||||
|
parent: Weak<Process>,
|
||||||
|
executable_path: &str,
|
||||||
|
process_vm: ProcessVm,
|
||||||
|
resource_limits: ResourceLimits,
|
||||||
|
nice: Nice,
|
||||||
|
sig_dispositions: Arc<Mutex<SigDispositions>>,
|
||||||
|
thread_builder: PosixThreadBuilder,
|
||||||
|
) -> Arc<Process> {
|
||||||
|
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<Process>) {
|
fn set_parent_and_group(parent: &Process, child: &Arc<Process>) {
|
||||||
// Lock order: process table -> children -> group of process
|
// Lock order: process table -> children -> group of process
|
||||||
// -> group inner -> session inner
|
// -> group inner -> session inner
|
||||||
|
@ -23,7 +23,8 @@ pub use clone::{clone_child, CloneArgs, CloneFlags};
|
|||||||
pub use credentials::{Credentials, Gid, Uid};
|
pub use credentials::{Credentials, Gid, Uid};
|
||||||
pub use kill::{kill, kill_all, kill_group, tgkill};
|
pub use kill::{kill, kill_all, kill_group, tgkill};
|
||||||
pub use process::{
|
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_filter::ProcessFilter;
|
||||||
pub use process_vm::{
|
pub use process_vm::{
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
#![expect(dead_code)]
|
|
||||||
|
|
||||||
use ostd::{
|
use ostd::{
|
||||||
cpu::{context::UserContext, CpuSet},
|
cpu::{context::UserContext, CpuSet},
|
||||||
sync::RwArc,
|
sync::RwArc,
|
||||||
@ -94,11 +92,6 @@ impl PosixThreadBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sched_policy(mut self, sched_policy: SchedPolicy) -> Self {
|
|
||||||
self.sched_policy = sched_policy;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(self) -> Arc<Task> {
|
pub fn build(self) -> Arc<Task> {
|
||||||
let Self {
|
let Self {
|
||||||
tid,
|
tid,
|
||||||
|
@ -38,7 +38,7 @@ pub mod thread_table;
|
|||||||
pub use builder::PosixThreadBuilder;
|
pub use builder::PosixThreadBuilder;
|
||||||
pub use exit::{do_exit, do_exit_group};
|
pub use exit::{do_exit, do_exit_group};
|
||||||
pub use name::{ThreadName, MAX_THREAD_NAME_LEN};
|
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 robust_list::RobustListHead;
|
||||||
pub use thread_local::{AsThreadLocal, FileTableRefMut, ThreadLocal};
|
pub use thread_local::{AsThreadLocal, FileTableRefMut, ThreadLocal};
|
||||||
|
|
||||||
|
@ -1,17 +1,9 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// 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 super::PosixThread;
|
||||||
use crate::{
|
use crate::thread::{AsThread, Thread};
|
||||||
fs::{
|
|
||||||
fs_resolver::{FsPath, AT_FDCWD},
|
|
||||||
thread_info::ThreadFsInfo,
|
|
||||||
},
|
|
||||||
prelude::*,
|
|
||||||
process::{process_vm::ProcessVm, program_loader::ProgramToLoad, Credentials, Process},
|
|
||||||
thread::{AsThread, Thread, Tid},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A trait to provide the `as_posix_thread` method for tasks and threads.
|
/// A trait to provide the `as_posix_thread` method for tasks and threads.
|
||||||
pub trait AsPosixThread {
|
pub trait AsPosixThread {
|
||||||
@ -30,37 +22,3 @@ impl AsPosixThread for Task {
|
|||||||
self.as_thread()?.as_posix_thread()
|
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<Process>,
|
|
||||||
argv: Vec<CString>,
|
|
||||||
envp: Vec<CString>,
|
|
||||||
) -> Result<Arc<Task>> {
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
|
@ -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<Process>,
|
|
||||||
|
|
||||||
// Optional parts
|
|
||||||
main_thread_builder: Option<PosixThreadBuilder>,
|
|
||||||
argv: Option<Vec<CString>>,
|
|
||||||
envp: Option<Vec<CString>>,
|
|
||||||
process_vm: Option<ProcessVm>,
|
|
||||||
resource_limits: Option<ResourceLimits>,
|
|
||||||
sig_dispositions: Option<Arc<Mutex<SigDispositions>>>,
|
|
||||||
credentials: Option<Credentials>,
|
|
||||||
nice: Option<Nice>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ProcessBuilder<'a> {
|
|
||||||
pub fn new(pid: Pid, executable_path: &'a str, parent: Weak<Process>) -> 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<Mutex<SigDispositions>>) -> &mut Self {
|
|
||||||
self.sig_dispositions = Some(sig_dispositions);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn argv(&mut self, argv: Vec<CString>) -> &mut Self {
|
|
||||||
self.argv = Some(argv);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn envp(&mut self, envp: Vec<CString>) -> &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<Arc<Process>> {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
146
kernel/src/process/process/init_proc.rs
Normal file
146
kernel/src/process/process/init_proc.rs
Normal file
@ -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<CString>,
|
||||||
|
envp: Vec<CString>,
|
||||||
|
) -> Result<Arc<Process>> {
|
||||||
|
// 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<CString>,
|
||||||
|
envp: Vec<CString>,
|
||||||
|
) -> Result<Arc<Process>> {
|
||||||
|
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<Process>) {
|
||||||
|
// 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<Process>,
|
||||||
|
argv: Vec<CString>,
|
||||||
|
envp: Vec<CString>,
|
||||||
|
) -> Result<Arc<Task>> {
|
||||||
|
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(())
|
||||||
|
}
|
@ -4,7 +4,7 @@ use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
|||||||
|
|
||||||
use self::timer_manager::PosixTimerManager;
|
use self::timer_manager::PosixTimerManager;
|
||||||
use super::{
|
use super::{
|
||||||
posix_thread::{allocate_posix_tid, AsPosixThread},
|
posix_thread::AsPosixThread,
|
||||||
process_table,
|
process_table,
|
||||||
process_vm::{Heap, InitStackReader, ProcessVm, ProcessVmarGuard},
|
process_vm::{Heap, InitStackReader, ProcessVm, ProcessVmarGuard},
|
||||||
rlimit::ResourceLimits,
|
rlimit::ResourceLimits,
|
||||||
@ -15,17 +15,15 @@ use super::{
|
|||||||
},
|
},
|
||||||
status::ProcessStatus,
|
status::ProcessStatus,
|
||||||
task_set::TaskSet,
|
task_set::TaskSet,
|
||||||
Credentials,
|
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
device::tty::open_ntty_as_controlling_terminal,
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
sched::{AtomicNice, Nice},
|
sched::{AtomicNice, Nice},
|
||||||
thread::{AsThread, Thread},
|
thread::{AsThread, Thread},
|
||||||
time::clocks::ProfClock,
|
time::clocks::ProfClock,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod builder;
|
mod init_proc;
|
||||||
mod job_control;
|
mod job_control;
|
||||||
mod process_group;
|
mod process_group;
|
||||||
mod session;
|
mod session;
|
||||||
@ -33,7 +31,7 @@ mod terminal;
|
|||||||
mod timer_manager;
|
mod timer_manager;
|
||||||
|
|
||||||
use atomic_integer_wrapper::define_atomic_version_of_integer_like_type;
|
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;
|
pub use job_control::JobControl;
|
||||||
use ostd::{sync::WaitQueue, task::Task};
|
use ostd::{sync::WaitQueue, task::Task};
|
||||||
pub use process_group::ProcessGroup;
|
pub use process_group::ProcessGroup;
|
||||||
@ -184,7 +182,7 @@ impl Process {
|
|||||||
Some(Task::current()?.as_posix_thread()?.process())
|
Some(Task::current()?.as_posix_thread()?.process())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(
|
pub(super) fn new(
|
||||||
pid: Pid,
|
pid: Pid,
|
||||||
parent: Weak<Process>,
|
parent: Weak<Process>,
|
||||||
executable_path: String,
|
executable_path: String,
|
||||||
@ -222,57 +220,8 @@ impl Process {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// init a user process and run the process
|
/// Runs the process.
|
||||||
pub fn spawn_user_process(
|
pub(super) fn run(&self) {
|
||||||
executable_path: &str,
|
|
||||||
argv: Vec<CString>,
|
|
||||||
envp: Vec<CString>,
|
|
||||||
) -> Result<Arc<Self>> {
|
|
||||||
// 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<CString>,
|
|
||||||
envp: Vec<CString>,
|
|
||||||
) -> Result<Arc<Self>> {
|
|
||||||
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) {
|
|
||||||
let tasks = self.tasks.lock();
|
let tasks = self.tasks.lock();
|
||||||
// when run the process, the process should has only one thread
|
// when run the process, the process should has only one thread
|
||||||
debug_assert!(tasks.as_slice().len() == 1);
|
debug_assert!(tasks.as_slice().len() == 1);
|
||||||
|
@ -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
|
// https://github.com/torvalds/linux/blob/fac04efc5c793dccbd07e2d59af9f90b7fc0dca4/include/uapi/linux/mqueue.h#L26
|
||||||
const INIT_RLIMIT_MSGQUEUE: u64 = 819200;
|
const INIT_RLIMIT_MSGQUEUE: u64 = 819200;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ResourceLimits {
|
pub struct ResourceLimits {
|
||||||
rlimits: [RLimit64; RLIMIT_COUNT],
|
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(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user