1use crate::notify::{GenericNotify, Internal, Notification};
7use crate::sync::atomic::Ordering;
8use crate::sync::cell::{Cell, UnsafeCell};
9use crate::{RegisterResult, State, TaskRef};
10
11#[cfg(feature = "critical-section")]
12use core::cell::RefCell;
13#[cfg(all(feature = "std", not(feature = "critical-section")))]
14use core::ops::{Deref, DerefMut};
15
16use core::marker::PhantomPinned;
17use core::mem;
18use core::pin::Pin;
19use core::ptr::NonNull;
20
21pub(super) struct List<T>(
22 #[cfg(all(feature = "std", not(feature = "critical-section")))]
24 crate::sync::Mutex<Inner<T>>,
25 #[cfg(feature = "critical-section")]
27 critical_section::Mutex<RefCell<Inner<T>>>,
28 #[cfg(not(any(feature = "std", feature = "critical-section")))]
30 spinlock::Spinlock<Inner<T>>,
31);
32
33struct Inner<T> {
34 head: Option<NonNull<Link<T>>>,
36
37 tail: Option<NonNull<Link<T>>>,
39
40 next: Option<NonNull<Link<T>>>,
42
43 len: usize,
45
46 notified: usize,
48}
49
50impl<T> List<T> {
51 pub(super) fn new() -> Self {
53 let inner = Inner {
54 head: None,
55 tail: None,
56 next: None,
57 len: 0,
58 notified: 0,
59 };
60
61 #[cfg(feature = "critical-section")]
62 {
63 Self(critical_section::Mutex::new(RefCell::new(inner)))
64 }
65
66 #[cfg(all(not(feature = "critical-section"), feature = "std"))]
67 {
68 Self(crate::sync::Mutex::new(inner))
69 }
70
71 #[cfg(not(any(feature = "std", feature = "critical-section")))]
72 {
73 Self(spinlock::Spinlock::new(inner))
74 }
75 }
76
77 #[cfg(all(feature = "std", not(feature = "critical-section")))]
79 pub(crate) fn try_total_listeners(&self) -> Option<usize> {
80 self.0.try_lock().ok().map(|list| list.len)
81 }
82
83 #[cfg(feature = "critical-section")]
85 pub(crate) fn try_total_listeners(&self) -> Option<usize> {
86 Some(self.total_listeners())
87 }
88
89 #[cfg(not(any(feature = "std", feature = "critical-section")))]
91 pub(crate) fn try_total_listeners(&self) -> Option<usize> {
92 self.0.try_with(|list| list.len)
93 }
94
95 #[cfg(all(feature = "std", not(feature = "critical-section")))]
97 pub(crate) fn total_listeners(&self) -> usize {
98 self.0.lock().unwrap_or_else(|e| e.into_inner()).len
99 }
100
101 #[cfg(feature = "critical-section")]
103 #[allow(unused)]
104 pub(crate) fn total_listeners(&self) -> usize {
105 critical_section::with(|cs| self.0.borrow(cs).borrow().len)
106 }
107}
108
109impl<T> crate::Inner<T> {
110 #[cfg(all(feature = "std", not(feature = "critical-section")))]
111 fn with_inner<R>(&self, f: impl FnOnce(&mut Inner<T>) -> R) -> R {
112 struct ListLock<'a, 'b, T> {
113 lock: crate::sync::MutexGuard<'a, Inner<T>>,
114 inner: &'b crate::Inner<T>,
115 }
116
117 impl<T> Deref for ListLock<'_, '_, T> {
118 type Target = Inner<T>;
119
120 fn deref(&self) -> &Self::Target {
121 &self.lock
122 }
123 }
124
125 impl<T> DerefMut for ListLock<'_, '_, T> {
126 fn deref_mut(&mut self) -> &mut Self::Target {
127 &mut self.lock
128 }
129 }
130
131 impl<T> Drop for ListLock<'_, '_, T> {
132 fn drop(&mut self) {
133 update_notified(&self.inner.notified, &self.lock);
134 }
135 }
136
137 let mut list = ListLock {
138 inner: self,
139 lock: self.list.0.lock().unwrap_or_else(|e| e.into_inner()),
140 };
141 f(&mut list)
142 }
143
144 #[cfg(any(not(feature = "std"), feature = "critical-section"))]
145 fn with_inner<R>(&self, f: impl FnOnce(&mut Inner<T>) -> R) -> R {
146 struct ListWrapper<'a, T> {
147 inner: &'a crate::Inner<T>,
148 list: &'a mut Inner<T>,
149 }
150
151 impl<T> Drop for ListWrapper<'_, T> {
152 fn drop(&mut self) {
153 update_notified(&self.inner.notified, self.list);
154 }
155 }
156
157 #[cfg(feature = "critical-section")]
158 return critical_section::with(move |cs| {
159 let mut list = self.list.0.borrow_ref_mut(cs);
160 let wrapper = ListWrapper {
161 inner: self,
162 list: &mut *list,
163 };
164
165 f(wrapper.list)
166 });
167
168 #[cfg(not(feature = "critical-section"))]
169 self.list.0.with(move |list| {
170 let wrapper = ListWrapper {
171 inner: self,
172 list: &mut *list,
173 };
174
175 f(wrapper.list)
176 })
177 }
178
179 pub(crate) fn insert(&self, mut listener: Pin<&mut Option<Listener<T>>>) {
181 self.with_inner(|inner| {
182 listener.as_mut().set(Some(Listener {
183 link: UnsafeCell::new(Link {
184 state: Cell::new(State::Created),
185 prev: Cell::new(inner.tail),
186 next: Cell::new(None),
187 }),
188 _pin: PhantomPinned,
189 }));
190 let listener = listener.as_pin_mut().unwrap();
191
192 {
193 let entry_guard = listener.link.get();
194 let entry = unsafe { entry_guard.deref() };
196
197 match inner.tail.replace(entry.into()) {
199 None => inner.head = Some(entry.into()),
200 Some(t) => unsafe { t.as_ref().next.set(Some(entry.into())) },
201 };
202 }
203
204 if inner.next.is_none() {
206 inner.next = inner.tail;
207 }
208
209 inner.len += 1;
211 });
212 }
213
214 pub(crate) fn remove(
216 &self,
217 listener: Pin<&mut Option<Listener<T>>>,
218 propagate: bool,
219 ) -> Option<State<T>> {
220 self.with_inner(|inner| inner.remove(listener, propagate))
221 }
222
223 #[cold]
225 pub(crate) fn notify(&self, notify: impl Notification<Tag = T>) -> usize {
226 self.with_inner(|inner| inner.notify(notify))
227 }
228
229 pub(crate) fn register(
234 &self,
235 mut listener: Pin<&mut Option<Listener<T>>>,
236 task: TaskRef<'_>,
237 ) -> RegisterResult<T> {
238 self.with_inner(|inner| {
239 let entry_guard = match listener.as_mut().as_pin_mut() {
240 Some(listener) => listener.link.get(),
241 None => return RegisterResult::NeverInserted,
242 };
243 let entry = unsafe { entry_guard.deref() };
245
246 match entry.state.replace(State::NotifiedTaken) {
248 State::Notified { tag, .. } => {
249 inner.remove(listener, false);
251 RegisterResult::Notified(tag)
252 }
253
254 State::Task(other_task) => {
255 entry.state.set(State::Task({
257 if !task.will_wake(other_task.as_task_ref()) {
258 task.into_task()
259 } else {
260 other_task
261 }
262 }));
263
264 RegisterResult::Registered
265 }
266
267 _ => {
268 entry.state.set(State::Task(task.into_task()));
270 RegisterResult::Registered
271 }
272 }
273 })
274 }
275}
276
277impl<T> Inner<T> {
278 fn remove(
279 &mut self,
280 mut listener: Pin<&mut Option<Listener<T>>>,
281 propagate: bool,
282 ) -> Option<State<T>> {
283 let entry_guard = listener.as_mut().as_pin_mut()?.link.get();
284 let entry = unsafe { entry_guard.deref() };
285
286 let prev = entry.prev.get();
287 let next = entry.next.get();
288
289 match prev {
291 None => self.head = next,
292 Some(p) => unsafe {
293 p.as_ref().next.set(next);
294 },
295 }
296
297 match next {
299 None => self.tail = prev,
300 Some(n) => unsafe {
301 n.as_ref().prev.set(prev);
302 },
303 }
304
305 if self.next == Some(entry.into()) {
307 self.next = next;
308 }
309
310 let entry = unsafe {
312 listener
313 .get_unchecked_mut()
314 .take()
315 .unwrap()
316 .link
317 .into_inner()
318 };
319
320 let mut state = entry.state.replace(State::Created);
325
326 if state.is_notified() {
328 self.notified -= 1;
329
330 if propagate {
331 let state = mem::replace(&mut state, State::NotifiedTaken);
332 if let State::Notified { additional, tag } = state {
333 let tags = {
334 let mut tag = Some(tag);
335 move || tag.take().expect("tag already taken")
336 };
337 self.notify(GenericNotify::new(1, additional, tags));
338 }
339 }
340 }
341 self.len -= 1;
342
343 Some(state)
344 }
345
346 #[cold]
347 fn notify(&mut self, mut notify: impl Notification<Tag = T>) -> usize {
348 let mut n = notify.count(Internal::new());
349 let is_additional = notify.is_additional(Internal::new());
350
351 if !is_additional {
352 if n < self.notified {
353 return 0;
354 }
355 n -= self.notified;
356 }
357
358 let original_count = n;
359 while n > 0 {
360 n -= 1;
361
362 match self.next {
364 None => return original_count - n - 1,
365
366 Some(e) => {
367 let entry = unsafe { e.as_ref() };
369 self.next = entry.next.get();
370
371 let tag = notify.next_tag(Internal::new());
373 if let State::Task(task) = entry.state.replace(State::Notified {
374 additional: is_additional,
375 tag,
376 }) {
377 task.wake();
378 }
379
380 self.notified += 1;
382 }
383 }
384 }
385
386 original_count - n
387 }
388}
389
390fn update_notified<T>(slot: &crate::sync::atomic::AtomicUsize, list: &Inner<T>) {
391 let notified = if list.notified < list.len {
393 list.notified
394 } else {
395 usize::MAX
396 };
397
398 slot.store(notified, Ordering::Release);
399}
400
401pub(crate) struct Listener<T> {
402 link: UnsafeCell<Link<T>>,
408
409 _pin: PhantomPinned,
411}
412
413struct Link<T> {
414 state: Cell<State<T>>,
416
417 prev: Cell<Option<NonNull<Link<T>>>>,
419
420 next: Cell<Option<NonNull<Link<T>>>>,
422}
423
424#[cfg(not(any(feature = "std", feature = "critical-section")))]
426mod spinlock {
427 use crate::sync::atomic::{AtomicBool, Ordering};
428 use crate::sync::cell::UnsafeCell;
429
430 pub(super) struct Spinlock<T> {
432 locked: AtomicBool,
434
435 data: UnsafeCell<T>,
437 }
438
439 impl<T> Spinlock<T> {
440 #[inline]
442 pub(super) fn new(data: T) -> Self {
443 Self {
444 locked: AtomicBool::new(false),
445 data: UnsafeCell::new(data),
446 }
447 }
448
449 #[inline]
451 pub(super) fn try_with<R>(&self, f: impl FnOnce(&mut T) -> R) -> Option<R> {
452 if self
453 .locked
454 .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
455 .is_ok()
456 {
457 let _guard = CallOnDrop(|| self.locked.store(false, Ordering::Release));
458 Some(f(unsafe { self.data.get().deref_mut() }))
460 } else {
461 None
462 }
463 }
464
465 #[inline]
467 pub(super) fn with<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
468 loop {
469 if self
470 .locked
471 .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
472 .is_ok()
473 {
474 let _guard = CallOnDrop(|| self.locked.store(false, Ordering::Release));
475 return f(unsafe { self.data.get().deref_mut() });
477 }
478
479 while self.locked.load(Ordering::Relaxed) {
480 core::hint::spin_loop();
481 }
482 }
483 }
484 }
485
486 struct CallOnDrop<F: FnMut()>(F);
487 impl<F: FnMut()> Drop for CallOnDrop<F> {
488 #[inline]
489 fn drop(&mut self) {
490 (self.0)();
491 }
492 }
493}
494
495#[cfg(test)]
496mod tests {
497 use super::*;
498 use futures_lite::pin;
499
500 #[cfg(target_family = "wasm")]
501 use wasm_bindgen_test::wasm_bindgen_test as test;
502
503 macro_rules! make_listeners {
504 ($($id:ident),*) => {
505 $(
506 let $id = Option::<Listener<()>>::None;
507 pin!($id);
508 )*
509 };
510 }
511
512 #[test]
513 fn insert() {
514 let inner = crate::Inner::new();
515 make_listeners!(listen1, listen2, listen3);
516
517 inner.insert(listen1.as_mut());
519 inner.insert(listen2.as_mut());
520 inner.insert(listen3.as_mut());
521
522 assert_eq!(inner.list.try_total_listeners(), Some(3));
523
524 assert_eq!(inner.remove(listen2, false), Some(State::Created));
526 assert_eq!(inner.list.try_total_listeners(), Some(2));
527
528 assert_eq!(inner.remove(listen1, false), Some(State::Created));
530 assert_eq!(inner.list.try_total_listeners(), Some(1));
531 }
532
533 #[test]
534 fn drop_non_notified() {
535 let inner = crate::Inner::new();
536 make_listeners!(listen1, listen2, listen3);
537
538 inner.insert(listen1.as_mut());
540 inner.insert(listen2.as_mut());
541 inner.insert(listen3.as_mut());
542
543 inner.notify(GenericNotify::new(1, false, || ()));
545
546 inner.remove(listen3, true);
548
549 inner.remove(listen1, true);
551 inner.remove(listen2, true);
552 }
553}