Skip to content

Commit 4f88dcd

Browse files
Virv12veluca93
authored andcommitted
Add Event
1 parent 57833f1 commit 4f88dcd

4 files changed

Lines changed: 132 additions & 110 deletions

File tree

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use alloc::sync::{Arc, Weak};
2+
use core::future::Future;
3+
use core::pin::Pin;
4+
use core::sync::atomic::{AtomicBool, Ordering};
5+
use core::task::{Context, Poll};
6+
7+
use futures::task::AtomicWaker;
8+
9+
#[derive(Debug, Default)]
10+
struct Inner {
11+
triggered: AtomicBool,
12+
waker: AtomicWaker,
13+
}
14+
15+
pub struct Event {
16+
inner: Arc<Inner>,
17+
}
18+
19+
impl Event {
20+
pub fn new() -> Self {
21+
Self {
22+
inner: Default::default(),
23+
}
24+
}
25+
26+
pub fn trigger(&self) -> EventTrigger {
27+
EventTrigger {
28+
inner: Arc::downgrade(&self.inner),
29+
}
30+
}
31+
}
32+
33+
impl Future for Event {
34+
type Output = ();
35+
36+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
37+
if self.inner.triggered.load(Ordering::Relaxed) {
38+
Poll::Ready(())
39+
} else {
40+
self.inner.waker.register(cx.waker());
41+
Poll::Pending
42+
}
43+
}
44+
}
45+
46+
pub struct EventTrigger {
47+
inner: Weak<Inner>,
48+
}
49+
50+
impl EventTrigger {
51+
pub fn trigger(&self) {
52+
if let Some(inner) = self.inner.upgrade() {
53+
inner.triggered.store(true, Ordering::Relaxed);
54+
inner.waker.wake();
55+
}
56+
}
57+
}
Lines changed: 44 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,16 @@ use core::task::{Context, Poll, Waker};
1212
use core::time::Duration;
1313

1414
use futures::channel::oneshot;
15-
use futures::task::AtomicWaker;
1615
use spin::Mutex;
1716
use uefi::proto::console::text::Color;
1817

18+
use crate::os::executor::event::{Event, EventTrigger};
1919
use crate::os::send_wrapper::SendWrapper;
2020
use crate::os::timer::Timer;
2121
use crate::os::ui::DrawArea;
2222

23+
pub mod event;
24+
2325
type BoxFuture = SendWrapper<Pin<Box<dyn Future<Output = ()> + 'static>>>;
2426

2527
struct Task {
@@ -55,11 +57,9 @@ impl Wake for Task {
5557
}
5658
}
5759

58-
pub(super) type WrappedWaker = Arc<AtomicWaker>;
59-
6060
struct TimedWait {
6161
wake_at: i64,
62-
waker: WrappedWaker,
62+
event: EventTrigger,
6363
}
6464

6565
impl PartialEq for TimedWait {
@@ -99,7 +99,7 @@ static EXECUTOR: Mutex<Executor> = Mutex::new(Executor {
9999
});
100100

101101
pub struct Executor {
102-
wake_on_interrupt: Vec<Waker>,
102+
wake_on_interrupt: Vec<EventTrigger>,
103103
timed_wait: BinaryHeap<TimedWait>,
104104
ready_tasks: VecDeque<Arc<Task>>,
105105
tasks: Vec<Arc<Task>>,
@@ -209,7 +209,7 @@ impl Executor {
209209
let mut do_wake = |force_interrupt_wake| {
210210
// Wake timed-waiting tasks.
211211
loop {
212-
let waker = {
212+
let event = {
213213
let mut ex = EXECUTOR.lock();
214214
let Some(w) = ex.timed_wait.peek() else {
215215
break;
@@ -218,52 +218,53 @@ impl Executor {
218218
break;
219219
}
220220
let w = ex.timed_wait.pop().unwrap();
221-
w.waker
221+
w.event
222222
};
223-
waker.wake();
223+
event.trigger();
224224
}
225225
// Since we don't notice interrupts that happened while we are not hlt-ing,
226226
// make sure that we wake up all the interrupt-based waiting tasks every at
227227
// most INTERRUPT_MICROS micros to make it unlikely to miss interrupts.
228228
if last_interrupt_wakeup + INTERRUPT_MICROS <= Timer::micros() || force_interrupt_wake {
229229
last_interrupt_wakeup = Timer::micros();
230230
let to_wake = core::mem::take(&mut EXECUTOR.lock().wake_on_interrupt);
231-
for w in to_wake {
232-
w.wake();
231+
for e in to_wake {
232+
e.trigger();
233233
}
234234
}
235235
};
236236

237237
loop {
238238
do_wake(false);
239239
let task = EXECUTOR.lock().ready_tasks.pop_front();
240-
if let Some(task) = task {
241-
// It is possible for a done task to end up in the queue (if it wakes
242-
// itself during execution). If that happens, we just remove it from
243-
// the queue here.
244-
if task.done.load(Ordering::Relaxed) {
245-
continue;
246-
}
247-
task.in_queue.store(false, Ordering::Relaxed);
248-
let waker = Waker::from(task.clone());
249-
let mut context = Context::from_waker(&waker);
250-
let mut fut = task.future.try_lock().unwrap();
251-
let begin = Timer::micros();
252-
let done = fut.0.as_mut().poll(&mut context);
253-
let end = Timer::micros();
254-
task.micros
255-
.fetch_add((end - begin) as u64, Ordering::Relaxed);
256-
if done.is_ready() {
257-
task.done.swap(true, Ordering::Relaxed);
258-
}
259-
} else {
240+
let Some(task) = task else {
260241
// If we don't have anything ready, sleep until the next interrupt.
261242
// SAFETY: hlt is available on all reasonable x86 processors and has no safety
262243
// requirements.
263244
unsafe {
264245
core::arch::asm!("hlt");
265246
}
266247
do_wake(true);
248+
continue;
249+
};
250+
251+
// It is possible for a done task to end up in the queue (if it wakes
252+
// itself during execution). If that happens, we just remove it from
253+
// the queue here.
254+
if task.done.load(Ordering::Relaxed) {
255+
continue;
256+
}
257+
task.in_queue.store(false, Ordering::Relaxed);
258+
let waker = Waker::from(task.clone());
259+
let mut context = Context::from_waker(&waker);
260+
let mut fut = task.future.try_lock().unwrap();
261+
let begin = Timer::micros();
262+
let done = fut.0.as_mut().poll(&mut context);
263+
let end = Timer::micros();
264+
task.micros
265+
.fetch_add((end - begin) as u64, Ordering::Relaxed);
266+
if done.is_ready() {
267+
task.done.swap(true, Ordering::Relaxed);
267268
}
268269
}
269270
}
@@ -283,41 +284,23 @@ impl Executor {
283284
})
284285
}
285286

287+
// Wakes a task as soon as *any* interrupt is received.
288+
pub fn wait_for_interrupt() -> impl Future<Output = ()> {
289+
let event = Event::new();
290+
EXECUTOR.lock().wake_on_interrupt.push(event.trigger());
291+
event
292+
}
293+
286294
// Note: there are no guarantees on whether the amount of time we will sleep for
287295
// will be exceeded.
288296
pub fn sleep(time: Duration) -> impl Future<Output = ()> {
289297
let tgt = Timer::micros() + time.as_micros() as i64;
290-
let mut ww = None;
291-
poll_fn(move |cx| {
292-
let now = Timer::micros();
293-
if now >= tgt {
294-
Poll::Ready(())
295-
} else {
296-
Self::wake_at_micros(tgt, cx.waker(), &mut ww);
297-
Poll::Pending
298-
}
299-
})
300-
}
301-
302-
// Wakes a task as soon as *any* interrupt is received.
303-
pub(super) fn wake_on_interrupt(waker: &Waker) {
304-
EXECUTOR.lock().wake_on_interrupt.push(waker.clone());
305-
}
306-
307-
pub(super) fn wake_at_micros(
308-
micros: i64,
309-
waker: &Waker,
310-
previous_waker: &mut Option<WrappedWaker>,
311-
) {
312-
if !previous_waker.is_some() {
313-
let w = Arc::new(AtomicWaker::new());
314-
EXECUTOR.lock().timed_wait.push(TimedWait {
315-
wake_at: micros,
316-
waker: w.clone(),
317-
});
318-
*previous_waker = Some(w);
319-
}
320-
previous_waker.as_ref().unwrap().register(waker);
298+
let event = Event::new();
299+
EXECUTOR.lock().timed_wait.push(TimedWait {
300+
wake_at: tgt,
301+
event: event.trigger(),
302+
});
303+
event
321304
}
322305

323306
/// Spawn a new task.

pixie-uefi/src/os/input.rs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
use core::future::{poll_fn, Future};
2-
use core::task::Poll;
3-
41
use spin::lazy::Lazy;
52
use spin::Mutex;
63
use uefi::boot::ScopedProtocol;
@@ -16,16 +13,11 @@ static INPUT: Lazy<Mutex<SendWrapper<ScopedProtocol<Input>>>> = Lazy::new(|| {
1613
Mutex::new(SendWrapper(input))
1714
});
1815

19-
pub fn read_key() -> impl Future<Output = Result<Key>> {
20-
poll_fn(move |cx| {
21-
let key = INPUT.lock().read_key();
22-
match key {
23-
Err(e) => Poll::Ready(Err(e.into())),
24-
Ok(Some(key)) => Poll::Ready(Ok(key)),
25-
Ok(None) => {
26-
Executor::wake_on_interrupt(cx.waker());
27-
Poll::Pending
28-
}
16+
pub async fn read_key() -> Result<Key> {
17+
loop {
18+
if let Some(key) = INPUT.lock().read_key()? {
19+
break Ok(key);
2920
}
30-
})
21+
Executor::wait_for_interrupt().await;
22+
}
3123
}

pixie-uefi/src/os/net/mod.rs

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
use alloc::string::{String, ToString};
2-
use alloc::sync::Arc;
32
use alloc::vec::Vec;
43
use core::fmt::Write;
5-
use core::future::{poll_fn, Future};
64
use core::net::Ipv4Addr;
75
use core::sync::atomic::{AtomicU64, Ordering};
8-
use core::task::Poll;
96
use core::time::Duration;
107

11-
use futures::task::AtomicWaker;
128
use smoltcp::iface::{
139
Config, Interface, PollIngressSingleResult, PollResult, SocketHandle, SocketSet,
1410
};
@@ -25,7 +21,8 @@ use uefi::Handle;
2521

2622
use super::timer::Timer;
2723
use crate::os::boot_options::BootOptions;
28-
use crate::os::executor::{Executor, WrappedWaker};
24+
use crate::os::executor::event::{Event as ExecutorEvent, EventTrigger};
25+
use crate::os::executor::Executor;
2926
use crate::os::net::interface::SnpDevice;
3027
pub use crate::os::net::tcp::TcpStream;
3128
pub use crate::os::net::udp::UdpSocket;
@@ -51,7 +48,7 @@ struct NetworkData {
5148

5249
static NETWORK_DATA: Mutex<Option<NetworkData>> = Mutex::new(None);
5350

54-
static WAITING_FOR_IP: Mutex<Vec<WrappedWaker>> = Mutex::new(vec![]);
51+
static WAITING_FOR_IP: Mutex<Vec<EventTrigger>> = Mutex::new(vec![]);
5552

5653
fn with_net<T, F: FnOnce(&mut NetworkData) -> T>(f: F) -> T {
5754
let mut mg = NETWORK_DATA.try_lock().expect("Network is locked");
@@ -127,27 +124,28 @@ pub(super) fn init() {
127124
dhcp_socket_handle,
128125
});
129126

130-
Executor::spawn("[net_poll]", {
131-
poll_fn(move |cx| {
127+
Executor::spawn("[net_poll]", async {
128+
loop {
132129
let wait = poll();
133130
match wait {
134131
None => {
135-
Executor::wake_on_interrupt(cx.waker());
132+
Executor::wait_for_interrupt().await;
136133
}
137-
Some(x) if x < 200 => {
134+
Some(wait) if wait < 200 => {
138135
// Immediately wake if we want call poll() again in a very short time.
139-
cx.waker().wake_by_ref();
136+
Executor::sched_yield().await;
140137
}
141138
Some(wait) => {
142-
// Halve the waiting time, to try to ensure that we don't exceed the suggested
143-
// waiting time.
144-
let deadline = Timer::micros() + wait as i64 / 2;
145-
Executor::wake_on_interrupt(cx.waker());
146-
Executor::wake_at_micros(deadline, cx.waker(), &mut None);
139+
futures::future::select(
140+
Executor::wait_for_interrupt(),
141+
// Halve the waiting time, to try to ensure that we don't exceed the suggested
142+
// waiting time.
143+
Executor::sleep(Duration::from_micros(wait / 2)),
144+
)
145+
.await;
147146
}
148147
}
149-
Poll::<()>::Pending
150-
})
148+
}
151149
});
152150

153151
Executor::spawn("[show_ip]", async {
@@ -169,21 +167,13 @@ pub(super) fn init() {
169167
speed::spawn_network_speed_task();
170168
}
171169

172-
pub fn wait_for_ip() -> impl Future<Output = ()> {
173-
let mut last_waker = None;
174-
poll_fn(move |cx| {
175-
if ip().is_some() {
176-
Poll::Ready(())
177-
} else {
178-
if last_waker.is_none() {
179-
let waker = Arc::new(AtomicWaker::new());
180-
WAITING_FOR_IP.lock().push(waker.clone());
181-
last_waker = Some(waker);
182-
}
183-
last_waker.as_ref().unwrap().register(cx.waker());
184-
Poll::Pending
185-
}
186-
})
170+
pub async fn wait_for_ip() {
171+
if ip().is_some() {
172+
return;
173+
}
174+
let event = ExecutorEvent::new();
175+
WAITING_FOR_IP.lock().push(event.trigger());
176+
event.await;
187177
}
188178

189179
fn ip() -> Option<Ipv4Addr> {
@@ -232,8 +222,8 @@ fn poll() -> Option<u64> {
232222
.unwrap();
233223
}
234224
let to_wake = core::mem::take(&mut *WAITING_FOR_IP.lock());
235-
for w in to_wake {
236-
w.wake();
225+
for e in to_wake {
226+
e.trigger();
237227
}
238228
} else {
239229
interface.update_ip_addrs(|a| {

0 commit comments

Comments
 (0)