@@ -21,6 +21,8 @@ use x86_64::registers::control::Cr3;
2121use x86_64:: registers:: model_specific:: Msr ;
2222
2323use super :: interrupts:: IDT ;
24+ #[ cfg( feature = "preemptive-multithreading" ) ]
25+ use crate :: arch:: scheduler:: MIN_RESCHEDULE_INTERVAL_US ;
2426use crate :: arch:: x86_64:: kernel:: CURRENT_STACK_ADDRESS ;
2527#[ cfg( feature = "acpi" ) ]
2628use 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,28 @@ 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+ #[ cfg( feature = "preemptive-multithreading" ) ]
752+ pub fn set_oneshot_timer_relative ( rel_wakeup_time_us : u64 ) {
729753 without_interrupts ( || {
730- __set_oneshot_timer ( wakeup_time ) ;
754+ __set_oneshot_timer_relative ( rel_wakeup_time_us ) ;
731755 } ) ;
732756}
733757
0 commit comments