tokio/util/idle_notified_set.rs
1//! This module defines an `IdleNotifiedSet`, which is a collection of elements.
2//! Each element is intended to correspond to a task, and the collection will
3//! keep track of which tasks have had their waker notified, and which have not.
4//!
5//! Each entry in the set holds some user-specified value. The value's type is
6//! specified using the `T` parameter. It will usually be a `JoinHandle` or
7//! similar.
8
9use std::marker::PhantomPinned;
10use std::mem::ManuallyDrop;
11use std::ptr::NonNull;
12use std::task::{Context, Waker};
13
14use crate::loom::cell::UnsafeCell;
15use crate::loom::sync::{Arc, Mutex};
16use crate::util::linked_list::{self, Link, LinkedList};
17use crate::util::{waker_ref, Wake};
18
19/// This is the main handle to the collection.
20pub(crate) struct IdleNotifiedSet<T> {
21 lists: Arc<Lists<T>>,
22 length: usize,
23}
24
25/// A handle to an entry that is guaranteed to be stored in the idle or notified
26/// list of its `IdleNotifiedSet`. This value borrows the `IdleNotifiedSet`
27/// mutably to prevent the entry from being moved to the `Neither` list, which
28/// only the `IdleNotifiedSet` may do.
29///
30/// The main consequence of being stored in one of the lists is that the `value`
31/// field has not yet been consumed.
32///
33/// Note: This entry can be moved from the idle to the notified list while this
34/// object exists by waking its waker.
35pub(crate) struct EntryInOneOfTheLists<'a, T> {
36 entry: Arc<ListEntry<T>>,
37 set: &'a mut IdleNotifiedSet<T>,
38}
39
40type Lists<T> = Mutex<ListsInner<T>>;
41
42/// The linked lists hold strong references to the `ListEntry` items, and the
43/// `ListEntry` items also hold a strong reference back to the Lists object, but
44/// the destructor of the `IdleNotifiedSet` will clear the two lists, so once
45/// that object is destroyed, no ref-cycles will remain.
46struct ListsInner<T> {
47 notified: LinkedList<ListEntry<T>>,
48 idle: LinkedList<ListEntry<T>>,
49 /// Whenever an element in the `notified` list is woken, this waker will be
50 /// notified and consumed, if it exists.
51 waker: Option<Waker>,
52}
53
54/// Which of the two lists in the shared Lists object is this entry stored in?
55///
56/// If the value is `Idle`, then an entry's waker may move it to the notified
57/// list. Otherwise, only the `IdleNotifiedSet` may move it.
58///
59/// If the value is `Neither`, then it is still possible that the entry is in
60/// some third external list (this happens in `drain`).
61#[derive(Copy, Clone, Eq, PartialEq)]
62enum List {
63 Notified,
64 Idle,
65 Neither,
66}
67
68/// An entry in the list.
69///
70/// # Safety
71///
72/// The `my_list` field must only be accessed while holding the mutex in
73/// `parent`. It is an invariant that the value of `my_list` corresponds to
74/// which linked list in the `parent` holds this entry. Once this field takes
75/// the value `Neither`, then it may never be modified again.
76///
77/// If the value of `my_list` is `Notified` or `Idle`, then the `pointers` field
78/// must only be accessed while holding the mutex. If the value of `my_list` is
79/// `Neither`, then the `pointers` field may be accessed by the
80/// `IdleNotifiedSet` (this happens inside `drain`).
81///
82/// The `value` field is owned by the `IdleNotifiedSet` and may only be accessed
83/// by the `IdleNotifiedSet`. The operation that sets the value of `my_list` to
84/// `Neither` assumes ownership of the `value`, and it must either drop it or
85/// move it out from this entry to prevent it from getting leaked. (Since the
86/// two linked lists are emptied in the destructor of `IdleNotifiedSet`, the
87/// value should not be leaked.)
88struct ListEntry<T> {
89 /// The linked list pointers of the list this entry is in.
90 pointers: linked_list::Pointers<ListEntry<T>>,
91 /// Pointer to the shared `Lists` struct.
92 parent: Arc<Lists<T>>,
93 /// The value stored in this entry.
94 value: UnsafeCell<ManuallyDrop<T>>,
95 /// Used to remember which list this entry is in.
96 my_list: UnsafeCell<List>,
97 /// Required by the `linked_list::Pointers` field.
98 _pin: PhantomPinned,
99}
100
101generate_addr_of_methods! {
102 impl<T> ListEntry<T> {
103 unsafe fn addr_of_pointers(self: NonNull<Self>) -> NonNull<linked_list::Pointers<ListEntry<T>>> {
104 &self.pointers
105 }
106 }
107}
108
109// With mutable access to the `IdleNotifiedSet`, you can get mutable access to
110// the values.
111unsafe impl<T: Send> Send for IdleNotifiedSet<T> {}
112// With the current API we strictly speaking don't even need `T: Sync`, but we
113// require it anyway to support adding &self APIs that access the values in the
114// future.
115unsafe impl<T: Sync> Sync for IdleNotifiedSet<T> {}
116
117// These impls control when it is safe to create a Waker. Since the waker does
118// not allow access to the value in any way (including its destructor), it is
119// not necessary for `T` to be Send or Sync.
120unsafe impl<T> Send for ListEntry<T> {}
121unsafe impl<T> Sync for ListEntry<T> {}
122
123impl<T> IdleNotifiedSet<T> {
124 /// Create a new `IdleNotifiedSet`.
125 pub(crate) fn new() -> Self {
126 let lists = Mutex::new(ListsInner {
127 notified: LinkedList::new(),
128 idle: LinkedList::new(),
129 waker: None,
130 });
131
132 IdleNotifiedSet {
133 lists: Arc::new(lists),
134 length: 0,
135 }
136 }
137
138 pub(crate) fn len(&self) -> usize {
139 self.length
140 }
141
142 pub(crate) fn is_empty(&self) -> bool {
143 self.length == 0
144 }
145
146 /// Insert the given value into the `idle` list.
147 pub(crate) fn insert_idle(&mut self, value: T) -> EntryInOneOfTheLists<'_, T> {
148 self.length += 1;
149
150 let entry = Arc::new(ListEntry {
151 parent: self.lists.clone(),
152 value: UnsafeCell::new(ManuallyDrop::new(value)),
153 my_list: UnsafeCell::new(List::Idle),
154 pointers: linked_list::Pointers::new(),
155 _pin: PhantomPinned,
156 });
157
158 {
159 let mut lock = self.lists.lock();
160 lock.idle.push_front(entry.clone());
161 }
162
163 // Safety: We just put the entry in the idle list, so it is in one of the lists.
164 EntryInOneOfTheLists { entry, set: self }
165 }
166
167 /// Pop an entry from the notified list to poll it. The entry is moved to
168 /// the idle list atomically.
169 pub(crate) fn pop_notified(&mut self, waker: &Waker) -> Option<EntryInOneOfTheLists<'_, T>> {
170 // We don't decrement the length because this call moves the entry to
171 // the idle list rather than removing it.
172 if self.length == 0 {
173 // Fast path.
174 return None;
175 }
176
177 let mut lock = self.lists.lock();
178
179 let should_update_waker = match lock.waker.as_mut() {
180 Some(cur_waker) => !waker.will_wake(cur_waker),
181 None => true,
182 };
183 if should_update_waker {
184 lock.waker = Some(waker.clone());
185 }
186
187 // Pop the entry, returning None if empty.
188 let entry = lock.notified.pop_back()?;
189
190 lock.idle.push_front(entry.clone());
191
192 // Safety: We are holding the lock.
193 entry.my_list.with_mut(|ptr| unsafe {
194 *ptr = List::Idle;
195 });
196
197 drop(lock);
198
199 // Safety: We just put the entry in the idle list, so it is in one of the lists.
200 Some(EntryInOneOfTheLists { entry, set: self })
201 }
202
203 /// Tries to pop an entry from the notified list to poll it. The entry is moved to
204 /// the idle list atomically.
205 pub(crate) fn try_pop_notified(&mut self) -> Option<EntryInOneOfTheLists<'_, T>> {
206 // We don't decrement the length because this call moves the entry to
207 // the idle list rather than removing it.
208 if self.length == 0 {
209 // Fast path.
210 return None;
211 }
212
213 let mut lock = self.lists.lock();
214
215 // Pop the entry, returning None if empty.
216 let entry = lock.notified.pop_back()?;
217
218 lock.idle.push_front(entry.clone());
219
220 // Safety: We are holding the lock.
221 entry.my_list.with_mut(|ptr| unsafe {
222 *ptr = List::Idle;
223 });
224
225 drop(lock);
226
227 // Safety: We just put the entry in the idle list, so it is in one of the lists.
228 Some(EntryInOneOfTheLists { entry, set: self })
229 }
230
231 /// Call a function on every element in this list.
232 pub(crate) fn for_each<F: FnMut(&mut T)>(&mut self, mut func: F) {
233 fn get_ptrs<T>(list: &mut LinkedList<ListEntry<T>>, ptrs: &mut Vec<*mut T>) {
234 let mut node = list.last();
235
236 while let Some(entry) = node {
237 ptrs.push(entry.value.with_mut(|ptr| {
238 let ptr: *mut ManuallyDrop<T> = ptr;
239 let ptr: *mut T = ptr.cast();
240 ptr
241 }));
242
243 let prev = entry.pointers.get_prev();
244 node = prev.map(|prev| unsafe { &*prev.as_ptr() });
245 }
246 }
247
248 // Atomically get a raw pointer to the value of every entry.
249 //
250 // Since this only locks the mutex once, it is not possible for a value
251 // to get moved from the idle list to the notified list during the
252 // operation, which would otherwise result in some value being listed
253 // twice.
254 let mut ptrs = Vec::with_capacity(self.len());
255 {
256 let mut lock = self.lists.lock();
257
258 get_ptrs(&mut lock.idle, &mut ptrs);
259 get_ptrs(&mut lock.notified, &mut ptrs);
260 }
261 debug_assert_eq!(ptrs.len(), ptrs.capacity());
262
263 for ptr in ptrs {
264 // Safety: When we grabbed the pointers, the entries were in one of
265 // the two lists. This means that their value was valid at the time,
266 // and it must still be valid because we are the IdleNotifiedSet,
267 // and only we can remove an entry from the two lists. (It's
268 // possible that an entry is moved from one list to the other during
269 // this loop, but that is ok.)
270 func(unsafe { &mut *ptr });
271 }
272 }
273
274 /// Remove all entries in both lists, applying some function to each element.
275 ///
276 /// The closure is called on all elements even if it panics. Having it panic
277 /// twice is a double-panic, and will abort the application.
278 pub(crate) fn drain<F: FnMut(T)>(&mut self, func: F) {
279 if self.length == 0 {
280 // Fast path.
281 return;
282 }
283 self.length = 0;
284
285 // The LinkedList is not cleared on panic, so we use a bomb to clear it.
286 //
287 // This value has the invariant that any entry in its `all_entries` list
288 // has `my_list` set to `Neither` and that the value has not yet been
289 // dropped.
290 struct AllEntries<T, F: FnMut(T)> {
291 all_entries: LinkedList<ListEntry<T>>,
292 func: F,
293 }
294
295 impl<T, F: FnMut(T)> AllEntries<T, F> {
296 fn pop_next(&mut self) -> bool {
297 if let Some(entry) = self.all_entries.pop_back() {
298 // Safety: We just took this value from the list, so we can
299 // destroy the value in the entry.
300 entry
301 .value
302 .with_mut(|ptr| unsafe { (self.func)(ManuallyDrop::take(&mut *ptr)) });
303 true
304 } else {
305 false
306 }
307 }
308 }
309
310 impl<T, F: FnMut(T)> Drop for AllEntries<T, F> {
311 fn drop(&mut self) {
312 while self.pop_next() {}
313 }
314 }
315
316 let mut all_entries = AllEntries {
317 all_entries: LinkedList::new(),
318 func,
319 };
320
321 // Atomically move all entries to the new linked list in the AllEntries
322 // object.
323 {
324 let mut lock = self.lists.lock();
325 unsafe {
326 // Safety: We are holding the lock and `all_entries` is a new
327 // LinkedList.
328 move_to_new_list(&mut lock.idle, &mut all_entries.all_entries);
329 move_to_new_list(&mut lock.notified, &mut all_entries.all_entries);
330 }
331 }
332
333 // Keep destroying entries in the list until it is empty.
334 //
335 // If the closure panics, then the destructor of the `AllEntries` bomb
336 // ensures that we keep running the destructor on the remaining values.
337 // A second panic will abort the program.
338 while all_entries.pop_next() {}
339 }
340}
341
342/// # Safety
343///
344/// The mutex for the entries must be held, and the target list must be such
345/// that setting `my_list` to `Neither` is ok.
346unsafe fn move_to_new_list<T>(
347 from: &mut LinkedList<ListEntry<T>>,
348 to: &mut LinkedList<ListEntry<T>>,
349) {
350 while let Some(entry) = from.pop_back() {
351 entry.my_list.with_mut(|ptr| {
352 // Safety: pointer is accessed while holding the mutex.
353 unsafe {
354 *ptr = List::Neither;
355 }
356 });
357 to.push_front(entry);
358 }
359}
360
361impl<'a, T> EntryInOneOfTheLists<'a, T> {
362 /// Remove this entry from the list it is in, returning the value associated
363 /// with the entry.
364 ///
365 /// This consumes the value, since it is no longer guaranteed to be in a
366 /// list.
367 pub(crate) fn remove(self) -> T {
368 self.set.length -= 1;
369
370 {
371 let mut lock = self.set.lists.lock();
372
373 // Safety: We are holding the lock so there is no race, and we will
374 // remove the entry afterwards to uphold invariants.
375 let old_my_list = self.entry.my_list.with_mut(|ptr| unsafe {
376 let old_my_list = *ptr;
377 *ptr = List::Neither;
378 old_my_list
379 });
380
381 let list = match old_my_list {
382 List::Idle => &mut lock.idle,
383 List::Notified => &mut lock.notified,
384 // An entry in one of the lists is in one of the lists.
385 List::Neither => unreachable!(),
386 };
387
388 unsafe {
389 // Safety: We just checked that the entry is in this particular
390 // list.
391 list.remove(ListEntry::as_raw(&self.entry)).unwrap();
392 }
393 }
394
395 // By setting `my_list` to `Neither`, we have taken ownership of the
396 // value. We return it to the caller.
397 //
398 // Safety: We have a mutable reference to the `IdleNotifiedSet` that
399 // owns this entry, so we can use its permission to access the value.
400 self.entry
401 .value
402 .with_mut(|ptr| unsafe { ManuallyDrop::take(&mut *ptr) })
403 }
404
405 /// Access the value in this entry together with a context for its waker.
406 pub(crate) fn with_value_and_context<F, U>(&mut self, func: F) -> U
407 where
408 F: FnOnce(&mut T, &mut Context<'_>) -> U,
409 T: 'static,
410 {
411 let waker = waker_ref(&self.entry);
412
413 let mut context = Context::from_waker(&waker);
414
415 // Safety: We have a mutable reference to the `IdleNotifiedSet` that
416 // owns this entry, so we can use its permission to access the value.
417 self.entry
418 .value
419 .with_mut(|ptr| unsafe { func(&mut *ptr, &mut context) })
420 }
421}
422
423impl<T> Drop for IdleNotifiedSet<T> {
424 fn drop(&mut self) {
425 // Clear both lists.
426 self.drain(drop);
427
428 #[cfg(debug_assertions)]
429 if !std::thread::panicking() {
430 let lock = self.lists.lock();
431 assert!(lock.idle.is_empty());
432 assert!(lock.notified.is_empty());
433 }
434 }
435}
436
437impl<T: 'static> Wake for ListEntry<T> {
438 fn wake_by_ref(me: &Arc<Self>) {
439 let mut lock = me.parent.lock();
440
441 // Safety: We are holding the lock and we will update the lists to
442 // maintain invariants.
443 let old_my_list = me.my_list.with_mut(|ptr| unsafe {
444 let old_my_list = *ptr;
445 if old_my_list == List::Idle {
446 *ptr = List::Notified;
447 }
448 old_my_list
449 });
450
451 if old_my_list == List::Idle {
452 // We move ourself to the notified list.
453 let me = unsafe {
454 // Safety: We just checked that we are in this particular list.
455 lock.idle.remove(ListEntry::as_raw(me)).unwrap()
456 };
457 lock.notified.push_front(me);
458
459 if let Some(waker) = lock.waker.take() {
460 drop(lock);
461 waker.wake();
462 }
463 }
464 }
465
466 fn wake(me: Arc<Self>) {
467 Self::wake_by_ref(&me);
468 }
469}
470
471/// # Safety
472///
473/// `ListEntry` is forced to be !Unpin.
474unsafe impl<T> linked_list::Link for ListEntry<T> {
475 type Handle = Arc<ListEntry<T>>;
476 type Target = ListEntry<T>;
477
478 fn as_raw(handle: &Self::Handle) -> NonNull<ListEntry<T>> {
479 let ptr: *const ListEntry<T> = Arc::as_ptr(handle);
480 // Safety: We can't get a null pointer from `Arc::as_ptr`.
481 unsafe { NonNull::new_unchecked(ptr as *mut ListEntry<T>) }
482 }
483
484 unsafe fn from_raw(ptr: NonNull<ListEntry<T>>) -> Arc<ListEntry<T>> {
485 unsafe { Arc::from_raw(ptr.as_ptr()) }
486 }
487
488 unsafe fn pointers(
489 target: NonNull<ListEntry<T>>,
490 ) -> NonNull<linked_list::Pointers<ListEntry<T>>> {
491 unsafe { ListEntry::addr_of_pointers(target) }
492 }
493}
494
495#[cfg(all(test, not(loom)))]
496mod tests {
497 use crate::runtime::Builder;
498 use crate::task::JoinSet;
499
500 // A test that runs under miri.
501 //
502 // https://github.com/tokio-rs/tokio/pull/5693
503 #[test]
504 fn join_set_test() {
505 let rt = Builder::new_current_thread().build().unwrap();
506
507 let mut set = JoinSet::new();
508 set.spawn_on(futures::future::ready(()), rt.handle());
509
510 rt.block_on(set.join_next()).unwrap().unwrap();
511 }
512}