diff --git a/src/arch/x86_64/kernel/apic.rs b/src/arch/x86_64/kernel/apic.rs index fc8804b25a..6f4850f3b8 100644 --- a/src/arch/x86_64/kernel/apic.rs +++ b/src/arch/x86_64/kernel/apic.rs @@ -225,6 +225,8 @@ extern "x86-interrupt" fn spurious_interrupt_handler(stack_frame: interrupts::Ex #[cfg(feature = "smp")] extern "x86-interrupt" fn wakeup_handler(_stack_frame: interrupts::ExceptionStackFrame) { + use crate::scheduler::PerCoreSchedulerExt; + debug!("Received Wakeup Interrupt"); increment_irq_counter(WAKEUP_INTERRUPT_NUMBER); let core_scheduler = core_scheduler(); diff --git a/src/arch/x86_64/kernel/scheduler.rs b/src/arch/x86_64/kernel/scheduler.rs index 41d11e3954..10fb48708b 100644 --- a/src/arch/x86_64/kernel/scheduler.rs +++ b/src/arch/x86_64/kernel/scheduler.rs @@ -16,6 +16,7 @@ use crate::arch::x86_64::mm::{PhysAddr, VirtAddr}; use crate::config::*; use crate::kernel; use crate::scheduler::task::{Task, TaskFrame}; +use crate::scheduler::PerCoreSchedulerExt; #[repr(C, packed)] struct State { diff --git a/src/drivers/net/mod.rs b/src/drivers/net/mod.rs index 64fbe47305..1144912e99 100644 --- a/src/drivers/net/mod.rs +++ b/src/drivers/net/mod.rs @@ -70,6 +70,8 @@ pub(crate) fn network_irqhandler(_state: &State) -> bool { #[cfg(target_arch = "x86_64")] pub(crate) extern "x86-interrupt" fn network_irqhandler(_stack_frame: ExceptionStackFrame) { + use crate::scheduler::PerCoreSchedulerExt; + debug!("Receive network interrupt"); apic::eoi(); let _ = _irqhandler(); diff --git a/src/executor/network.rs b/src/executor/network.rs index 22d98ca2ff..78122626e5 100644 --- a/src/executor/network.rs +++ b/src/executor/network.rs @@ -29,6 +29,7 @@ use crate::drivers::net::NetworkDriver; use crate::drivers::pci::get_network_driver; use crate::executor::device::HermitNet; use crate::executor::{spawn, TaskNotify}; +use crate::scheduler::PerCoreSchedulerExt; pub(crate) enum NetworkState<'a> { Missing, diff --git a/src/lib.rs b/src/lib.rs index 29cb0edf2b..a9c1d34b30 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,6 +56,7 @@ use mm::allocator::LockedAllocator; pub(crate) use crate::arch::*; pub(crate) use crate::config::*; use crate::kernel::is_uhyve_with_pci; +use crate::scheduler::PerCoreSchedulerExt; pub use crate::syscalls::*; #[macro_use] diff --git a/src/scheduler/mod.rs b/src/scheduler/mod.rs index 03eae19910..26dc21b1d4 100644 --- a/src/scheduler/mod.rs +++ b/src/scheduler/mod.rs @@ -76,6 +76,112 @@ pub struct PerCoreScheduler { blocked_tasks: BlockedTaskQueue, } +pub trait PerCoreSchedulerExt { + /// Triggers the scheduler to reschedule the tasks. + /// Interrupt flag will be cleared during the reschedule + fn reschedule(self); + + #[cfg(any(feature = "tcp", feature = "udp"))] + fn add_network_timer(self, wakeup_time: Option); + + /// Terminate the current task on the current core. + fn exit(self, exit_code: i32) -> !; +} + +impl PerCoreSchedulerExt for &mut PerCoreScheduler { + #[cfg(target_arch = "x86_64")] + fn reschedule(self) { + without_interrupts(|| { + if let Some(last_stack_pointer) = self.scheduler() { + let (new_stack_pointer, is_idle) = { + let borrowed = self.current_task.borrow(); + ( + borrowed.last_stack_pointer, + borrowed.status == TaskStatus::Idle, + ) + }; + + if is_idle || Rc::ptr_eq(&self.current_task, &self.fpu_owner) { + unsafe { + switch_to_fpu_owner(last_stack_pointer, new_stack_pointer.as_usize()); + } + } else { + unsafe { + switch_to_task(last_stack_pointer, new_stack_pointer.as_usize()); + } + } + } + }) + } + + /// Trigger an interrupt to reschedule the system + #[cfg(target_arch = "aarch64")] + fn reschedule(self) { + use core::arch::asm; + + use arm_gic::gicv3::{GicV3, IntId, SgiTarget}; + + use crate::interrupts::SGI_RESCHED; + + unsafe { + asm!("dsb nsh", "isb", options(nostack, nomem, preserves_flags)); + } + + let reschedid = IntId::sgi(SGI_RESCHED.into()); + GicV3::send_sgi( + reschedid, + SgiTarget::List { + affinity3: 0, + affinity2: 0, + affinity1: 0, + target_list: 0b1, + }, + ); + + interrupts::enable(); + } + + #[cfg(any(feature = "tcp", feature = "udp"))] + fn add_network_timer(self, wakeup_time: Option) { + without_interrupts(|| { + self.blocked_tasks.add_network_timer(wakeup_time); + }) + } + + fn exit(self, exit_code: i32) -> ! { + without_interrupts(|| { + // Get the current task. + let mut current_task_borrowed = self.current_task.borrow_mut(); + assert_ne!( + current_task_borrowed.status, + TaskStatus::Idle, + "Trying to terminate the idle task" + ); + + // Finish the task and reschedule. + debug!( + "Finishing task {} with exit code {}", + current_task_borrowed.id, exit_code + ); + current_task_borrowed.status = TaskStatus::Finished; + NO_TASKS.fetch_sub(1, Ordering::SeqCst); + + let current_id = current_task_borrowed.id; + drop(current_task_borrowed); + + // wakeup tasks, which are waiting for task with the identifier id + if let Some(mut queue) = WAITING_TASKS.lock().remove(¤t_id) { + while let Some(task) = queue.pop_front() { + self.custom_wakeup(task); + } + } + }); + + self.reschedule(); + unreachable!() + } +} + struct NewTask { tid: TaskId, func: extern "C" fn(usize), @@ -169,40 +275,6 @@ impl PerCoreScheduler { tid } - /// Terminate the current task on the current core. - pub fn exit(&mut self, exit_code: i32) -> ! { - without_interrupts(|| { - // Get the current task. - let mut current_task_borrowed = self.current_task.borrow_mut(); - assert_ne!( - current_task_borrowed.status, - TaskStatus::Idle, - "Trying to terminate the idle task" - ); - - // Finish the task and reschedule. - debug!( - "Finishing task {} with exit code {}", - current_task_borrowed.id, exit_code - ); - current_task_borrowed.status = TaskStatus::Finished; - NO_TASKS.fetch_sub(1, Ordering::SeqCst); - - let current_id = current_task_borrowed.id; - drop(current_task_borrowed); - - // wakeup tasks, which are waiting for task with the identifier id - if let Some(mut queue) = WAITING_TASKS.lock().remove(¤t_id) { - while let Some(task) = queue.pop_front() { - self.custom_wakeup(task); - } - } - }); - - self.reschedule(); - unreachable!() - } - #[cfg(feature = "newlib")] fn clone_impl(&self, func: extern "C" fn(usize), arg: usize) -> TaskId { static NEXT_CORE_ID: AtomicU32 = AtomicU32::new(1); @@ -332,12 +404,6 @@ impl PerCoreScheduler { }); } - #[cfg(any(feature = "tcp", feature = "udp"))] - #[inline] - pub fn add_network_timer(&mut self, wakeup_time: Option) { - without_interrupts(|| self.blocked_tasks.add_network_timer(wakeup_time)) - } - #[inline] pub fn get_current_task_handle(&self) -> TaskHandle { without_interrupts(|| { @@ -465,60 +531,6 @@ impl PerCoreScheduler { } } - /// Triggers the scheduler to reschedule the tasks. - /// Interrupt flag will be cleared during the reschedule - #[cfg(target_arch = "x86_64")] - pub fn reschedule(&mut self) { - without_interrupts(|| { - if let Some(last_stack_pointer) = self.scheduler() { - let (new_stack_pointer, is_idle) = { - let borrowed = self.current_task.borrow(); - ( - borrowed.last_stack_pointer, - borrowed.status == TaskStatus::Idle, - ) - }; - - if is_idle || Rc::ptr_eq(&self.current_task, &self.fpu_owner) { - unsafe { - switch_to_fpu_owner(last_stack_pointer, new_stack_pointer.as_usize()); - } - } else { - unsafe { - switch_to_task(last_stack_pointer, new_stack_pointer.as_usize()); - } - } - } - }) - } - - /// Trigger an interrupt to reschedule the system - #[cfg(target_arch = "aarch64")] - pub fn reschedule(&self) { - use core::arch::asm; - - use arm_gic::gicv3::{GicV3, IntId, SgiTarget}; - - use crate::interrupts::SGI_RESCHED; - - unsafe { - asm!("dsb nsh", "isb", options(nostack, nomem, preserves_flags)); - } - - let reschedid = IntId::sgi(SGI_RESCHED.into()); - GicV3::send_sgi( - reschedid, - SgiTarget::List { - affinity3: 0, - affinity2: 0, - affinity1: 0, - target_list: 0b1, - }, - ); - - interrupts::enable(); - } - /// Only the idle task should call this function. /// Set the idle task to halt state if not another /// available. diff --git a/src/synch/futex.rs b/src/synch/futex.rs index db1196d281..ded2428357 100644 --- a/src/synch/futex.rs +++ b/src/synch/futex.rs @@ -10,6 +10,7 @@ use crate::arch::kernel::core_local::core_scheduler; use crate::arch::kernel::processor::get_timer_ticks; use crate::errno::{EAGAIN, EINVAL, ETIMEDOUT}; use crate::scheduler::task::TaskHandlePriorityQueue; +use crate::scheduler::PerCoreSchedulerExt; // TODO: Replace with a concurrent hashmap. static PARKING_LOT: InterruptTicketMutex> = diff --git a/src/synch/recmutex.rs b/src/synch/recmutex.rs index 885fa9fdd1..9491124e84 100644 --- a/src/synch/recmutex.rs +++ b/src/synch/recmutex.rs @@ -2,6 +2,7 @@ use hermit_sync::TicketMutex; use crate::arch::core_local::*; use crate::scheduler::task::{TaskHandlePriorityQueue, TaskId}; +use crate::scheduler::PerCoreSchedulerExt; struct RecursiveMutexState { current_tid: Option, diff --git a/src/synch/semaphore.rs b/src/synch/semaphore.rs index 2bf81ec22a..1c508fb8a0 100644 --- a/src/synch/semaphore.rs +++ b/src/synch/semaphore.rs @@ -4,6 +4,7 @@ use hermit_sync::InterruptTicketMutex; use crate::arch::core_local::*; use crate::scheduler::task::TaskHandlePriorityQueue; +use crate::scheduler::PerCoreSchedulerExt; struct SemaphoreState { /// Resource available count diff --git a/src/syscalls/tasks.rs b/src/syscalls/tasks.rs index 8edbac4880..e4962dae15 100644 --- a/src/syscalls/tasks.rs +++ b/src/syscalls/tasks.rs @@ -14,6 +14,7 @@ use crate::errno::*; #[cfg(feature = "newlib")] use crate::mm::{task_heap_end, task_heap_start}; use crate::scheduler::task::{Priority, TaskHandle, TaskId}; +use crate::scheduler::PerCoreSchedulerExt; use crate::syscalls::timer::timespec; use crate::{arch, scheduler, syscalls};