aboutsummaryrefslogtreecommitdiff
path: root/rtic-time/src/lib.rs
diff options
context:
space:
mode:
authorEmil Fresk <emil.fresk@gmail.com>2023-01-28 13:21:44 +0100
committerHenrik Tjäder <henrik@tjaders.com>2023-03-01 00:33:36 +0100
commit3050fc0591f087a4fbe08840c69633e89d3f58a7 (patch)
tree63c26184993ce42c63102e174d781c5d52da6623 /rtic-time/src/lib.rs
parent5908d5bdbc3a3daf741d58b925fa280a3a81bf6a (diff)
Use `Pin` in the linked lists
Diffstat (limited to 'rtic-time/src/lib.rs')
-rw-r--r--rtic-time/src/lib.rs18
1 files changed, 15 insertions, 3 deletions
diff --git a/rtic-time/src/lib.rs b/rtic-time/src/lib.rs
index eeecd86..6b23f76 100644
--- a/rtic-time/src/lib.rs
+++ b/rtic-time/src/lib.rs
@@ -7,6 +7,7 @@
#![feature(async_fn_in_trait)]
use core::future::{poll_fn, Future};
+use core::pin::Pin;
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use core::task::{Poll, Waker};
use futures_util::{
@@ -185,7 +186,10 @@ impl<Mono: Monotonic> TimerQueue<Mono> {
);
}
- let mut link = None;
+ let mut link_ptr: Option<linked_list::Link<WaitingWaker<Mono>>> = None;
+
+ // Make this future `Drop`-safe, also shadow the original definition so we can't abuse it.
+ let link_ptr = &mut link_ptr as *mut Option<linked_list::Link<WaitingWaker<Mono>>>;
let queue = &self.queue;
let marker = &AtomicUsize::new(0);
@@ -199,6 +203,9 @@ impl<Mono: Monotonic> TimerQueue<Mono> {
return Poll::Ready(());
}
+ // SAFETY: This pointer is only dereferenced here and on drop of the future
+ // which happens outside this `poll_fn`'s stack frame.
+ let link = unsafe { &mut *link_ptr };
if link.is_none() {
let mut link_ref = link.insert(Link::new(WaitingWaker {
waker: cx.waker().clone(),
@@ -206,7 +213,9 @@ impl<Mono: Monotonic> TimerQueue<Mono> {
was_poped: AtomicBool::new(false),
}));
- let (was_empty, addr) = queue.insert(&mut link_ref);
+ // SAFETY: The address to the link is stable as it is defined outside this stack
+ // frame.
+ let (was_empty, addr) = queue.insert(unsafe { Pin::new_unchecked(&mut link_ref) });
marker.store(addr, Ordering::Relaxed);
if was_empty {
@@ -219,7 +228,10 @@ impl<Mono: Monotonic> TimerQueue<Mono> {
})
.await;
- if let Some(link) = link {
+ // SAFETY: We only run this and dereference the pointer if we have
+ // exited the `poll_fn` below in the `drop(dropper)` call. The other dereference
+ // of this pointer is in the `poll_fn`.
+ if let Some(link) = unsafe { &mut *link_ptr } {
if link.val.was_poped.load(Ordering::Relaxed) {
// If it was poped from the queue there is no need to run delete
dropper.defuse();