Skip to content

Commit 6108e2f

Browse files
committed
WIP
1 parent f250a72 commit 6108e2f

File tree

11 files changed

+171
-100
lines changed

11 files changed

+171
-100
lines changed

src/arch/aarch64/kernel/interrupts.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@ 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")]
2324
use crate::drivers::pci::get_interrupt_handlers;
2425
use crate::drivers::{InterruptHandlerQueue, InterruptLine};
26+
#[cfg(feature = "net")]
27+
use crate::executor::network::NETWORK_WAKER;
2528
use crate::kernel::serial::handle_uart_interrupt;
2629
use crate::mm::{PageAlloc, PageRangeAllocator};
2730
use crate::scheduler::{self, CoreId};
@@ -94,9 +97,12 @@ pub(crate) fn install_handlers() {
9497
fn timer_handler() {
9598
debug!("Handle timer interrupt");
9699

97-
// disable timer
98-
CNTP_CVAL_EL0.set(0);
99-
CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::CLEAR);
100+
timer_interrupts::clear_active();
101+
if !timer_interrupts::set_next_timer() {
102+
// disable timer
103+
CNTP_CVAL_EL0.set(0);
104+
CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::CLEAR);
105+
}
100106
}
101107

102108
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/timer_interrupts.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use core::sync::atomic::{AtomicU64, Ordering};
2+
3+
use crate::set_oneshot_timer;
4+
5+
/// A possible timer interrupt source (i.e. reason the timer interrupt was set
6+
/// up).
7+
#[derive(PartialEq, Eq)]
8+
pub enum Source {
9+
Network,
10+
Scheduler,
11+
}
12+
13+
/// A slot in the timer list. Each source is represented once. This is so that
14+
/// we can have multiple timers at the same time with only one hardware timer.
15+
struct Slot {
16+
/// Timer source.
17+
source: Source,
18+
/// Point in time at which to wake up (in microsecond precision).
19+
/// A value of [`u64::MAX`] means the timer is not set.
20+
wakeup_time: AtomicU64,
21+
}
22+
23+
/// The actual timer list with one entry for each source.
24+
static TIMERS: [Slot; 2] = [
25+
Slot {
26+
source: Source::Network,
27+
wakeup_time: AtomicU64::new(u64::MAX),
28+
},
29+
Slot {
30+
source: Source::Scheduler,
31+
wakeup_time: AtomicU64::new(u64::MAX),
32+
},
33+
];
34+
35+
/// Create a new timer, overriding any previous timer for the source.
36+
pub fn create_timer(source: Source, wakeup_micros: u64) {
37+
let wakeup_time = crate::arch::processor::get_timer_ticks() + wakeup_micros;
38+
39+
{
40+
// SAFETY: Our timer list has an entry for every possible source
41+
let previous_entry = TIMERS.iter().find(|slot| slot.source == source).unwrap();
42+
43+
// Overwite the wakeup time
44+
previous_entry
45+
.wakeup_time
46+
.store(wakeup_time, Ordering::Relaxed);
47+
}
48+
49+
// If this timer is the one closest in the future, set the real timer to it
50+
// SAFETY: There's more than 1 slot
51+
if TIMERS
52+
.iter()
53+
.map(|slot| slot.wakeup_time.load(Ordering::Relaxed))
54+
.min_by(|a, b| a.cmp(b))
55+
.unwrap()
56+
== wakeup_time
57+
{
58+
set_oneshot_timer(Some(wakeup_time));
59+
}
60+
}
61+
62+
/// Sets the next timer, returns `false` if no timer is set.
63+
pub fn set_next_timer() -> bool {
64+
// SAFETY: There's more than 1 slot
65+
let lowest_timer = TIMERS
66+
.iter()
67+
.map(|slot| slot.wakeup_time.load(Ordering::Relaxed))
68+
.min_by(|a, b| a.cmp(b))
69+
.unwrap();
70+
71+
if lowest_timer == u64::MAX {
72+
false
73+
} else {
74+
set_oneshot_timer(Some(lowest_timer));
75+
76+
true
77+
}
78+
}
79+
80+
/// Clears the timer slot for the currently active timer.
81+
pub fn clear_active() {
82+
// SAFETY: There's more than 1 slot
83+
let lowest_timer = TIMERS
84+
.iter()
85+
.min_by(|a, b| {
86+
a.wakeup_time
87+
.load(Ordering::Relaxed)
88+
.cmp(&b.wakeup_time.load(Ordering::Relaxed))
89+
})
90+
.unwrap();
91+
92+
lowest_timer.wakeup_time.store(u64::MAX, Ordering::Relaxed);
93+
}

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+
debug!("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+
debug!("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+
debug!("Waking network waker");
693+
NETWORK_WAKER.lock().wake();
690694
}
691695
}
692696

src/drivers/net/virtio/mod.rs

Lines changed: 8 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.
@@ -415,7 +416,14 @@ impl NetworkDriver for VirtioNetDriver<Init> {
415416
todo!("Implement possibility to change config on the fly...")
416417
}
417418

419+
error!("virtio interrupt");
420+
418421
self.isr_stat.acknowledge();
422+
423+
debug!("Waking network waker");
424+
NETWORK_WAKER.lock().wake();
425+
426+
error!("meow after");
419427
}
420428
}
421429

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
}

src/executor/network.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::arch;
2626
use crate::drivers::net::{NetworkDevice, NetworkDriver};
2727
#[cfg(feature = "dns")]
2828
use crate::errno::Errno;
29-
use crate::executor::spawn;
29+
use crate::executor::{WakerRegistration, spawn};
3030
#[cfg(feature = "dns")]
3131
use crate::io;
3232
use crate::scheduler::PerCoreSchedulerExt;
@@ -189,14 +189,36 @@ async fn dhcpv4_run() {
189189
.await;
190190
}
191191

192+
pub(crate) static NETWORK_WAKER: InterruptTicketMutex<WakerRegistration> =
193+
InterruptTicketMutex::new(WakerRegistration::new());
194+
192195
async fn network_run() {
193196
future::poll_fn(|cx| {
194197
if let Some(mut guard) = NIC.try_lock() {
195198
match &mut *guard {
196199
NetworkState::Initialized(nic) => {
197-
nic.poll_common(now());
198-
// FIXME: only wake when progress can be made
199-
cx.waker().wake_by_ref();
200+
let now = now();
201+
202+
// TODO: smoltcp is probably not exposing enough information here
203+
// Well, how could it! Impossible :)
204+
match nic.poll_common(now) {
205+
PollResult::SocketStateChanged => {
206+
// Progress was made
207+
cx.waker().wake_by_ref();
208+
}
209+
PollResult::None => {
210+
// Very likely no progress can be made, so set up a timer interrupt to wake the waker
211+
NETWORK_WAKER.lock().register(cx.waker());
212+
nic.set_polling_mode(false);
213+
let wakeup_time = nic.poll_delay(now).map(|d| {
214+
crate::arch::processor::get_timer_ticks() + d.total_micros()
215+
});
216+
crate::core_scheduler().add_network_timer(wakeup_time);
217+
info!("Configured an interrupt for {wakeup_time:?}");
218+
//cx.waker().wake_by_ref();
219+
}
220+
}
221+
200222
Poll::Pending
201223
}
202224
_ => Poll::Ready(()),

0 commit comments

Comments
 (0)