Make task store Arc<Thread> and process store Arc<Task>

This commit is contained in:
Jianfeng Jiang
2024-09-13 03:13:07 +00:00
committed by Tate, Hongliang Tian
parent 81b0f265b5
commit f3174dbbbc
22 changed files with 255 additions and 246 deletions

View File

@ -4,11 +4,12 @@ use core::sync::atomic::Ordering;
use ostd::{
cpu::UserContext,
task::Task,
user::{UserContextApi, UserSpace},
};
use super::{
posix_thread::{PosixThread, PosixThreadBuilder, PosixThreadExt, ThreadName},
posix_thread::{thread_table, PosixThread, PosixThreadBuilder, PosixThreadExt, ThreadName},
process_table,
process_vm::ProcessVm,
signal::sig_disposition::SigDispositions,
@ -19,7 +20,7 @@ use crate::{
fs::{file_table::FileTable, fs_resolver::FsResolver, utils::FileCreationMask},
prelude::*,
process::posix_thread::allocate_posix_tid,
thread::{thread_table, Thread, Tid},
thread::{Thread, Tid},
};
bitflags! {
@ -133,7 +134,8 @@ pub fn clone_child(
) -> Result<Tid> {
clone_args.clone_flags.check_unsupported_flags()?;
if clone_args.clone_flags.contains(CloneFlags::CLONE_THREAD) {
let child_thread = clone_child_thread(ctx, parent_context, clone_args)?;
let child_task = clone_child_task(ctx, parent_context, clone_args)?;
let child_thread = Thread::borrow_from_task(&child_task);
child_thread.run();
let child_tid = child_thread.tid();
@ -147,11 +149,11 @@ pub fn clone_child(
}
}
fn clone_child_thread(
fn clone_child_task(
ctx: &Context,
parent_context: &UserContext,
clone_args: CloneArgs,
) -> Result<Arc<Thread>> {
) -> Result<Arc<Task>> {
let Context {
process,
posix_thread,
@ -182,7 +184,7 @@ fn clone_child_thread(
let sig_mask = posix_thread.sig_mask().load(Ordering::Relaxed).into();
let child_tid = allocate_posix_tid();
let child_thread = {
let child_task = {
let credentials = {
let credentials = ctx.posix_thread.credentials();
Credentials::new_from(&credentials)
@ -194,13 +196,13 @@ fn clone_child_thread(
thread_builder.build()
};
process.threads().lock().push(child_thread.clone());
process.tasks().lock().push(child_task.clone());
let child_posix_thread = child_thread.as_posix_thread().unwrap();
let child_posix_thread = child_task.as_posix_thread().unwrap();
clone_parent_settid(child_tid, clone_args.parent_tidptr, clone_flags)?;
clone_child_cleartid(child_posix_thread, clone_args.child_tidptr, clone_flags)?;
clone_child_settid(child_posix_thread, clone_args.child_tidptr, clone_flags)?;
Ok(child_thread)
Ok(child_task)
}
fn clone_child_process(
@ -296,7 +298,7 @@ fn clone_child_process(
};
// Deals with clone flags
let child_thread = thread_table::get_posix_thread(child_tid).unwrap();
let child_thread = thread_table::get_thread(child_tid).unwrap();
let child_posix_thread = child_thread.as_posix_thread().unwrap();
clone_parent_settid(child_tid, clone_args.parent_tidptr, clone_flags)?;
clone_child_cleartid(child_posix_thread, clone_args.child_tidptr, clone_flags)?;

View File

@ -7,6 +7,7 @@ use crate::{
posix_thread::{do_exit, PosixThreadExt},
signal::{constants::SIGCHLD, signals::kernel::KernelSignal},
},
thread::Thread,
};
pub fn do_exit_group(term_status: TermStatus) {
@ -18,9 +19,11 @@ pub fn do_exit_group(term_status: TermStatus) {
current.set_zombie(term_status);
// Exit all threads
let threads = current.threads().lock().clone();
for thread in threads {
if let Err(e) = do_exit(&thread, thread.as_posix_thread().unwrap(), term_status) {
let tasks = current.tasks().lock().clone();
for task in tasks {
let thread = Thread::borrow_from_task(&task);
let posix_thread = thread.as_posix_thread().unwrap();
if let Err(e) = do_exit(thread, posix_thread, term_status) {
debug!("Ignore error when call exit: {:?}", e);
}
}

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
use super::{
posix_thread::PosixThreadExt,
posix_thread::{thread_table, PosixThreadExt},
process_table,
signal::{
constants::SIGCONT,
@ -10,10 +10,7 @@ use super::{
},
Pgid, Pid, Process, Sid, Uid,
};
use crate::{
prelude::*,
thread::{thread_table, Tid},
};
use crate::{prelude::*, thread::Tid};
/// Sends a signal to a process, using the current process as the sender.
///
@ -71,7 +68,7 @@ pub fn kill_group(pgid: Pgid, signal: Option<UserSignal>, ctx: &Context) -> Resu
/// If `signal` is `None`, this method will only check permission without sending
/// any signal.
pub fn tgkill(tid: Tid, tgid: Pid, signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
let thread = thread_table::get_posix_thread(tid)
let thread = thread_table::get_thread(tid)
.ok_or_else(|| Error::with_message(Errno::ESRCH, "target thread does not exist"))?;
if thread.status().is_exited() {
@ -120,14 +117,14 @@ pub fn kill_all(signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
}
fn kill_process(process: &Process, signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
let threads = process.threads().lock();
let tasks = process.tasks().lock();
let signum = signal.map(|signal| signal.num());
let sender_ids = current_thread_sender_ids(signum.as_ref(), ctx);
let mut permitted_thread = None;
for thread in threads.iter() {
let posix_thread = thread.as_posix_thread().unwrap();
for task in tasks.iter() {
let posix_thread = task.as_posix_thread().unwrap();
// First check permission
if posix_thread

View File

@ -2,9 +2,9 @@
#![allow(dead_code)]
use ostd::user::UserSpace;
use ostd::{task::Task, user::UserSpace};
use super::PosixThread;
use super::{thread_table, PosixThread};
use crate::{
prelude::*,
process::{
@ -12,7 +12,7 @@ use crate::{
signal::{sig_mask::AtomicSigMask, sig_queues::SigQueues},
Credentials, Process,
},
thread::{status::ThreadStatus, task, thread_table, Thread, Tid},
thread::{status::ThreadStatus, task, Thread, Tid},
time::{clocks::ProfClock, TimerManager},
};
@ -72,7 +72,7 @@ impl PosixThreadBuilder {
self
}
pub fn build(self) -> Arc<Thread> {
pub fn build(self) -> Arc<Task> {
let Self {
tid,
user_space,
@ -85,35 +85,36 @@ impl PosixThreadBuilder {
sig_queues,
} = self;
let thread = Arc::new_cyclic(|thread_ref| {
let task = task::create_new_user_task(user_space, thread_ref.clone());
let status = ThreadStatus::Init;
Arc::new_cyclic(|weak_task| {
let posix_thread = {
let prof_clock = ProfClock::new();
let virtual_timer_manager = TimerManager::new(prof_clock.user_clock().clone());
let prof_timer_manager = TimerManager::new(prof_clock.clone());
let prof_clock = ProfClock::new();
let virtual_timer_manager = TimerManager::new(prof_clock.user_clock().clone());
let prof_timer_manager = TimerManager::new(prof_clock.clone());
let posix_thread = PosixThread {
process,
tid,
name: Mutex::new(thread_name),
set_child_tid: Mutex::new(set_child_tid),
clear_child_tid: Mutex::new(clear_child_tid),
credentials,
sig_mask,
sig_queues,
sig_context: Mutex::new(None),
sig_stack: Mutex::new(None),
signalled_waker: SpinLock::new(None),
robust_list: Mutex::new(None),
prof_clock,
virtual_timer_manager,
prof_timer_manager,
PosixThread {
process,
tid,
name: Mutex::new(thread_name),
set_child_tid: Mutex::new(set_child_tid),
clear_child_tid: Mutex::new(clear_child_tid),
credentials,
sig_mask,
sig_queues,
sig_context: Mutex::new(None),
sig_stack: Mutex::new(None),
signalled_waker: SpinLock::new(None),
robust_list: Mutex::new(None),
prof_clock,
virtual_timer_manager,
prof_timer_manager,
}
};
Thread::new(task, posix_thread, status)
});
thread_table::add_posix_thread(tid, thread.clone());
thread
let status = ThreadStatus::Init;
let thread = Arc::new(Thread::new(weak_task.clone(), posix_thread, status));
thread_table::add_thread(tid, thread.clone());
task::create_new_user_task(user_space, thread)
})
}
}

View File

@ -1,10 +1,10 @@
// SPDX-License-Identifier: MPL-2.0
use super::{futex::futex_wake, robust_list::wake_robust_futex, PosixThread};
use super::{futex::futex_wake, robust_list::wake_robust_futex, thread_table, PosixThread};
use crate::{
prelude::*,
process::{do_exit_group, TermStatus},
thread::{thread_table, Thread, Tid},
thread::{Thread, Tid},
};
/// Exits the thread if the thread is a POSIX thread.
@ -36,7 +36,7 @@ pub fn do_exit(thread: &Thread, posix_thread: &PosixThread, term_status: TermSta
if tid != posix_thread.process().pid() {
// We don't remove main thread.
// The main thread is removed when the process is reaped.
thread_table::remove_posix_thread(tid);
thread_table::remove_thread(tid);
}
if posix_thread.is_main_thread(tid) || posix_thread.is_last_thread() {

View File

@ -22,7 +22,7 @@ use crate::{
events::Observer,
prelude::*,
process::signal::constants::SIGCONT,
thread::Tid,
thread::{Thread, Tid},
time::{clocks::ProfClock, Timer, TimerManager},
};
@ -32,11 +32,12 @@ pub mod futex;
mod name;
mod posix_thread_ext;
mod robust_list;
pub mod thread_table;
pub use builder::PosixThreadBuilder;
pub use exit::do_exit;
pub use name::{ThreadName, MAX_THREAD_NAME_LEN};
pub use posix_thread_ext::PosixThreadExt;
pub use posix_thread_ext::{create_posix_task_from_executable, PosixThreadExt};
pub use robust_list::RobustListHead;
pub struct PosixThread {
@ -273,12 +274,10 @@ impl PosixThread {
fn is_last_thread(&self) -> bool {
let process = self.process.upgrade().unwrap();
let threads = process.threads().lock();
threads
let tasks = process.tasks().lock();
tasks
.iter()
.filter(|thread| !thread.status().is_exited())
.count()
== 0
.any(|task| !Thread::borrow_from_task(task).status().is_exited())
}
/// Gets the read-only credentials of the thread.

View File

@ -2,6 +2,7 @@
use ostd::{
cpu::UserContext,
task::Task,
user::{UserContextApi, UserSpace},
};
@ -22,51 +23,48 @@ pub trait PosixThreadExt {
self.as_posix_thread().unwrap().tid()
}
fn as_posix_thread(&self) -> Option<&PosixThread>;
#[allow(clippy::too_many_arguments)]
fn new_posix_thread_from_executable(
tid: Tid,
credentials: Credentials,
process_vm: &ProcessVm,
fs_resolver: &FsResolver,
executable_path: &str,
process: Weak<Process>,
argv: Vec<CString>,
envp: Vec<CString>,
) -> Result<Arc<Self>>;
}
impl PosixThreadExt for Thread {
/// This function should only be called when launch shell()
fn new_posix_thread_from_executable(
tid: Tid,
credentials: Credentials,
process_vm: &ProcessVm,
fs_resolver: &FsResolver,
executable_path: &str,
process: Weak<Process>,
argv: Vec<CString>,
envp: Vec<CString>,
) -> Result<Arc<Self>> {
let elf_file = {
let fs_path = FsPath::new(AT_FDCWD, executable_path)?;
fs_resolver.lookup(&fs_path)?
};
let (_, elf_load_info) =
load_program_to_vm(process_vm, elf_file, argv, envp, fs_resolver, 1)?;
let vm_space = process_vm.root_vmar().vm_space().clone();
let mut cpu_ctx = UserContext::default();
cpu_ctx.set_instruction_pointer(elf_load_info.entry_point() as _);
cpu_ctx.set_stack_pointer(elf_load_info.user_stack_top() as _);
let user_space = Arc::new(UserSpace::new(vm_space, cpu_ctx));
let thread_name = Some(ThreadName::new_from_executable_path(executable_path)?);
let thread_builder = PosixThreadBuilder::new(tid, user_space, credentials)
.thread_name(thread_name)
.process(process);
Ok(thread_builder.build())
}
fn as_posix_thread(&self) -> Option<&PosixThread> {
self.data().downcast_ref::<PosixThread>()
}
}
impl PosixThreadExt for Arc<Task> {
fn as_posix_thread(&self) -> Option<&PosixThread> {
Thread::borrow_from_task(self).as_posix_thread()
}
}
/// Creates a task for running an executable file.
///
/// This function should _only_ be used to create the init user task.
#[allow(clippy::too_many_arguments)]
pub fn create_posix_task_from_executable(
tid: Tid,
credentials: Credentials,
process_vm: &ProcessVm,
fs_resolver: &FsResolver,
executable_path: &str,
process: Weak<Process>,
argv: Vec<CString>,
envp: Vec<CString>,
) -> Result<Arc<Task>> {
let elf_file = {
let fs_path = FsPath::new(AT_FDCWD, executable_path)?;
fs_resolver.lookup(&fs_path)?
};
let (_, elf_load_info) = load_program_to_vm(process_vm, elf_file, argv, envp, fs_resolver, 1)?;
let vm_space = process_vm.root_vmar().vm_space().clone();
let mut cpu_ctx = UserContext::default();
cpu_ctx.set_instruction_pointer(elf_load_info.entry_point() as _);
cpu_ctx.set_stack_pointer(elf_load_info.user_stack_top() as _);
let user_space = Arc::new(UserSpace::new(vm_space, cpu_ctx));
let thread_name = Some(ThreadName::new_from_executable_path(executable_path)?);
let thread_builder = PosixThreadBuilder::new(tid, user_space, credentials)
.thread_name(thread_name)
.process(process);
Ok(thread_builder.build())
}

View File

@ -0,0 +1,22 @@
// SPDX-License-Identifier: MPL-2.0
use super::{Thread, Tid};
use crate::{prelude::*, process::posix_thread::PosixThreadExt};
static THREAD_TABLE: SpinLock<BTreeMap<Tid, Arc<Thread>>> = SpinLock::new(BTreeMap::new());
/// Adds a posix thread to global thread table
pub fn add_thread(tid: Tid, thread: Arc<Thread>) {
debug_assert_eq!(tid, thread.tid());
THREAD_TABLE.lock().insert(tid, thread);
}
/// Removes a posix thread to global thread table
pub fn remove_thread(tid: Tid) {
THREAD_TABLE.lock().remove(&tid);
}
/// Gets a posix thread from the global thread table
pub fn get_thread(tid: Tid) -> Option<Arc<Thread>> {
THREAD_TABLE.lock().get(&tid).cloned()
}

View File

@ -7,14 +7,13 @@ use crate::{
fs::{file_table::FileTable, fs_resolver::FsResolver, utils::FileCreationMask},
prelude::*,
process::{
posix_thread::{PosixThreadBuilder, PosixThreadExt},
posix_thread::{create_posix_task_from_executable, PosixThreadBuilder},
process_vm::ProcessVm,
rlimit::ResourceLimits,
signal::sig_disposition::SigDispositions,
Credentials,
},
sched::nice::Nice,
thread::Thread,
};
pub struct ProcessBuilder<'a> {
@ -190,11 +189,11 @@ impl<'a> ProcessBuilder<'a> {
)
};
let thread = if let Some(thread_builder) = main_thread_builder {
let task = if let Some(thread_builder) = main_thread_builder {
let builder = thread_builder.process(Arc::downgrade(&process));
builder.build()
} else {
Thread::new_posix_thread_from_executable(
create_posix_task_from_executable(
pid,
credentials.unwrap(),
process.vm(),
@ -206,7 +205,7 @@ impl<'a> ProcessBuilder<'a> {
)?
};
process.threads().lock().push(thread);
process.tasks().lock().push(task);
process.set_runnable();

View File

@ -37,7 +37,7 @@ use aster_rights::Full;
use atomic::Atomic;
pub use builder::ProcessBuilder;
pub use job_control::JobControl;
use ostd::sync::WaitQueue;
use ostd::{sync::WaitQueue, task::Task};
pub use process_group::ProcessGroup;
pub use session::Session;
pub use terminal::Terminal;
@ -68,7 +68,7 @@ pub struct Process {
/// The executable path.
executable_path: RwLock<String>,
/// The threads
threads: Mutex<Vec<Arc<Thread>>>,
tasks: Mutex<Vec<Arc<Task>>>,
/// Process status
status: ProcessStatus,
/// Parent process
@ -167,14 +167,20 @@ impl Process {
/// - the function is called in the bootstrap context;
/// - or if the current task is not associated with a process.
pub fn current() -> Option<Arc<Process>> {
Some(Thread::current()?.as_posix_thread()?.process())
Some(
Task::current()?
.data()
.downcast_ref::<Arc<Thread>>()?
.as_posix_thread()?
.process(),
)
}
#[allow(clippy::too_many_arguments)]
fn new(
pid: Pid,
parent: Weak<Process>,
threads: Vec<Arc<Thread>>,
tasks: Vec<Arc<Task>>,
executable_path: String,
process_vm: ProcessVm,
@ -194,7 +200,7 @@ impl Process {
Arc::new_cyclic(|process_ref: &Weak<Process>| Self {
pid,
threads: Mutex::new(threads),
tasks: Mutex::new(tasks),
executable_path: RwLock::new(executable_path),
process_vm,
children_wait_queue,
@ -271,13 +277,14 @@ impl Process {
/// start to run current process
pub fn run(&self) {
let threads = self.threads.lock();
let tasks = self.tasks.lock();
// when run the process, the process should has only one thread
debug_assert!(threads.len() == 1);
debug_assert!(tasks.len() == 1);
debug_assert!(self.is_runnable());
let thread = threads[0].clone();
let task = tasks[0].clone();
// should not hold the lock when run thread
drop(threads);
drop(tasks);
let thread = Thread::borrow_from_task(&task);
thread.run();
}
@ -297,8 +304,8 @@ impl Process {
&self.timer_manager
}
pub fn threads(&self) -> &Mutex<Vec<Arc<Thread>>> {
&self.threads
pub fn tasks(&self) -> &Mutex<Vec<Arc<Task>>> {
&self.tasks
}
pub fn executable_path(&self) -> String {
@ -318,10 +325,11 @@ impl Process {
}
pub fn main_thread(&self) -> Option<Arc<Thread>> {
self.threads
self.tasks
.lock()
.iter()
.find(|thread| thread.tid() == self.pid)
.find(|task| task.tid() == self.pid)
.map(Thread::borrow_from_task)
.cloned()
}
@ -644,7 +652,7 @@ impl Process {
// TODO: check that the signal is not user signal
// Enqueue signal to the first thread that does not block the signal
let threads = self.threads.lock();
let threads = self.tasks.lock();
for thread in threads.iter() {
let posix_thread = thread.as_posix_thread().unwrap();
if !posix_thread.has_signal_blocked(signal.num()) {

View File

@ -86,16 +86,9 @@ impl Pause for Waiter {
return Ok(res);
}
let current_thread = self
.task()
.data()
.downcast_ref::<Weak<Thread>>()
.and_then(|thread| thread.upgrade());
let current_thread = self.task().data().downcast_ref::<Arc<Thread>>();
let Some(posix_thread) = current_thread
.as_ref()
.and_then(|thread| thread.as_posix_thread())
else {
let Some(posix_thread) = current_thread.and_then(|thread| thread.as_posix_thread()) else {
if let Some(timeout) = timeout {
return self.wait_until_or_timeout(cond, timeout);
} else {

View File

@ -5,8 +5,11 @@
use super::{process_filter::ProcessFilter, signal::constants::SIGCHLD, ExitCode, Pid, Process};
use crate::{
prelude::*,
process::{posix_thread::PosixThreadExt, process_table, signal::with_signal_blocked},
thread::thread_table,
process::{
posix_thread::{thread_table, PosixThreadExt},
process_table,
signal::with_signal_blocked,
},
};
// The definition of WaitOptions is from Occlum
@ -85,8 +88,8 @@ pub fn wait_child_exit(
fn reap_zombie_child(process: &Process, pid: Pid) -> ExitCode {
let child_process = process.children().lock().remove(&pid).unwrap();
assert!(child_process.is_zombie());
for thread in &*child_process.threads().lock() {
thread_table::remove_posix_thread(thread.tid());
for task in &*child_process.tasks().lock() {
thread_table::remove_thread(task.tid());
}
// Lock order: session table -> group table -> process table -> group of process