@@ -21,6 +21,8 @@ use x86_64::registers::control::Cr3;
21
21
use x86_64:: registers:: model_specific:: Msr ;
22
22
23
23
use super :: interrupts:: IDT ;
24
+ #[ cfg( feature = "preemptive-multithreading" ) ]
25
+ use crate :: arch:: scheduler:: MIN_RESCHEDULE_INTERVAL_US ;
24
26
use crate :: arch:: x86_64:: kernel:: CURRENT_STACK_ADDRESS ;
25
27
#[ cfg( feature = "acpi" ) ]
26
28
use crate :: arch:: x86_64:: kernel:: acpi;
@@ -683,8 +685,26 @@ fn calibrate_timer() {
683
685
) ;
684
686
}
685
687
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 {
688
708
if processor:: supports_tsc_deadline ( ) {
689
709
// wt is the absolute wakeup time in microseconds based on processor::get_timer_ticks.
690
710
// 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>) {
710
730
} else {
711
731
1
712
732
} ;
713
- let init_count = cmp:: min (
714
- CALIBRATED_COUNTER_VALUE . get ( ) . unwrap ( ) * ticks,
715
- u64:: from ( u32:: MAX ) ,
716
- ) ;
717
733
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) ;
721
735
}
722
736
} else {
723
737
// Disable the APIC Timer.
738
+ #[ cfg( not( feature = "preemptive-multithreading" ) ) ]
724
739
local_apic_write ( IA32_X2APIC_LVT_TIMER , APIC_LVT_MASK ) ;
725
740
}
726
741
}
727
742
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 ) {
729
752
without_interrupts ( || {
730
- __set_oneshot_timer ( wakeup_time ) ;
753
+ __set_oneshot_timer_relative ( rel_wakeup_time_us ) ;
731
754
} ) ;
732
755
}
733
756
0 commit comments