Skip to content

Commit 390c379

Browse files
committed
WIP
1 parent 67c1b2b commit 390c379

File tree

15 files changed

+214
-210
lines changed

15 files changed

+214
-210
lines changed

src/arch/aarch64/kernel/interrupts.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use memory_addresses::arch::aarch64::PhysAddr;
1717
use crate::arch::aarch64::kernel::core_local::increment_irq_counter;
1818
use crate::arch::aarch64::kernel::scheduler::State;
1919
use crate::arch::aarch64::mm::paging::{self, BasePageSize, PageSize, PageTableEntryFlags};
20+
use crate::arch::timer_interrupts;
2021
#[cfg(not(feature = "pci"))]
2122
use crate::drivers::mmio::get_interrupt_handlers;
2223
#[cfg(feature = "pci")]
@@ -93,10 +94,8 @@ pub(crate) fn install_handlers() {
9394

9495
fn timer_handler() {
9596
debug!("Handle timer interrupt");
96-
97-
// disable timer
98-
CNTP_CVAL_EL0.set(0);
99-
CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::CLEAR);
97+
timer_interrupts::clear_active();
98+
timer_interrupts::set_next_timer();
10099
}
101100

102101
for (key, value) in get_interrupt_handlers().into_iter() {

src/arch/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Architecture-specific architecture abstraction.
22
3+
pub(crate) mod timer_interrupts;
4+
35
cfg_if::cfg_if! {
46
if #[cfg(target_arch = "aarch64")] {
57
pub(crate) mod aarch64;

src/arch/riscv64/kernel/scheduler.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@ use free_list::{PageLayout, PageRange};
55
use memory_addresses::{PhysAddr, VirtAddr};
66

77
use crate::arch::riscv64::kernel::core_local::core_scheduler;
8-
use crate::arch::riscv64::kernel::processor::set_oneshot_timer;
98
use crate::arch::riscv64::mm::paging::{BasePageSize, PageSize, PageTableEntryFlags};
109
use crate::mm::{FrameAlloc, PageAlloc, PageRangeAllocator};
1110
use crate::scheduler::task::{Task, TaskFrame};
12-
use crate::{DEFAULT_STACK_SIZE, KERNEL_STACK_SIZE};
11+
use crate::{DEFAULT_STACK_SIZE, KERNEL_STACK_SIZE, timer_interrupts};
1312

1413
#[repr(C, packed)]
1514
#[derive(Clone, Copy, Debug)]
@@ -360,9 +359,10 @@ unsafe extern "C" fn task_start(func: extern "C" fn(usize), arg: usize, user_sta
360359
}
361360

362361
pub fn timer_handler() {
363-
//increment_irq_counter(apic::TIMER_INTERRUPT_NUMBER.into());
362+
debug!("Handle timer interrupt");
363+
timer_interrupts::clear_active();
364+
timer_interrupts::set_next_timer();
364365
core_scheduler().handle_waiting_tasks();
365-
set_oneshot_timer(None);
366366
core_scheduler().scheduler();
367367
}
368368

src/arch/timer_interrupts.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use core::sync::atomic::{AtomicU64, Ordering};
2+
3+
#[cfg(feature = "net")]
4+
use crate::executor::network::NETWORK_WAKER;
5+
use crate::set_oneshot_timer;
6+
7+
/// A possible timer interrupt source (i.e. reason the timer interrupt was set
8+
/// up).
9+
#[derive(PartialEq, Eq)]
10+
pub enum Source {
11+
Network,
12+
Scheduler,
13+
}
14+
15+
/// A slot in the timer list. Each source is represented once. This is so that
16+
/// we can have multiple timers at the same time with only one hardware timer.
17+
struct Slot {
18+
/// Timer source.
19+
source: Source,
20+
/// Point in time at which to wake up (in microsecond precision).
21+
/// A value of [`u64::MAX`] means the timer is not set.
22+
wakeup_time: AtomicU64,
23+
}
24+
25+
/// The actual timer list with one entry for each source.
26+
static TIMERS: [Slot; 2] = [
27+
Slot {
28+
source: Source::Network,
29+
wakeup_time: AtomicU64::new(u64::MAX),
30+
},
31+
Slot {
32+
source: Source::Scheduler,
33+
wakeup_time: AtomicU64::new(u64::MAX),
34+
},
35+
];
36+
37+
/// Create a new timer, overriding any previous timer for the source.
38+
#[cfg(feature = "net")]
39+
pub fn create_timer(source: Source, wakeup_micros: u64) {
40+
trace!("Setting relative timer interrupt for {wakeup_micros}us");
41+
42+
create_timer_abs(
43+
source,
44+
crate::arch::processor::get_timer_ticks() + wakeup_micros,
45+
);
46+
}
47+
48+
/// Crete a new timer, but with an absolute wakeup time.
49+
pub fn create_timer_abs(source: Source, wakeup_time: u64) {
50+
trace!(
51+
"Setting an absolute timer interrupt for {}us",
52+
wakeup_time - crate::arch::processor::get_timer_ticks()
53+
);
54+
55+
{
56+
// SAFETY: Our timer list has an entry for every possible source
57+
let previous_entry = TIMERS.iter().find(|slot| slot.source == source).unwrap();
58+
59+
// Overwrite the wakeup time
60+
previous_entry
61+
.wakeup_time
62+
.store(wakeup_time, Ordering::Relaxed);
63+
}
64+
65+
// If this timer is the one closest in the future, set the real timer to it
66+
// SAFETY: There's more than 1 slot
67+
if TIMERS
68+
.iter()
69+
.map(|slot| slot.wakeup_time.load(Ordering::Relaxed))
70+
.min_by(|a, b| a.cmp(b))
71+
.unwrap()
72+
== wakeup_time
73+
{
74+
trace!("Setting the oneshot timer now");
75+
76+
set_oneshot_timer(Some(wakeup_time));
77+
}
78+
}
79+
80+
/// Sets the next timer or disables it if no timer is pending.
81+
pub fn set_next_timer() {
82+
// SAFETY: There's more than 1 slot
83+
let lowest_timer = TIMERS
84+
.iter()
85+
.map(|slot| slot.wakeup_time.load(Ordering::Relaxed))
86+
.min_by(|a, b| a.cmp(b))
87+
.unwrap();
88+
89+
if lowest_timer == u64::MAX {
90+
set_oneshot_timer(None);
91+
} else {
92+
set_oneshot_timer(Some(lowest_timer));
93+
}
94+
}
95+
96+
/// Clears the timer slot for the currently active timer.
97+
pub fn clear_active() {
98+
// SAFETY: There's more than 1 slot
99+
let lowest_timer = TIMERS
100+
.iter()
101+
.min_by(|a, b| {
102+
a.wakeup_time
103+
.load(Ordering::Relaxed)
104+
.cmp(&b.wakeup_time.load(Ordering::Relaxed))
105+
})
106+
.unwrap();
107+
108+
// TODO: Do we really want to do this here?
109+
match lowest_timer.source {
110+
#[cfg(feature = "net")]
111+
Source::Network => NETWORK_WAKER.lock().wake(),
112+
_ => {} // no-op, we always poll after a timer interrupt
113+
}
114+
115+
trace!("Cleared active timer");
116+
117+
lowest_timer.wakeup_time.store(u64::MAX, Ordering::Relaxed);
118+
}

src/arch/x86_64/kernel/scheduler.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ use crate::arch::x86_64::mm::paging::{
1414
BasePageSize, PageSize, PageTableEntryFlags, PageTableEntryFlagsExt,
1515
};
1616
use crate::config::*;
17-
use crate::env;
1817
use crate::mm::{FrameAlloc, PageAlloc, PageRangeAllocator};
1918
use crate::scheduler::PerCoreSchedulerExt;
2019
use crate::scheduler::task::{Task, TaskFrame};
20+
use crate::{env, timer_interrupts};
2121

2222
#[repr(C, packed)]
2323
struct State {
@@ -318,6 +318,11 @@ impl TaskFrame for Task {
318318

319319
extern "x86-interrupt" fn timer_handler(_stack_frame: interrupts::ExceptionStackFrame) {
320320
increment_irq_counter(apic::TIMER_INTERRUPT_NUMBER);
321+
322+
debug!("Handle timer interrupt");
323+
timer_interrupts::clear_active();
324+
timer_interrupts::set_next_timer();
325+
321326
core_scheduler().handle_waiting_tasks();
322327
apic::eoi();
323328
core_scheduler().reschedule();

src/drivers/net/gem.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use crate::drivers::net::{NetworkDriver, mtu};
3232
#[cfg(feature = "pci")]
3333
use crate::drivers::pci as hardware;
3434
use crate::drivers::{Driver, InterruptLine};
35+
use crate::executor::network::NETWORK_WAKER;
3536
use crate::mm::device_alloc::DeviceAlloc;
3637
use crate::{BasePageSize, PageSize};
3738

@@ -276,6 +277,9 @@ impl NetworkDriver for GEMDriver {
276277

277278
fn handle_interrupt(&mut self) {
278279
self.tx_fields.handle_interrupt();
280+
281+
trace!("Waking network waker");
282+
NETWORK_WAKER.lock().wake();
279283
}
280284
}
281285

src/drivers/net/loopback.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use smoltcp::time::Instant;
88

99
use crate::drivers::net::NetworkDriver;
1010
use crate::drivers::{Driver, InterruptLine};
11+
use crate::executor::network::NETWORK_WAKER;
1112
use crate::mm::device_alloc::DeviceAlloc;
1213

1314
pub(crate) struct LoopbackDriver {
@@ -122,7 +123,8 @@ impl NetworkDriver for LoopbackDriver {
122123
}
123124

124125
fn handle_interrupt(&mut self) {
125-
// no-op
126+
trace!("Waking network waker");
127+
NETWORK_WAKER.lock().wake();
126128
}
127129
}
128130

src/drivers/net/rtl8139.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::drivers::Driver;
2121
use crate::drivers::error::DriverError;
2222
use crate::drivers::net::{NetworkDriver, mtu};
2323
use crate::drivers::pci::PciDevice;
24+
use crate::executor::network::NETWORK_WAKER;
2425
use crate::mm::device_alloc::DeviceAlloc;
2526

2627
/// size of the receive buffer
@@ -687,6 +688,9 @@ impl NetworkDriver for RTL8139Driver {
687688
self.regs.as_mut_ptr().isr().write(le16::from(
688689
isr_contents & (ISR_RXOVW | ISR_TER | ISR_RER | ISR_TOK | ISR_ROK),
689690
));
691+
692+
trace!("Waking network waker");
693+
NETWORK_WAKER.lock().wake();
690694
}
691695
}
692696

src/drivers/net/virtio/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use crate::drivers::virtio::virtqueue::{
4141
AvailBufferToken, BufferElem, BufferType, UsedBufferToken, VirtQueue, Virtq,
4242
};
4343
use crate::drivers::{Driver, InterruptLine};
44+
use crate::executor::network::NETWORK_WAKER;
4445
use crate::mm::device_alloc::DeviceAlloc;
4546

4647
/// A wrapper struct for the raw configuration structure.
@@ -416,6 +417,9 @@ impl NetworkDriver for VirtioNetDriver<Init> {
416417
}
417418

418419
self.isr_stat.acknowledge();
420+
421+
trace!("Waking network waker");
422+
NETWORK_WAKER.lock().wake();
419423
}
420424
}
421425

src/executor/mod.rs

Lines changed: 9 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,11 @@ use core::time::Duration;
1818

1919
use crossbeam_utils::Backoff;
2020
use hermit_sync::without_interrupts;
21-
#[cfg(feature = "net")]
22-
use smoltcp::time::Instant;
2321

2422
use crate::arch::core_local;
2523
use crate::errno::Errno;
2624
use crate::executor::task::AsyncTask;
2725
use crate::io;
28-
#[cfg(feature = "net")]
29-
use crate::scheduler::PerCoreSchedulerExt;
3026
use crate::synch::futex::*;
3127

3228
/// WakerRegistration is derived from smoltcp's
@@ -155,101 +151,27 @@ where
155151

156152
let now = crate::arch::kernel::systemtime::now_micros();
157153
if let Poll::Ready(t) = result {
158-
// allow network interrupts
159-
#[cfg(feature = "net")]
160-
{
161-
if let Some(mut guard) = crate::executor::network::NIC.try_lock() {
162-
let delay = if let Ok(nic) = guard.as_nic_mut() {
163-
nic.set_polling_mode(false);
164-
165-
nic.poll_delay(Instant::from_micros_const(now.try_into().unwrap()))
166-
.map(|d| d.total_micros())
167-
} else {
168-
None
169-
};
170-
core_local::core_scheduler().add_network_timer(
171-
delay.map(|d| crate::arch::processor::get_timer_ticks() + d),
172-
);
173-
}
174-
}
175-
176154
return t;
177155
}
178156

179157
if let Some(duration) = timeout
180158
&& Duration::from_micros(now - start) >= duration
181159
{
182-
// allow network interrupts
183-
#[cfg(feature = "net")]
184-
{
185-
if let Some(mut guard) = crate::executor::network::NIC.try_lock() {
186-
let delay = if let Ok(nic) = guard.as_nic_mut() {
187-
nic.set_polling_mode(false);
188-
189-
nic.poll_delay(Instant::from_micros_const(now.try_into().unwrap()))
190-
.map(|d| d.total_micros())
191-
} else {
192-
None
193-
};
194-
core_local::core_scheduler().add_network_timer(
195-
delay.map(|d| crate::arch::processor::get_timer_ticks() + d),
196-
);
197-
}
198-
}
199-
200160
return Err(Errno::Time);
201161
}
202162

203-
#[cfg(feature = "net")]
163+
// TODO: I have no idea whether this is correct
204164
if backoff.is_completed() {
205-
let delay = if let Some(mut guard) = crate::executor::network::NIC.try_lock() {
206-
if let Ok(nic) = guard.as_nic_mut() {
207-
nic.set_polling_mode(false);
208-
209-
nic.poll_delay(Instant::from_micros_const(now.try_into().unwrap()))
210-
.map(|d| d.total_micros())
211-
} else {
212-
None
213-
}
214-
} else {
215-
None
216-
};
217-
218-
if delay.unwrap_or(10_000_000) > 10_000 {
219-
core_local::core_scheduler().add_network_timer(
220-
delay.map(|d| crate::arch::processor::get_timer_ticks() + d),
221-
);
222-
let wakeup_time =
223-
timeout.map(|duration| start + u64::try_from(duration.as_micros()).unwrap());
224-
225-
// switch to another task
226-
task_notify.wait(wakeup_time);
227-
228-
// restore default values
229-
if let Ok(nic) = crate::executor::network::NIC.lock().as_nic_mut() {
230-
nic.set_polling_mode(true);
231-
}
232-
233-
backoff.reset();
234-
}
235-
} else {
236-
backoff.snooze();
237-
}
238-
239-
#[cfg(not(feature = "net"))]
240-
{
241-
if backoff.is_completed() {
242-
let wakeup_time =
243-
timeout.map(|duration| start + u64::try_from(duration.as_micros()).unwrap());
165+
let wakeup_time =
166+
timeout.map(|duration| start + u64::try_from(duration.as_micros()).unwrap());
244167

245-
// switch to another task
246-
task_notify.wait(wakeup_time);
168+
// switch to another task
169+
task_notify.wait(wakeup_time);
247170

248-
// restore default values
249-
backoff.reset();
250-
} else {
251-
backoff.snooze();
252-
}
171+
// restore default values
172+
backoff.reset();
173+
} else {
174+
backoff.snooze();
253175
}
254176
}
255177
}

0 commit comments

Comments
 (0)