Skip to content

Commit e132fc8

Browse files
committed
Replace Slab-backed waker list with linked list
Signed-off-by: Gary Guo <gary@garyguo.net>
1 parent ba871b6 commit e132fc8

File tree

3 files changed

+148
-26
lines changed

3 files changed

+148
-26
lines changed

src/sync/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub use rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
3737

3838
mod mutex;
3939
mod rwlock;
40+
mod waker_list;
4041

4142
cfg_unstable! {
4243
pub use barrier::{Barrier, BarrierWaitResult};

src/sync/mutex.rs

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ use std::ops::{Deref, DerefMut};
44
use std::pin::Pin;
55
use std::sync::atomic::{AtomicUsize, Ordering};
66

7-
use slab::Slab;
8-
97
use crate::future::Future;
10-
use crate::task::{Context, Poll, Waker};
8+
use crate::task::{Context, Poll};
9+
10+
use super::waker_list::WakerList;
11+
use std::num::NonZeroUsize;
1112

1213
/// Set if the mutex is locked.
1314
const LOCK: usize = 1;
@@ -17,7 +18,7 @@ const BLOCKED: usize = 1 << 1;
1718

1819
struct RawMutex {
1920
state: AtomicUsize,
20-
blocked: std::sync::Mutex<Slab<Option<Waker>>>,
21+
blocked: std::sync::Mutex<WakerList>,
2122
}
2223

2324
unsafe impl Send for RawMutex {}
@@ -29,7 +30,7 @@ impl RawMutex {
2930
pub fn new() -> RawMutex {
3031
RawMutex {
3132
state: AtomicUsize::new(0),
32-
blocked: std::sync::Mutex::new(Slab::new()),
33+
blocked: std::sync::Mutex::new(WakerList::new()),
3334
}
3435
}
3536

@@ -54,13 +55,7 @@ impl RawMutex {
5455
#[cold]
5556
fn unlock_slow(&self) {
5657
let mut blocked = self.blocked.lock().unwrap();
57-
58-
if let Some((_, opt_waker)) = blocked.iter_mut().next() {
59-
// If there is no waker in this entry, that means it was already woken.
60-
if let Some(w) = opt_waker.take() {
61-
w.wake();
62-
}
63-
}
58+
blocked.wake_one_weak();
6459
}
6560

6661
/// Unlock this mutex.
@@ -77,7 +72,7 @@ impl RawMutex {
7772

7873
struct RawLockFuture<'a> {
7974
mutex: &'a RawMutex,
80-
opt_key: Option<usize>,
75+
opt_key: Option<NonZeroUsize>,
8176
acquired: bool,
8277
}
8378

@@ -94,21 +89,22 @@ impl<'a> Future for RawLockFuture<'a> {
9489
// Register the current task.
9590
match self.opt_key {
9691
None => {
92+
if blocked.is_empty() {
93+
self.mutex.state.fetch_or(BLOCKED, Ordering::Relaxed);
94+
}
95+
9796
// Insert a new entry into the list of blocked tasks.
9897
let w = cx.waker().clone();
9998
let key = blocked.insert(Some(w));
10099
self.opt_key = Some(key);
101-
102-
if blocked.len() == 1 {
103-
self.mutex.state.fetch_or(BLOCKED, Ordering::Relaxed);
104-
}
105100
}
106101
Some(key) => {
107102
// There is already an entry in the list of blocked tasks. Just
108103
// reset the waker if it was removed.
109-
if blocked[key].is_none() {
104+
let opt_waker = unsafe { blocked.get(key) };
105+
if opt_waker.is_none() {
110106
let w = cx.waker().clone();
111-
blocked[key] = Some(w);
107+
*opt_waker = Some(w);
112108
}
113109
}
114110
}
@@ -129,16 +125,11 @@ impl Drop for RawLockFuture<'_> {
129125
fn drop(&mut self) {
130126
if let Some(key) = self.opt_key {
131127
let mut blocked = self.mutex.blocked.lock().unwrap();
132-
let opt_waker = blocked.remove(key);
128+
let opt_waker = unsafe { blocked.remove(key) };
133129

134130
if opt_waker.is_none() && !self.acquired {
135131
// We were awoken but didn't acquire the lock. Wake up another task.
136-
if let Some((_, opt_waker)) = blocked.iter_mut().next() {
137-
// If there is no waker in this entry, that means it was already woken.
138-
if let Some(w) = opt_waker.take() {
139-
w.wake();
140-
}
141-
}
132+
blocked.wake_one_weak();
142133
}
143134

144135
if blocked.is_empty() {

src/sync/waker_list.rs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
use crate::task::Waker;
2+
3+
use std::num::NonZeroUsize;
4+
5+
struct WakerNode {
6+
/// Previous `WakerNode` in the queue. If this node is the first node, it shall point to the last node.
7+
prev_in_queue: *mut WakerNode,
8+
/// Next `WakerNode` in the queue. If this node is the last node, it shall be null.
9+
next_in_queue: *mut WakerNode,
10+
waker: Option<Waker>,
11+
}
12+
13+
pub struct WakerList {
14+
head: *mut WakerNode,
15+
}
16+
17+
unsafe impl Send for WakerList {}
18+
unsafe impl Sync for WakerList {}
19+
20+
impl WakerList {
21+
/// Create a new empty `WakerList`
22+
pub fn new() -> Self {
23+
Self {
24+
head: std::ptr::null_mut(),
25+
}
26+
}
27+
28+
/// Insert a waker to the back of the list, and return its key.
29+
pub fn insert(&mut self, waker: Option<Waker>) -> NonZeroUsize {
30+
let node = Box::into_raw(Box::new(WakerNode {
31+
waker,
32+
next_in_queue: std::ptr::null_mut(),
33+
prev_in_queue: std::ptr::null_mut(),
34+
}));
35+
36+
if self.head.is_null() {
37+
unsafe {
38+
(*node).prev_in_queue = node;
39+
}
40+
self.head = node;
41+
} else {
42+
unsafe {
43+
let prev = std::mem::replace(&mut (*self.head).prev_in_queue, node);
44+
(*prev).next_in_queue = node;
45+
(*node).prev_in_queue = prev;
46+
}
47+
}
48+
49+
unsafe { NonZeroUsize::new_unchecked(node as usize) }
50+
}
51+
52+
/// Remove a waker by its key.
53+
///
54+
/// # Safety
55+
/// This function is unsafe because there is no guarantee that key is the previously returned
56+
/// key, and that the key is only removed once.
57+
pub unsafe fn remove(&mut self, key: NonZeroUsize) -> Option<Waker> {
58+
let node = key.get() as *mut WakerNode;
59+
let prev = (*node).prev_in_queue;
60+
let next = (*node).next_in_queue;
61+
62+
// Special treatment on removing first node
63+
if self.head == node {
64+
self.head = next;
65+
} else {
66+
std::mem::replace(&mut (*prev).next_in_queue, next);
67+
}
68+
69+
// Special treatment on removing last node
70+
if next.is_null() {
71+
if !self.head.is_null() {
72+
std::mem::replace(&mut (*self.head).prev_in_queue, prev);
73+
}
74+
} else {
75+
std::mem::replace(&mut (*next).prev_in_queue, prev);
76+
}
77+
78+
Box::from_raw(node).waker
79+
}
80+
81+
/// Get a waker by its key.
82+
///
83+
/// # Safety
84+
/// This function is unsafe because there is no guarantee that key is the previously returned
85+
/// key, and that the key is not removed.
86+
pub unsafe fn get(&mut self, key: NonZeroUsize) -> &mut Option<Waker> {
87+
&mut (*(key.get() as *mut WakerNode)).waker
88+
}
89+
90+
/// Check if this list is empty.
91+
pub fn is_empty(&self) -> bool {
92+
self.head.is_null()
93+
}
94+
95+
/// Get an iterator over all wakers.
96+
pub fn iter_mut(&mut self) -> Iter<'_> {
97+
Iter {
98+
ptr: self.head,
99+
_marker: std::marker::PhantomData,
100+
}
101+
}
102+
103+
/// Wake the first waker in the list, and convert it to `None`. This function is named `weak` as
104+
/// nothing is performed when the first waker is waken already.
105+
pub fn wake_one_weak(&mut self) {
106+
if let Some(opt_waker) = self.iter_mut().next() {
107+
if let Some(w) = opt_waker.take() {
108+
w.wake();
109+
}
110+
}
111+
}
112+
}
113+
114+
pub struct Iter<'a> {
115+
ptr: *mut WakerNode,
116+
_marker: std::marker::PhantomData<&'a ()>,
117+
}
118+
119+
impl<'a> Iterator for Iter<'a> {
120+
type Item = &'a mut Option<Waker>;
121+
122+
fn next(&mut self) -> Option<Self::Item> {
123+
if self.ptr.is_null() {
124+
return None;
125+
}
126+
let next = unsafe { (*self.ptr).next_in_queue };
127+
let ptr = std::mem::replace(&mut self.ptr, next);
128+
Some(unsafe { &mut (*ptr).waker })
129+
}
130+
}

0 commit comments

Comments
 (0)