diff --git a/kernel/src/process/clone.rs b/kernel/src/process/clone.rs index c4aaf33b5..f6233f314 100644 --- a/kernel/src/process/clone.rs +++ b/kernel/src/process/clone.rs @@ -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 { 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> { +) -> Result> { 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)?; diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index 8d74f44cc..c0fedd853 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -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); } } diff --git a/kernel/src/process/kill.rs b/kernel/src/process/kill.rs index af734fbff..29cfaf63f 100644 --- a/kernel/src/process/kill.rs +++ b/kernel/src/process/kill.rs @@ -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, 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, 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, ctx: &Context) -> Result<()> { } fn kill_process(process: &Process, signal: Option, 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 diff --git a/kernel/src/process/posix_thread/builder.rs b/kernel/src/process/posix_thread/builder.rs index ae5c76200..c2467fbfd 100644 --- a/kernel/src/process/posix_thread/builder.rs +++ b/kernel/src/process/posix_thread/builder.rs @@ -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 { + pub fn build(self) -> Arc { 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) + }) } } diff --git a/kernel/src/process/posix_thread/exit.rs b/kernel/src/process/posix_thread/exit.rs index 8828a8f41..7143a7b6d 100644 --- a/kernel/src/process/posix_thread/exit.rs +++ b/kernel/src/process/posix_thread/exit.rs @@ -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() { diff --git a/kernel/src/process/posix_thread/mod.rs b/kernel/src/process/posix_thread/mod.rs index 9c202792e..2cef30b22 100644 --- a/kernel/src/process/posix_thread/mod.rs +++ b/kernel/src/process/posix_thread/mod.rs @@ -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. diff --git a/kernel/src/process/posix_thread/posix_thread_ext.rs b/kernel/src/process/posix_thread/posix_thread_ext.rs index eb9a4316d..eac3cbb68 100644 --- a/kernel/src/process/posix_thread/posix_thread_ext.rs +++ b/kernel/src/process/posix_thread/posix_thread_ext.rs @@ -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, - argv: Vec, - envp: Vec, - ) -> Result>; } 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, - argv: Vec, - envp: Vec, - ) -> Result> { - 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::() } } + +impl PosixThreadExt for Arc { + 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, + argv: Vec, + envp: Vec, +) -> Result> { + 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()) +} diff --git a/kernel/src/process/posix_thread/thread_table.rs b/kernel/src/process/posix_thread/thread_table.rs new file mode 100644 index 000000000..fc8f1e88d --- /dev/null +++ b/kernel/src/process/posix_thread/thread_table.rs @@ -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>> = SpinLock::new(BTreeMap::new()); + +/// Adds a posix thread to global thread table +pub fn add_thread(tid: Tid, thread: Arc) { + 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> { + THREAD_TABLE.lock().get(&tid).cloned() +} diff --git a/kernel/src/process/process/builder.rs b/kernel/src/process/process/builder.rs index f645221e6..5f296b694 100644 --- a/kernel/src/process/process/builder.rs +++ b/kernel/src/process/process/builder.rs @@ -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(); diff --git a/kernel/src/process/process/mod.rs b/kernel/src/process/process/mod.rs index d9b368653..b8dc35da3 100644 --- a/kernel/src/process/process/mod.rs +++ b/kernel/src/process/process/mod.rs @@ -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, /// The threads - threads: Mutex>>, + tasks: Mutex>>, /// 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> { - Some(Thread::current()?.as_posix_thread()?.process()) + Some( + Task::current()? + .data() + .downcast_ref::>()? + .as_posix_thread()? + .process(), + ) } #[allow(clippy::too_many_arguments)] fn new( pid: Pid, parent: Weak, - threads: Vec>, + tasks: Vec>, executable_path: String, process_vm: ProcessVm, @@ -194,7 +200,7 @@ impl Process { Arc::new_cyclic(|process_ref: &Weak| 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>> { - &self.threads + pub fn tasks(&self) -> &Mutex>> { + &self.tasks } pub fn executable_path(&self) -> String { @@ -318,10 +325,11 @@ impl Process { } pub fn main_thread(&self) -> Option> { - 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()) { diff --git a/kernel/src/process/signal/pause.rs b/kernel/src/process/signal/pause.rs index f00375263..f9e686ff8 100644 --- a/kernel/src/process/signal/pause.rs +++ b/kernel/src/process/signal/pause.rs @@ -86,16 +86,9 @@ impl Pause for Waiter { return Ok(res); } - let current_thread = self - .task() - .data() - .downcast_ref::>() - .and_then(|thread| thread.upgrade()); + let current_thread = self.task().data().downcast_ref::>(); - 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 { diff --git a/kernel/src/process/wait.rs b/kernel/src/process/wait.rs index d89724de6..3dfe35d79 100644 --- a/kernel/src/process/wait.rs +++ b/kernel/src/process/wait.rs @@ -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 diff --git a/kernel/src/syscall/clock_gettime.rs b/kernel/src/syscall/clock_gettime.rs index d15247977..725e2dc96 100644 --- a/kernel/src/syscall/clock_gettime.rs +++ b/kernel/src/syscall/clock_gettime.rs @@ -7,8 +7,10 @@ use int_to_c_enum::TryFromInt; use super::SyscallReturn; use crate::{ prelude::*, - process::{posix_thread::PosixThreadExt, process_table}, - thread::thread_table, + process::{ + posix_thread::{thread_table, PosixThreadExt}, + process_table, + }, time::{ clockid_t, clocks::{ @@ -136,7 +138,7 @@ pub fn read_clock(clockid: clockid_t, ctx: &Context) -> Result { } } DynamicClockIdInfo::Tid(tid, clock_type) => { - let thread = thread_table::get_posix_thread(tid) + let thread = thread_table::get_thread(tid) .ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid clock ID"))?; let posix_thread = thread.as_posix_thread().unwrap(); match clock_type { diff --git a/kernel/src/syscall/timer_create.rs b/kernel/src/syscall/timer_create.rs index da42201d8..5723e36bb 100644 --- a/kernel/src/syscall/timer_create.rs +++ b/kernel/src/syscall/timer_create.rs @@ -7,7 +7,7 @@ use super::{ use crate::{ prelude::*, process::{ - posix_thread::PosixThreadExt, + posix_thread::{thread_table, PosixThreadExt}, process_table, signal::{ c_types::{sigevent_t, SigNotify}, @@ -17,10 +17,7 @@ use crate::{ }, }, syscall::ClockId, - thread::{ - thread_table, - work_queue::{submit_work_item, work_item::WorkItem}, - }, + thread::work_queue::{submit_work_item, work_item::WorkItem}, time::{ clockid_t, clocks::{BootTimeClock, MonotonicClock, RealTimeClock}, @@ -76,7 +73,7 @@ pub fn sys_timer_create( // Send a signal to the specified thread when the timer is expired. SigNotify::SIGEV_THREAD_ID => { let tid = sig_event.sigev_un.read_tid() as u32; - let thread = thread_table::get_posix_thread(tid).ok_or_else(|| { + let thread = thread_table::get_thread(tid).ok_or_else(|| { Error::with_message(Errno::EINVAL, "target thread does not exist") })?; let posix_thread = thread.as_posix_thread().unwrap(); @@ -132,7 +129,7 @@ pub fn sys_timer_create( } } DynamicClockIdInfo::Tid(tid, clock_type) => { - let thread = thread_table::get_posix_thread(tid) + let thread = thread_table::get_thread(tid) .ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid clock id"))?; let posix_thread = thread.as_posix_thread().unwrap(); match clock_type { diff --git a/kernel/src/thread/kernel_thread.rs b/kernel/src/thread/kernel_thread.rs index 332c04771..e613ceccf 100644 --- a/kernel/src/thread/kernel_thread.rs +++ b/kernel/src/thread/kernel_thread.rs @@ -2,23 +2,22 @@ use ostd::{ cpu::CpuSet, - task::{Priority, TaskOptions}, + task::{Priority, Task, TaskOptions}, }; -use super::{status::ThreadStatus, thread_table, Thread}; +use super::{status::ThreadStatus, Thread}; use crate::prelude::*; /// The inner data of a kernel thread pub struct KernelThread; pub trait KernelThreadExt { - /// get the kernel_thread structure + /// Gets the kernel_thread structure fn as_kernel_thread(&self) -> Option<&KernelThread>; - /// create a new kernel thread structure, **NOT** run the thread. - fn new_kernel_thread(thread_options: ThreadOptions) -> Arc; - /// create a new kernel thread structure, and then run the thread. + /// Creates a new kernel thread, and then run the thread. fn spawn_kernel_thread(thread_options: ThreadOptions) -> Arc { - let thread = Self::new_kernel_thread(thread_options); + let task = create_new_kernel_task(thread_options); + let thread = Thread::borrow_from_task(&task).clone(); thread.run(); thread } @@ -31,31 +30,6 @@ impl KernelThreadExt for Thread { self.data().downcast_ref::() } - fn new_kernel_thread(mut thread_options: ThreadOptions) -> Arc { - let task_fn = thread_options.take_func(); - let thread_fn = move || { - task_fn(); - let current_thread = current_thread!(); - // ensure the thread is exit - current_thread.exit(); - thread_table::remove_kernel_thread(current_thread); - }; - let thread = Arc::new_cyclic(|thread_ref| { - let weak_thread = thread_ref.clone(); - let task = TaskOptions::new(thread_fn) - .data(weak_thread) - .priority(thread_options.priority) - .cpu_affinity(thread_options.cpu_affinity) - .build() - .unwrap(); - let status = ThreadStatus::Init; - let kernel_thread = KernelThread; - Thread::new(task, kernel_thread, status) - }); - thread_table::add_kernel_thread(thread.clone()); - thread - } - fn join(&self) { loop { if self.status().is_exited() { @@ -67,6 +41,31 @@ impl KernelThreadExt for Thread { } } +/// Creates a new task of kernel thread, **NOT** run the thread. +pub fn create_new_kernel_task(mut thread_options: ThreadOptions) -> Arc { + let task_fn = thread_options.take_func(); + let thread_fn = move || { + task_fn(); + // Ensures the thread is exit + current_thread!().exit(); + }; + + Arc::new_cyclic(|weak_task| { + let thread = { + let kernel_thread = KernelThread; + let status = ThreadStatus::Init; + Arc::new(Thread::new(weak_task.clone(), kernel_thread, status)) + }; + + TaskOptions::new(thread_fn) + .data(thread) + .priority(thread_options.priority) + .cpu_affinity(thread_options.cpu_affinity) + .build() + .unwrap() + }) +} + /// Options to create or spawn a new thread. pub struct ThreadOptions { func: Option>, diff --git a/kernel/src/thread/mod.rs b/kernel/src/thread/mod.rs index 177eaf109..43f27d59f 100644 --- a/kernel/src/thread/mod.rs +++ b/kernel/src/thread/mod.rs @@ -13,7 +13,6 @@ pub mod exception; pub mod kernel_thread; pub mod status; pub mod task; -pub mod thread_table; pub mod work_queue; pub type Tid = u32; @@ -22,7 +21,7 @@ pub type Tid = u32; pub struct Thread { // immutable part /// Low-level info - task: Arc, + task: Weak, /// Data: Posix thread info/Kernel thread Info data: Box, @@ -32,7 +31,7 @@ pub struct Thread { impl Thread { /// Never call these function directly - pub fn new(task: Arc, data: impl Send + Sync + Any, status: ThreadStatus) -> Self { + pub fn new(task: Weak, data: impl Send + Sync + Any, status: ThreadStatus) -> Self { Thread { task, data: Box::new(data), @@ -47,18 +46,23 @@ impl Thread { pub fn current() -> Option> { Task::current()? .data() - .downcast_ref::>()? - .upgrade() + .downcast_ref::>() + .cloned() } - pub(in crate::thread) fn task(&self) -> &Arc { - &self.task + /// Gets the Thread from task's data. + /// + /// # Panics + /// + /// This method panics if the task is not a thread. + pub fn borrow_from_task(task: &Arc) -> &Arc { + task.data().downcast_ref::>().unwrap() } /// Runs this thread at once. pub fn run(&self) { self.set_status(ThreadStatus::Running); - self.task.run(); + self.task.upgrade().unwrap().run(); } pub(super) fn exit(&self) { diff --git a/kernel/src/thread/task.rs b/kernel/src/thread/task.rs index 35ffa0e66..ee8b120d8 100644 --- a/kernel/src/thread/task.rs +++ b/kernel/src/thread/task.rs @@ -16,12 +16,12 @@ use crate::{ }; /// create new task with userspace and parent process -pub fn create_new_user_task(user_space: Arc, thread_ref: Weak) -> Arc { +pub fn create_new_user_task(user_space: Arc, thread_ref: Arc) -> Task { fn user_task_entry() { let current_thread = current_thread!(); let current_posix_thread = current_thread.as_posix_thread().unwrap(); let current_process = current_posix_thread.process(); - let current_task = current_thread.task(); + let current_task = Task::current().unwrap(); let user_space = current_task .user_space() diff --git a/kernel/src/thread/thread_table.rs b/kernel/src/thread/thread_table.rs deleted file mode 100644 index 2dcb68d34..000000000 --- a/kernel/src/thread/thread_table.rs +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -use keyable_arc::KeyableArc; - -use super::{Thread, Tid}; -use crate::{prelude::*, process::posix_thread::PosixThreadExt}; - -static POSIX_THREAD_TABLE: SpinLock>> = SpinLock::new(BTreeMap::new()); -static KERNEL_THREAD_TABLE: SpinLock>> = SpinLock::new(BTreeSet::new()); - -pub fn add_posix_thread(tid: Tid, thread: Arc) { - debug_assert_eq!(tid, thread.tid()); - POSIX_THREAD_TABLE.lock().insert(tid, thread); -} - -pub fn remove_posix_thread(tid: Tid) { - POSIX_THREAD_TABLE.lock().remove(&tid); -} - -pub fn get_posix_thread(tid: Tid) -> Option> { - POSIX_THREAD_TABLE.lock().get(&tid).cloned() -} - -pub(super) fn add_kernel_thread(thread: Arc) { - KERNEL_THREAD_TABLE.lock().insert(KeyableArc::from(thread)); -} - -pub(super) fn remove_kernel_thread(thread: Arc) { - KERNEL_THREAD_TABLE.lock().remove(&KeyableArc::from(thread)); -} diff --git a/kernel/src/thread/work_queue/worker.rs b/kernel/src/thread/work_queue/worker.rs index 173af08f9..0a38c2944 100644 --- a/kernel/src/thread/work_queue/worker.rs +++ b/kernel/src/thread/work_queue/worker.rs @@ -2,12 +2,15 @@ #![allow(dead_code)] -use ostd::{cpu::CpuSet, task::Priority}; +use ostd::{ + cpu::CpuSet, + task::{Priority, Task}, +}; use super::worker_pool::WorkerPool; use crate::{ prelude::*, - thread::kernel_thread::{KernelThreadExt, ThreadOptions}, + thread::kernel_thread::{create_new_kernel_task, ThreadOptions}, Thread, }; @@ -17,7 +20,7 @@ use crate::{ /// added to the `WorkerPool`. pub(super) struct Worker { worker_pool: Weak, - bound_thread: Arc, + bound_task: Arc, bound_cpu: u32, inner: SpinLock, } @@ -51,14 +54,14 @@ impl Worker { if worker_pool.upgrade().unwrap().is_high_priority() { priority = Priority::high(); } - let bound_thread = Thread::new_kernel_thread( + let bound_task = create_new_kernel_task( ThreadOptions::new(task_fn) .cpu_affinity(cpu_affinity) .priority(priority), ); Self { worker_pool, - bound_thread, + bound_task, bound_cpu, inner: SpinLock::new(WorkerInner { worker_status: WorkerStatus::Running, @@ -68,7 +71,8 @@ impl Worker { } pub(super) fn run(&self) { - self.bound_thread.run(); + let thread = Thread::borrow_from_task(&self.bound_task); + thread.run(); } /// The thread function bound to normal workers. @@ -97,8 +101,8 @@ impl Worker { self.exit(); } - pub(super) fn bound_thread(&self) -> &Arc { - &self.bound_thread + pub(super) fn bound_task(&self) -> &Arc { + &self.bound_task } pub(super) fn is_idle(&self) -> bool { diff --git a/kernel/src/thread/work_queue/worker_pool.rs b/kernel/src/thread/work_queue/worker_pool.rs index c1a5b467d..6b9425d37 100644 --- a/kernel/src/thread/work_queue/worker_pool.rs +++ b/kernel/src/thread/work_queue/worker_pool.rs @@ -7,12 +7,16 @@ use core::{ time::Duration, }; -use ostd::{cpu::CpuSet, sync::WaitQueue, task::Priority}; +use ostd::{ + cpu::CpuSet, + sync::WaitQueue, + task::{Priority, Task}, +}; use super::{simple_scheduler::SimpleScheduler, worker::Worker, WorkItem, WorkPriority, WorkQueue}; use crate::{ prelude::*, - thread::kernel_thread::{KernelThreadExt, ThreadOptions}, + thread::kernel_thread::{create_new_kernel_task, ThreadOptions}, Thread, }; @@ -60,7 +64,7 @@ pub trait WorkerScheduler: Sync + Send { /// are found processing in the pool. pub struct Monitor { worker_pool: Weak, - bound_thread: Arc, + bound_task: Arc, } impl LocalWorkerPool { @@ -77,7 +81,7 @@ impl LocalWorkerPool { fn add_worker(&self) { let worker = Worker::new(self.parent.clone(), self.cpu_id); self.workers.disable_irq().lock().push_back(worker.clone()); - worker.bound_thread().run(); + Thread::borrow_from_task(worker.bound_task()).run(); } fn remove_worker(&self) { @@ -236,20 +240,20 @@ impl Monitor { WorkPriority::High => Priority::high(), WorkPriority::Normal => Priority::normal(), }; - let bound_thread = Thread::new_kernel_thread( + let bound_task = create_new_kernel_task( ThreadOptions::new(task_fn) .cpu_affinity(cpu_affinity) .priority(priority), ); Self { worker_pool, - bound_thread, + bound_task, } }) } pub fn run(&self) { - self.bound_thread.run(); + Thread::borrow_from_task(&self.bound_task).run() } fn run_monitor_loop(self: &Arc) { diff --git a/osdk/tests/examples_in_book/write_a_kernel_in_100_lines_templates/lib.rs b/osdk/tests/examples_in_book/write_a_kernel_in_100_lines_templates/lib.rs index 23618110b..7c7c9f434 100644 --- a/osdk/tests/examples_in_book/write_a_kernel_in_100_lines_templates/lib.rs +++ b/osdk/tests/examples_in_book/write_a_kernel_in_100_lines_templates/lib.rs @@ -102,11 +102,13 @@ fn create_user_task(user_space: Arc) -> Arc { // Kernel tasks are managed by the Framework, // while scheduling algorithms for them can be // determined by the users of the Framework. - TaskOptions::new(user_task) - .user_space(Some(user_space)) - .data(0) - .build() - .unwrap() + Arc::new( + TaskOptions::new(user_task) + .user_space(Some(user_space)) + .data(0) + .build() + .unwrap(), + ) } fn handle_syscall(user_context: &mut UserContext, user_space: &UserSpace) { diff --git a/ostd/src/task/mod.rs b/ostd/src/task/mod.rs index 253caf09a..e99da2ba7 100644 --- a/ostd/src/task/mod.rs +++ b/ostd/src/task/mod.rs @@ -166,7 +166,7 @@ impl TaskOptions { } /// Builds a new task without running it immediately. - pub fn build(self) -> Result> { + pub fn build(self) -> Result { /// all task will entering this function /// this function is mean to executing the task_fn in Task extern "C" fn kernel_task_entry() { @@ -201,12 +201,12 @@ impl TaskOptions { // have any arguments, so we only need to align the stack pointer to 16 bytes. ctx.set_stack_pointer(crate::mm::paddr_to_vaddr(new_task.kstack.end_paddr() - 16)); - Ok(Arc::new(new_task)) + Ok(new_task) } /// Builds a new task and run it immediately. pub fn spawn(self) -> Result> { - let task = self.build()?; + let task = Arc::new(self.build()?); task.run(); Ok(task) } @@ -237,11 +237,13 @@ mod test { let task = || { assert_eq!(1, 1); }; - let task_option = crate::task::TaskOptions::new(task) - .data(()) - .build() - .unwrap(); - task_option.run(); + let task = Arc::new( + crate::task::TaskOptions::new(task) + .data(()) + .build() + .unwrap(), + ); + task.run(); } #[ktest]