diff --git a/kernel/src/fs/mod.rs b/kernel/src/fs/mod.rs index 3cdd46d8b..01b223fa0 100644 --- a/kernel/src/fs/mod.rs +++ b/kernel/src/fs/mod.rs @@ -26,7 +26,6 @@ use crate::{ fs_resolver::FsPath, }, prelude::*, - thread::kernel_thread::KernelThreadExt, }; fn start_block_device(device_name: &str) -> Result> { @@ -39,7 +38,7 @@ fn start_block_device(device_name: &str) -> Result> { virtio_block_device.handle_requests(); } }; - crate::Thread::spawn_kernel_thread(crate::ThreadOptions::new(task_fn)); + crate::ThreadOptions::new(task_fn).spawn(); Ok(device) } else { return_errno_with_message!(Errno::ENOENT, "Device does not exist") diff --git a/kernel/src/fs/pipe.rs b/kernel/src/fs/pipe.rs index c4ae5ce0b..635e6b2af 100644 --- a/kernel/src/fs/pipe.rs +++ b/kernel/src/fs/pipe.rs @@ -200,10 +200,7 @@ mod test { use super::*; use crate::{ fs::utils::Channel, - thread::{ - kernel_thread::{KernelThreadExt, ThreadOptions}, - Thread, - }, + thread::{kernel_thread::ThreadOptions, Thread}, }; #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -232,7 +229,7 @@ mod test { let signal_writer = Arc::new(AtomicBool::new(false)); let signal_reader = signal_writer.clone(); - let writer = Thread::spawn_kernel_thread(ThreadOptions::new(move || { + let writer = ThreadOptions::new(move || { let writer = writer_with_lock.lock().take().unwrap(); if ordering == Ordering::ReadThenWrite { @@ -244,9 +241,10 @@ mod test { } write(writer); - })); + }) + .spawn(); - let reader = Thread::spawn_kernel_thread(ThreadOptions::new(move || { + let reader = ThreadOptions::new(move || { let reader = reader_with_lock.lock().take().unwrap(); if ordering == Ordering::WriteThenRead { @@ -258,7 +256,8 @@ mod test { } read(reader); - })); + }) + .spawn(); writer.join(); reader.join(); diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 861e40c22..9487e67a7 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -43,10 +43,7 @@ use sched::priority::PriorityRange; use crate::{ prelude::*, sched::priority::Priority, - thread::{ - kernel_thread::{KernelThreadExt, ThreadOptions}, - Thread, - }, + thread::{kernel_thread::ThreadOptions, Thread}, }; extern crate alloc; @@ -89,10 +86,9 @@ pub fn main() { ostd::boot::smp::register_ap_entry(ap_init); // Spawn the first kernel thread on BSP. - Thread::spawn_kernel_thread( - ThreadOptions::new(init_thread) - .priority(Priority::new(PriorityRange::new(PriorityRange::MAX))), - ); + ThreadOptions::new(init_thread) + .priority(Priority::new(PriorityRange::new(PriorityRange::MAX))) + .spawn(); } pub fn init() { @@ -122,11 +118,10 @@ fn ap_init() { let cpu_id = preempt_guard.current_cpu(); drop(preempt_guard); - Thread::spawn_kernel_thread( - ThreadOptions::new(ap_idle_thread) - .cpu_affinity(cpu_id.into()) - .priority(Priority::new(PriorityRange::new(PriorityRange::MAX))), - ); + ThreadOptions::new(ap_idle_thread) + .cpu_affinity(cpu_id.into()) + .priority(Priority::new(PriorityRange::new(PriorityRange::MAX))) + .spawn(); } fn init_thread() { @@ -139,9 +134,10 @@ fn init_thread() { fs::lazy_init(); ipc::init(); // driver::pci::virtio::block::block_device_test(); - let thread = Thread::spawn_kernel_thread(ThreadOptions::new(|| { + let thread = ThreadOptions::new(|| { println!("[kernel] Hello world from kernel!"); - })); + }) + .spawn(); thread.join(); print_banner(); diff --git a/kernel/src/net/iface/poll.rs b/kernel/src/net/iface/poll.rs index f46284e3d..fb783f082 100644 --- a/kernel/src/net/iface/poll.rs +++ b/kernel/src/net/iface/poll.rs @@ -9,10 +9,7 @@ use ostd::timer::Jiffies; use super::{ext::IfaceEx, Iface, IFACES}; use crate::{ sched::priority::{Priority, PriorityRange}, - thread::{ - kernel_thread::{KernelThreadExt, ThreadOptions}, - Thread, - }, + thread::kernel_thread::ThreadOptions, WaitTimeout, }; @@ -70,6 +67,7 @@ fn spawn_background_poll_thread(iface: Arc) { }; // FIXME: remove the use of real-time priority. - let options = ThreadOptions::new(task_fn).priority(Priority::new(PriorityRange::new(0))); - Thread::spawn_kernel_thread(options); + ThreadOptions::new(task_fn) + .priority(Priority::new(PriorityRange::new(0))) + .spawn(); } diff --git a/kernel/src/process/signal/pause.rs b/kernel/src/process/signal/pause.rs index 17ab54278..40f0150c4 100644 --- a/kernel/src/process/signal/pause.rs +++ b/kernel/src/process/signal/pause.rs @@ -217,10 +217,7 @@ mod test { use ostd::prelude::*; use super::*; - use crate::thread::{ - kernel_thread::{KernelThreadExt, ThreadOptions}, - Thread, - }; + use crate::thread::{kernel_thread::ThreadOptions, Thread}; #[ktest] fn test_waiter_pause() { @@ -230,12 +227,13 @@ mod test { let boolean = Arc::new(AtomicBool::new(false)); let boolean_cloned = boolean.clone(); - let thread = Thread::spawn_kernel_thread(ThreadOptions::new(move || { + let thread = ThreadOptions::new(move || { Thread::yield_now(); boolean_cloned.store(true, Ordering::Relaxed); wait_queue_cloned.wake_all(); - })); + }) + .spawn(); wait_queue .pause_until(|| boolean.load(Ordering::Relaxed).then_some(())) diff --git a/kernel/src/process/sync/condvar.rs b/kernel/src/process/sync/condvar.rs index b4cbde7af..c28fa52dd 100644 --- a/kernel/src/process/sync/condvar.rs +++ b/kernel/src/process/sync/condvar.rs @@ -52,20 +52,21 @@ impl LockErr { /// ```rust /// use alloc::sync::Arc; /// use ostd::sync::Mutex; -/// use crate::{process::sync::Condvar, thread::{kernel_thread::KernelThreadExt, Thread}}; +/// use crate::{process::sync::Condvar, thread::kernel_thread::Thread}; /// /// // Initializing a shared condition between threads /// let pair = Arc::new((Mutex::new(false), Condvar::new())); /// let pair2 = Arc::clone(&pair); /// /// // Spawning a new kernel thread to change a shared state and notify the Condvar -/// Thread::spawn_kernel_thread(ThreadOptions::new(move || { +/// ThreadOptions::new(move || { /// let (lock, cvar) = &*pair2; /// Thread::yield_now(); /// let mut started = lock.lock(); /// *started = true; // Modifying the shared state /// cvar.notify_one(); // Notifying one waiting thread -/// })); +/// }) +/// .spawn(); /// /// // Main thread waiting for the shared state to be set to true /// { @@ -267,23 +268,21 @@ mod test { use ostd::{prelude::*, sync::Mutex}; use super::*; - use crate::thread::{ - kernel_thread::{KernelThreadExt, ThreadOptions}, - Thread, - }; + use crate::thread::{kernel_thread::ThreadOptions, Thread}; #[ktest] fn test_condvar_wait() { let pair = Arc::new((Mutex::new(false), Condvar::new())); let pair2 = Arc::clone(&pair); - Thread::spawn_kernel_thread(ThreadOptions::new(move || { + ThreadOptions::new(move || { Thread::yield_now(); let (lock, cvar) = &*pair2; let mut started = lock.lock(); *started = true; cvar.notify_one(); - })); + }) + .spawn(); { let (lock, cvar) = &*pair; @@ -300,13 +299,14 @@ mod test { let pair = Arc::new((Mutex::new(false), Condvar::new())); let pair2 = Arc::clone(&pair); - Thread::spawn_kernel_thread(ThreadOptions::new(move || { + ThreadOptions::new(move || { Thread::yield_now(); let (lock, cvar) = &*pair2; let mut started = lock.lock(); *started = true; cvar.notify_one(); - })); + }) + .spawn(); { let (lock, cvar) = &*pair; @@ -325,13 +325,14 @@ mod test { let pair = Arc::new((Mutex::new(true), Condvar::new())); let pair2 = Arc::clone(&pair); - Thread::spawn_kernel_thread(ThreadOptions::new(move || { + ThreadOptions::new(move || { Thread::yield_now(); let (lock, cvar) = &*pair2; let mut started = lock.lock(); *started = false; cvar.notify_one(); - })); + }) + .spawn(); { let (lock, cvar) = &*pair; @@ -347,13 +348,14 @@ mod test { let pair = Arc::new((Mutex::new(true), Condvar::new())); let pair2 = Arc::clone(&pair); - Thread::spawn_kernel_thread(ThreadOptions::new(move || { + ThreadOptions::new(move || { Thread::yield_now(); let (lock, cvar) = &*pair2; let mut started = lock.lock(); *started = false; cvar.notify_one(); - })); + }) + .spawn(); { let (lock, cvar) = &*pair; diff --git a/kernel/src/thread/kernel_thread.rs b/kernel/src/thread/kernel_thread.rs index 477d64e6d..1f0336b38 100644 --- a/kernel/src/thread/kernel_thread.rs +++ b/kernel/src/thread/kernel_thread.rs @@ -8,68 +8,10 @@ use ostd::{ use super::{oops, status::ThreadStatus, Thread}; use crate::{prelude::*, sched::priority::Priority}; -/// The inner data of a kernel thread -pub struct KernelThread; +/// The inner data of a kernel thread. +struct KernelThread; -pub trait KernelThreadExt { - /// Gets the kernel_thread structure - fn as_kernel_thread(&self) -> Option<&KernelThread>; - /// Creates a new kernel thread, and then run the thread. - fn spawn_kernel_thread(thread_options: ThreadOptions) -> Arc { - let task = create_new_kernel_task(thread_options); - let thread = Thread::borrow_from_task(&task).clone(); - thread.run(); - thread - } - /// join a kernel thread, returns if the kernel thread exit - fn join(&self); -} - -impl KernelThreadExt for Thread { - fn as_kernel_thread(&self) -> Option<&KernelThread> { - self.data().downcast_ref::() - } - - fn join(&self) { - loop { - if self.is_exited() { - return; - } else { - Thread::yield_now(); - } - } - } -} - -/// 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 || { - let _ = oops::catch_panics_as_oops(task_fn); - // Ensure that the thread exits. - current_thread!().exit(); - }; - - Arc::new_cyclic(|weak_task| { - let thread = { - let kernel_thread = KernelThread; - let status = ThreadStatus::Init; - let priority = thread_options.priority; - let cpu_affinity = thread_options.cpu_affinity; - Arc::new(Thread::new( - weak_task.clone(), - kernel_thread, - status, - priority, - cpu_affinity, - )) - }; - - TaskOptions::new(thread_fn).data(thread).build().unwrap() - }) -} - -/// Options to create or spawn a new thread. +/// Options to create or spawn a new kernel thread. pub struct ThreadOptions { func: Option>, priority: Priority, @@ -77,6 +19,7 @@ pub struct ThreadOptions { } impl ThreadOptions { + /// Creates the thread options with the thread function. pub fn new(func: F) -> Self where F: Fn() + Send + Sync + 'static, @@ -89,25 +32,53 @@ impl ThreadOptions { } } - pub fn func(mut self, func: F) -> Self - where - F: Fn() + Send + Sync + 'static, - { - self.func = Some(Box::new(func)); - self - } - - fn take_func(&mut self) -> Box { - self.func.take().unwrap() - } - + /// Sets the priority of the new thread. pub fn priority(mut self, priority: Priority) -> Self { self.priority = priority; self } + /// Sets the CPU affinity of the new thread. pub fn cpu_affinity(mut self, cpu_affinity: CpuSet) -> Self { self.cpu_affinity = cpu_affinity; self } } + +impl ThreadOptions { + /// Builds a new kernel thread without running it immediately. + pub fn build(mut self) -> Arc { + let task_fn = self.func.take().unwrap(); + let thread_fn = move || { + let _ = oops::catch_panics_as_oops(task_fn); + // Ensure that the thread exits. + current_thread!().exit(); + }; + + Arc::new_cyclic(|weak_task| { + let thread = { + let kernel_thread = KernelThread; + let status = ThreadStatus::Init; + let priority = self.priority; + let cpu_affinity = self.cpu_affinity; + Arc::new(Thread::new( + weak_task.clone(), + kernel_thread, + status, + priority, + cpu_affinity, + )) + }; + + TaskOptions::new(thread_fn).data(thread).build().unwrap() + }) + } + + /// Builds a new kernel thread and runs it immediately. + pub fn spawn(self) -> Arc { + let task = self.build(); + let thread = Thread::borrow_from_task(&task).clone(); + thread.run(); + thread + } +} diff --git a/kernel/src/thread/mod.rs b/kernel/src/thread/mod.rs index dd2e0df07..64dc40e8e 100644 --- a/kernel/src/thread/mod.rs +++ b/kernel/src/thread/mod.rs @@ -152,10 +152,22 @@ impl Thread { &self.cpu_affinity } + /// Yields the execution to another thread. + /// + /// This method will return once the current thread is scheduled again. pub fn yield_now() { Task::yield_now() } + /// Joins the execution of the thread. + /// + /// This method will return after the thread exits. + pub fn join(&self) { + while !self.is_exited() { + Self::yield_now(); + } + } + /// Returns the associated data. pub fn data(&self) -> &(dyn Send + Sync + Any) { &*self.data diff --git a/kernel/src/thread/work_queue/worker.rs b/kernel/src/thread/work_queue/worker.rs index 685a68f94..a74af943f 100644 --- a/kernel/src/thread/work_queue/worker.rs +++ b/kernel/src/thread/work_queue/worker.rs @@ -11,7 +11,7 @@ use super::worker_pool::WorkerPool; use crate::{ prelude::*, sched::priority::{Priority, PriorityRange}, - thread::kernel_thread::{create_new_kernel_task, ThreadOptions}, + thread::kernel_thread::ThreadOptions, Thread, }; @@ -56,11 +56,10 @@ impl Worker { // FIXME: remove the use of real-time priority. priority = Priority::new(PriorityRange::new(0)); } - let bound_task = create_new_kernel_task( - ThreadOptions::new(task_fn) - .cpu_affinity(cpu_affinity) - .priority(priority), - ); + let bound_task = ThreadOptions::new(task_fn) + .cpu_affinity(cpu_affinity) + .priority(priority) + .build(); Self { worker_pool, bound_task, diff --git a/kernel/src/thread/work_queue/worker_pool.rs b/kernel/src/thread/work_queue/worker_pool.rs index 6476e7281..26c583c94 100644 --- a/kernel/src/thread/work_queue/worker_pool.rs +++ b/kernel/src/thread/work_queue/worker_pool.rs @@ -17,7 +17,7 @@ use super::{simple_scheduler::SimpleScheduler, worker::Worker, WorkItem, WorkPri use crate::{ prelude::*, sched::priority::{Priority, PriorityRange}, - thread::kernel_thread::{create_new_kernel_task, ThreadOptions}, + thread::kernel_thread::ThreadOptions, Thread, }; @@ -246,11 +246,10 @@ impl Monitor { WorkPriority::High => Priority::new(PriorityRange::new(0)), WorkPriority::Normal => Priority::default(), }; - let bound_task = create_new_kernel_task( - ThreadOptions::new(task_fn) - .cpu_affinity(cpu_affinity) - .priority(priority), - ); + let bound_task = ThreadOptions::new(task_fn) + .cpu_affinity(cpu_affinity) + .priority(priority) + .build(); Self { worker_pool, bound_task, diff --git a/ostd/src/task/mod.rs b/ostd/src/task/mod.rs index 1fb81183e..3b28385f6 100644 --- a/ostd/src/task/mod.rs +++ b/ostd/src/task/mod.rs @@ -215,7 +215,7 @@ impl TaskOptions { Ok(new_task) } - /// Builds a new task and run it immediately. + /// Builds a new task and runs it immediately. pub fn spawn(self) -> Result> { let task = Arc::new(self.build()?); task.run();