Skip to content

Commit

Permalink
refactor(scheduler): move reschedule, add_network_timer, and exit to …
Browse files Browse the repository at this point in the history
…extension trait

Signed-off-by: Martin Kröning <[email protected]>
  • Loading branch information
mkroening committed Sep 18, 2023
1 parent a80bc91 commit a434f0e
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 94 deletions.
2 changes: 2 additions & 0 deletions src/arch/x86_64/kernel/apic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions src/arch/x86_64/kernel/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions src/drivers/net/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions src/executor/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
200 changes: 106 additions & 94 deletions src/scheduler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u64>);

/// 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<u64>) {
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(&current_id) {
while let Some(task) = queue.pop_front() {
self.custom_wakeup(task);
}
}
});

self.reschedule();
unreachable!()
}
}

struct NewTask {
tid: TaskId,
func: extern "C" fn(usize),
Expand Down Expand Up @@ -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(&current_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);
Expand Down Expand Up @@ -332,12 +404,6 @@ impl PerCoreScheduler {
});
}

#[cfg(any(feature = "tcp", feature = "udp"))]
#[inline]
pub fn add_network_timer(&mut self, wakeup_time: Option<u64>) {
without_interrupts(|| self.blocked_tasks.add_network_timer(wakeup_time))
}

#[inline]
pub fn get_current_task_handle(&self) -> TaskHandle {
without_interrupts(|| {
Expand Down Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions src/synch/futex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<HashMap<usize, TaskHandlePriorityQueue, RandomState>> =
Expand Down
1 change: 1 addition & 0 deletions src/synch/recmutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TaskId>,
Expand Down
1 change: 1 addition & 0 deletions src/synch/semaphore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/syscalls/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down

0 comments on commit a434f0e

Please sign in to comment.