Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ vga = []
virtio = ["dep:virtio"]
virtio-net = ["net", "virtio"]
vsock = ["virtio", "pci"]
preemptive-multithreading = []

[lints.rust]
rust_2018_idioms = "warn"
Expand Down
46 changes: 35 additions & 11 deletions src/arch/x86_64/kernel/apic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ use x86_64::registers::control::Cr3;
use x86_64::registers::model_specific::Msr;

use super::interrupts::IDT;
#[cfg(feature = "preemptive-multithreading")]
use crate::arch::scheduler::MIN_RESCHEDULE_INTERVAL_US;
use crate::arch::x86_64::kernel::CURRENT_STACK_ADDRESS;
#[cfg(feature = "acpi")]
use crate::arch::x86_64::kernel::acpi;
Expand Down Expand Up @@ -683,8 +685,26 @@ fn calibrate_timer() {
);
}

fn __set_oneshot_timer(wakeup_time: Option<u64>) {
if let Some(wt) = wakeup_time {
fn __set_oneshot_timer_relative(ticks: u64) {
#[cfg(feature = "preemptive-multithreading")]
let ticks = cmp::min(ticks, MIN_RESCHEDULE_INTERVAL_US);

let ticks = cmp::min(
CALIBRATED_COUNTER_VALUE.get().unwrap() * ticks,
u64::from(u32::MAX),
);

__set_oneshot_timer_ticks(ticks);
}

fn __set_oneshot_timer_ticks(ticks: u64) {
// Enable the APIC Timer in One-Shot Mode and let it start by setting the initial counter value.
local_apic_write(IA32_X2APIC_LVT_TIMER, u64::from(TIMER_INTERRUPT_NUMBER));
local_apic_write(IA32_X2APIC_INIT_COUNT, ticks);
}

fn __set_oneshot_timer(wakeup_time_us: Option<u64>) {
if let Some(wt) = wakeup_time_us {
if processor::supports_tsc_deadline() {
// wt is the absolute wakeup time in microseconds based on processor::get_timer_ticks.
// We can simply multiply it by the processor frequency to get the absolute Time-Stamp Counter deadline
Expand All @@ -710,24 +730,28 @@ fn __set_oneshot_timer(wakeup_time: Option<u64>) {
} else {
1
};
let init_count = cmp::min(
CALIBRATED_COUNTER_VALUE.get().unwrap() * ticks,
u64::from(u32::MAX),
);

// Enable the APIC Timer in One-Shot Mode and let it start by setting the initial counter value.
local_apic_write(IA32_X2APIC_LVT_TIMER, u64::from(TIMER_INTERRUPT_NUMBER));
local_apic_write(IA32_X2APIC_INIT_COUNT, init_count);
__set_oneshot_timer_relative(ticks);
}
} else {
// Disable the APIC Timer.
#[cfg(not(feature = "preemptive-multithreading"))]
local_apic_write(IA32_X2APIC_LVT_TIMER, APIC_LVT_MASK);
}
}

pub fn set_oneshot_timer(wakeup_time: Option<u64>) {
/// Sets a timer at precisely abs_wakeup_time_us after boot
pub fn set_oneshot_timer(abs_wakeup_time_us: Option<u64>) {
without_interrupts(|| {
__set_oneshot_timer(abs_wakeup_time_us);
});
}

/// Sets a timer in precisely rel_wakeup_time_us microseconds$
#[cfg(feature = "preemptive-multithreading")]
pub fn set_oneshot_timer_relative(rel_wakeup_time_us: u64) {
without_interrupts(|| {
__set_oneshot_timer(wakeup_time);
__set_oneshot_timer_relative(rel_wakeup_time_us);
});
}

Expand Down
11 changes: 11 additions & 0 deletions src/arch/x86_64/kernel/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use free_list::{PageLayout, PageRange};
use memory_addresses::{PhysAddr, VirtAddr};

use super::interrupts::{IDT, IST_SIZE};
#[cfg(feature = "preemptive-multithreading")]
use crate::arch::kernel::apic::set_oneshot_timer_relative;
use crate::arch::x86_64::kernel::core_local::*;
use crate::arch::x86_64::kernel::{apic, interrupts};
use crate::arch::x86_64::mm::paging::{
Expand All @@ -26,6 +28,10 @@ use crate::mm::virtualmem::KERNEL_FREE_LIST;
use crate::scheduler::PerCoreSchedulerExt;
use crate::scheduler::task::{Task, TaskFrame};

// Run scheduler at least every xxx micro-seconds
#[cfg(feature = "preemptive-multithreading")]
pub const MIN_RESCHEDULE_INTERVAL_US: u64 = 50;

#[repr(C, packed)]
struct State {
#[cfg(feature = "common-os")]
Expand Down Expand Up @@ -398,6 +404,8 @@ extern "x86-interrupt" fn timer_handler(_stack_frame: interrupts::ExceptionStack
increment_irq_counter(apic::TIMER_INTERRUPT_NUMBER);
core_scheduler().handle_waiting_tasks();
apic::eoi();
#[cfg(feature = "preemptive-multithreading")]
set_oneshot_timer_relative(MIN_RESCHEDULE_INTERVAL_US);
core_scheduler().reschedule();
}

Expand All @@ -409,4 +417,7 @@ pub fn install_timer_handler() {
.set_stack_index(0);
}
interrupts::add_irq_name(apic::TIMER_INTERRUPT_NUMBER - 32, "Timer");

#[cfg(feature = "preemptive-multithreading")]
set_oneshot_timer_relative(1);
}