Skip to content

Commit 984b850

Browse files
committed
x86_64: feature - preemptive multithreading
1 parent 40e0c6e commit 984b850

File tree

3 files changed

+48
-11
lines changed

3 files changed

+48
-11
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ vga = []
7676
virtio = ["dep:virtio"]
7777
virtio-net = ["net", "virtio"]
7878
vsock = ["virtio", "pci"]
79+
preemptive-multithreading = []
7980

8081
[lints.rust]
8182
rust_2018_idioms = "warn"

src/arch/x86_64/kernel/apic.rs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ use x86_64::registers::control::Cr3;
2121
use x86_64::registers::model_specific::Msr;
2222

2323
use super::interrupts::IDT;
24+
#[cfg(feature = "preemptive-multithreading")]
25+
use crate::arch::scheduler::MIN_RESCHEDULE_INTERVAL_US;
2426
use crate::arch::x86_64::kernel::CURRENT_STACK_ADDRESS;
2527
#[cfg(feature = "acpi")]
2628
use crate::arch::x86_64::kernel::acpi;
@@ -683,8 +685,26 @@ fn calibrate_timer() {
683685
);
684686
}
685687

686-
fn __set_oneshot_timer(wakeup_time: Option<u64>) {
687-
if let Some(wt) = wakeup_time {
688+
fn __set_oneshot_timer_relative(ticks: u64) {
689+
#[cfg(feature = "preemptive-multithreading")]
690+
let ticks = cmp::min(ticks, MIN_RESCHEDULE_INTERVAL_US);
691+
692+
let ticks = cmp::min(
693+
CALIBRATED_COUNTER_VALUE.get().unwrap() * ticks,
694+
u64::from(u32::MAX),
695+
);
696+
697+
__set_oneshot_timer_ticks(ticks)
698+
}
699+
700+
fn __set_oneshot_timer_ticks(ticks: u64) {
701+
// Enable the APIC Timer in One-Shot Mode and let it start by setting the initial counter value.
702+
local_apic_write(IA32_X2APIC_LVT_TIMER, u64::from(TIMER_INTERRUPT_NUMBER));
703+
local_apic_write(IA32_X2APIC_INIT_COUNT, ticks);
704+
}
705+
706+
fn __set_oneshot_timer(wakeup_time_us: Option<u64>) {
707+
if let Some(wt) = wakeup_time_us {
688708
if processor::supports_tsc_deadline() {
689709
// wt is the absolute wakeup time in microseconds based on processor::get_timer_ticks.
690710
// We can simply multiply it by the processor frequency to get the absolute Time-Stamp Counter deadline
@@ -710,24 +730,27 @@ fn __set_oneshot_timer(wakeup_time: Option<u64>) {
710730
} else {
711731
1
712732
};
713-
let init_count = cmp::min(
714-
CALIBRATED_COUNTER_VALUE.get().unwrap() * ticks,
715-
u64::from(u32::MAX),
716-
);
717733

718-
// Enable the APIC Timer in One-Shot Mode and let it start by setting the initial counter value.
719-
local_apic_write(IA32_X2APIC_LVT_TIMER, u64::from(TIMER_INTERRUPT_NUMBER));
720-
local_apic_write(IA32_X2APIC_INIT_COUNT, init_count);
734+
__set_oneshot_timer_relative(ticks);
721735
}
722736
} else {
723737
// Disable the APIC Timer.
738+
#[cfg(not(feature = "preemptive-multithreading"))]
724739
local_apic_write(IA32_X2APIC_LVT_TIMER, APIC_LVT_MASK);
725740
}
726741
}
727742

728-
pub fn set_oneshot_timer(wakeup_time: Option<u64>) {
743+
/// Sets a timer at precisely abs_wakeup_time_us after boot
744+
pub fn set_oneshot_timer(abs_wakeup_time_us: Option<u64>) {
745+
without_interrupts(|| {
746+
__set_oneshot_timer(abs_wakeup_time_us);
747+
});
748+
}
749+
750+
/// Sets a timer in precisely rel_wakeup_time_us microseconds
751+
pub fn set_oneshot_timer_relative(rel_wakeup_time_us: u64) {
729752
without_interrupts(|| {
730-
__set_oneshot_timer(wakeup_time);
753+
__set_oneshot_timer_relative(rel_wakeup_time_us);
731754
});
732755
}
733756

src/arch/x86_64/kernel/scheduler.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ use free_list::{PageLayout, PageRange};
1414
use memory_addresses::{PhysAddr, VirtAddr};
1515

1616
use super::interrupts::{IDT, IST_SIZE};
17+
#[cfg(feature = "preemptive-multithreading")]
18+
use crate::arch::kernel::apic::set_oneshot_timer_relative;
19+
#[cfg(feature = "preemptive-multithreading")]
20+
use crate::arch::set_oneshot_timer;
1721
use crate::arch::x86_64::kernel::core_local::*;
1822
use crate::arch::x86_64::kernel::{apic, interrupts};
1923
use crate::arch::x86_64::mm::paging::{
@@ -26,6 +30,10 @@ use crate::mm::virtualmem::KERNEL_FREE_LIST;
2630
use crate::scheduler::PerCoreSchedulerExt;
2731
use crate::scheduler::task::{Task, TaskFrame};
2832

33+
// Run scheduler at least every xxx micro-seconds
34+
#[cfg(feature = "preemptive-multithreading")]
35+
pub const MIN_RESCHEDULE_INTERVAL_US: u64 = 50;
36+
2937
#[repr(C, packed)]
3038
struct State {
3139
#[cfg(feature = "common-os")]
@@ -398,6 +406,8 @@ extern "x86-interrupt" fn timer_handler(_stack_frame: interrupts::ExceptionStack
398406
increment_irq_counter(apic::TIMER_INTERRUPT_NUMBER);
399407
core_scheduler().handle_waiting_tasks();
400408
apic::eoi();
409+
#[cfg(feature = "preemptive-multithreading")]
410+
set_oneshot_timer_relative(MIN_RESCHEDULE_INTERVAL_US);
401411
core_scheduler().reschedule();
402412
}
403413

@@ -409,4 +419,7 @@ pub fn install_timer_handler() {
409419
.set_stack_index(0);
410420
}
411421
interrupts::add_irq_name(apic::TIMER_INTERRUPT_NUMBER - 32, "Timer");
422+
423+
#[cfg(feature = "preemptive-multithreading")]
424+
set_oneshot_timer_relative(1);
412425
}

0 commit comments

Comments
 (0)