1use std::future::Future;
2use std::mem::MaybeUninit;
3use std::pin::Pin;
4use std::sync::atomic::Ordering;
5use std::task::{Context, Poll};
6
7use atomic_waker::AtomicWaker;
8
9#[cfg(test)]
10use loom::cell::UnsafeCell;
11#[cfg(test)]
12use loom::sync::{atomic::AtomicU8, Arc};
13#[cfg(not(test))]
14use std::cell::UnsafeCell;
15#[cfg(not(test))]
16use std::sync::{atomic::AtomicU8, Arc};
17
18const PENDING: u8 = 0;
19const WRITING: u8 = 1;
20const READY: u8 = 2;
21const TAKEN: u8 = 3;
22const CANCELED: u8 = 4;
23
24struct NotifyFutureState<RESULT> {
25 state: AtomicU8,
26 waker: AtomicWaker,
27 result: UnsafeCell<MaybeUninit<RESULT>>,
28}
29
30unsafe impl<RESULT: Send> Send for NotifyFutureState<RESULT> {}
34unsafe impl<RESULT: Send> Sync for NotifyFutureState<RESULT> {}
35
36impl<RESULT> NotifyFutureState<RESULT> {
37 pub fn new() -> Arc<NotifyFutureState<RESULT>> {
38 Arc::new(NotifyFutureState {
39 state: AtomicU8::new(PENDING),
40 waker: AtomicWaker::new(),
41 result: UnsafeCell::new(MaybeUninit::uninit()),
42 })
43 }
44
45 pub fn set_complete(state: &Arc<NotifyFutureState<RESULT>>, result: RESULT) {
46 state.set_complete_inner(result);
47 }
48
49 fn set_complete_inner(&self, result: RESULT) {
50 if self
51 .state
52 .compare_exchange(PENDING, WRITING, Ordering::AcqRel, Ordering::Acquire)
53 .is_err()
54 {
55 return;
56 }
57
58 self.write_result(result);
59
60 self.state.store(READY, Ordering::Release);
61 self.waker.wake();
62 }
63
64 fn poll_result(&self, cx: &mut Context<'_>, already_taken_message: &str) -> Poll<RESULT> {
65 match self.state.load(Ordering::Acquire) {
66 READY => return Poll::Ready(self.take_result(already_taken_message)),
67 TAKEN => panic!("{already_taken_message}"),
68 _ => {}
69 }
70
71 self.waker.register(cx.waker());
72
73 match self.state.load(Ordering::Acquire) {
74 READY => Poll::Ready(self.take_result(already_taken_message)),
75 TAKEN => panic!("{already_taken_message}"),
76 _ => Poll::Pending,
77 }
78 }
79
80 fn take_result(&self, already_taken_message: &str) -> RESULT {
81 match self
82 .state
83 .compare_exchange(READY, TAKEN, Ordering::AcqRel, Ordering::Acquire)
84 {
85 Ok(_) => self.read_result(),
86 Err(TAKEN) => panic!("{already_taken_message}"),
87 Err(_) => panic!("Notify result was not ready"),
88 }
89 }
90
91 fn cancel(&self) {
92 let _ = self
93 .state
94 .compare_exchange(PENDING, CANCELED, Ordering::AcqRel, Ordering::Acquire);
95 let _ = self.waker.take();
96 }
97
98 pub fn is_canceled(&self) -> bool {
99 self.state.load(Ordering::Acquire) == CANCELED
100 }
101}
102
103#[cfg(not(test))]
104impl<RESULT> NotifyFutureState<RESULT> {
105 fn write_result(&self, result: RESULT) {
106 unsafe {
109 self.result.get().write(MaybeUninit::new(result));
110 }
111 }
112
113 fn read_result(&self) -> RESULT {
114 unsafe { (*self.result.get()).as_ptr().read() }
117 }
118
119 fn drop_result(&mut self) {
120 unsafe {
123 self.result.get_mut().assume_init_drop();
124 }
125 }
126}
127
128#[cfg(test)]
129impl<RESULT> NotifyFutureState<RESULT> {
130 fn write_result(&self, result: RESULT) {
131 self.result.with_mut(|ptr| unsafe {
134 ptr.write(MaybeUninit::new(result));
135 });
136 }
137
138 fn read_result(&self) -> RESULT {
139 self.result.with(|ptr| unsafe { (*ptr).as_ptr().read() })
142 }
143
144 fn drop_result(&mut self) {
145 self.result.get_mut().with(|ptr| unsafe {
148 (*ptr).assume_init_drop();
149 });
150 }
151}
152
153impl<RESULT> Drop for NotifyFutureState<RESULT> {
154 fn drop(&mut self) {
155 if self.state.load(Ordering::Acquire) == READY {
156 self.drop_result();
157 }
158 }
159}
160
161#[deprecated(since = "0.2.1", note = "Please use Notify instead")]
162pub struct NotifyFuture<RESULT> {
163 state: Arc<NotifyFutureState<RESULT>>,
164}
165
166#[allow(deprecated)]
167impl<RESULT> Clone for NotifyFuture<RESULT> {
168 fn clone(&self) -> Self {
169 Self {
170 state: self.state.clone(),
171 }
172 }
173}
174
175#[allow(deprecated)]
176impl<RESULT> NotifyFuture<RESULT> {
177 pub fn new() -> Self {
178 Self {
179 state: NotifyFutureState::new(),
180 }
181 }
182
183 pub fn set_complete(&self, result: RESULT) {
184 NotifyFutureState::set_complete(&self.state, result);
185 }
186}
187
188#[allow(deprecated)]
189impl<RESULT> Default for NotifyFuture<RESULT> {
190 fn default() -> Self {
191 Self::new()
192 }
193}
194
195#[allow(deprecated)]
196impl<RESULT> Future for NotifyFuture<RESULT> {
197 type Output = RESULT;
198
199 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
200 self.state.poll_result(
201 cx,
202 "NotifyFuture was awaited by more than one task. Use Notify::new() instead",
203 )
204 }
205}
206
207pub struct Notify<RESULT> {
208 state: Arc<NotifyFutureState<RESULT>>,
209}
210
211impl<RESULT> Notify<RESULT> {
212 pub fn new() -> (Self, NotifyWaiter<RESULT>) {
213 let state = NotifyFutureState::new();
214 (
215 Self {
216 state: state.clone(),
217 },
218 NotifyWaiter::new(state),
219 )
220 }
221
222 pub fn notify(self, result: RESULT) {
223 NotifyFutureState::set_complete(&self.state, result);
224 }
225
226 pub fn is_canceled(&self) -> bool {
227 self.state.is_canceled()
228 }
229}
230
231pub struct NotifyWaiter<RESULT> {
232 state: Arc<NotifyFutureState<RESULT>>,
233}
234
235impl<RESULT> NotifyWaiter<RESULT> {
236 pub(crate) fn new(state: Arc<NotifyFutureState<RESULT>>) -> Self {
237 Self { state }
238 }
239}
240
241impl<RESULT> Drop for NotifyWaiter<RESULT> {
242 fn drop(&mut self) {
243 self.state.cancel();
244 }
245}
246
247impl<RESULT> Future for NotifyWaiter<RESULT> {
248 type Output = RESULT;
249
250 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
251 self.state
252 .poll_result(cx, "NotifyWaiter was polled after completion")
253 }
254}
255
256#[cfg(test)]
257#[allow(deprecated)]
258mod test {
259 use std::future::Future;
260 use std::pin::Pin;
261 use std::sync::{
262 atomic::{AtomicUsize as StdAtomicUsize, Ordering},
263 Arc as StdArc,
264 };
265 use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
266
267 use loom::sync::{atomic::AtomicUsize, Arc};
268 use loom::thread;
269
270 use crate::{Notify, NotifyFuture};
271
272 struct DropCounter {
273 drops: Arc<AtomicUsize>,
274 }
275
276 impl Drop for DropCounter {
277 fn drop(&mut self) {
278 self.drops.fetch_add(1, Ordering::SeqCst);
279 }
280 }
281
282 fn noop_waker() -> &'static Waker {
283 Waker::noop()
284 }
285
286 fn counting_waker(wakes: StdArc<StdAtomicUsize>) -> Waker {
287 unsafe fn clone(data: *const ()) -> RawWaker {
288 let wakes = StdArc::<StdAtomicUsize>::from_raw(data.cast::<StdAtomicUsize>());
289 let cloned = wakes.clone();
290 let _ = StdArc::into_raw(wakes);
291 RawWaker::new(StdArc::into_raw(cloned).cast::<()>(), &VTABLE)
292 }
293
294 unsafe fn wake(data: *const ()) {
295 let wakes = StdArc::<StdAtomicUsize>::from_raw(data.cast::<StdAtomicUsize>());
296 wakes.fetch_add(1, Ordering::SeqCst);
297 }
298
299 unsafe fn wake_by_ref(data: *const ()) {
300 let wakes = StdArc::<StdAtomicUsize>::from_raw(data.cast::<StdAtomicUsize>());
301 wakes.fetch_add(1, Ordering::SeqCst);
302 let _ = StdArc::into_raw(wakes);
303 }
304
305 unsafe fn drop(data: *const ()) {
306 let _ = StdArc::<StdAtomicUsize>::from_raw(data.cast::<StdAtomicUsize>());
307 }
308
309 static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
310
311 let raw = RawWaker::new(StdArc::into_raw(wakes).cast::<()>(), &VTABLE);
312 unsafe { Waker::from_raw(raw) }
313 }
314
315 #[test]
316 fn notify_future_ready_after_set_complete() {
317 loom::model(|| {
318 let mut notify_future = NotifyFuture::<u32>::new();
319 let notifier = notify_future.clone();
320
321 notifier.set_complete(1);
322
323 let mut cx = Context::from_waker(noop_waker());
324 let value = match Pin::new(&mut notify_future).poll(&mut cx) {
325 Poll::Ready(value) => value,
326 Poll::Pending => panic!("future remained pending after set_complete"),
327 };
328
329 assert_eq!(value, 1);
330 });
331 }
332
333 #[test]
334 fn notify_waiter_ready_after_notify() {
335 loom::model(|| {
336 let (notify, mut waiter) = Notify::<u32>::new();
337
338 notify.notify(1);
339
340 let mut cx = Context::from_waker(noop_waker());
341 let value = match Pin::new(&mut waiter).poll(&mut cx) {
342 Poll::Ready(value) => value,
343 Poll::Pending => panic!("waiter remained pending after notify"),
344 };
345
346 assert_eq!(value, 1);
347 });
348 }
349
350 #[test]
351 fn notify_waiter_drop_before_ready_is_canceled() {
352 loom::model(|| {
353 let (notify, waiter) = Notify::<u32>::new();
354 drop(waiter);
355 assert!(notify.is_canceled());
356 });
357 }
358
359 #[test]
360 fn notify_waiter_wakes_registered_waker() {
361 loom::model(|| {
362 let (notify, mut waiter) = Notify::<u32>::new();
363 let wakes = StdArc::new(StdAtomicUsize::new(0));
364 let waker = counting_waker(wakes.clone());
365 let mut cx = Context::from_waker(&waker);
366
367 assert!(matches!(Pin::new(&mut waiter).poll(&mut cx), Poll::Pending));
368
369 notify.notify(1);
370
371 assert_eq!(wakes.load(Ordering::SeqCst), 1);
372 let value = match Pin::new(&mut waiter).poll(&mut cx) {
373 Poll::Ready(value) => value,
374 Poll::Pending => panic!("waiter remained pending after notify"),
375 };
376 assert_eq!(value, 1);
377 });
378 }
379
380 #[test]
381 fn notify_after_waiter_drop_discards_result() {
382 loom::model(|| {
383 let drops = Arc::new(AtomicUsize::new(0));
384 let (notify, waiter) = Notify::<DropCounter>::new();
385
386 drop(waiter);
387 assert!(notify.is_canceled());
388
389 notify.notify(DropCounter {
390 drops: drops.clone(),
391 });
392
393 assert_eq!(drops.load(Ordering::SeqCst), 1);
394 });
395 }
396
397 #[test]
398 fn waiter_drop_after_ready_does_not_cancel() {
399 loom::model(|| {
400 let state = super::NotifyFutureState::new();
401 let notify = Notify {
402 state: state.clone(),
403 };
404 let waiter = super::NotifyWaiter::new(state.clone());
405
406 notify.notify(1);
407 drop(waiter);
408
409 assert!(!state.is_canceled());
410 });
411 }
412
413 #[test]
414 fn repeated_set_complete_keeps_first_value() {
415 loom::model(|| {
416 let mut notify_future = NotifyFuture::<u32>::new();
417 let notifier = notify_future.clone();
418
419 notifier.set_complete(1);
420 notifier.set_complete(2);
421
422 let mut cx = Context::from_waker(noop_waker());
423 let value = match Pin::new(&mut notify_future).poll(&mut cx) {
424 Poll::Ready(value) => value,
425 Poll::Pending => panic!("future remained pending after set_complete"),
426 };
427
428 assert_eq!(value, 1);
429 });
430 }
431
432 #[test]
433 fn ready_value_is_dropped_if_waiter_is_dropped() {
434 loom::model(|| {
435 let drops = Arc::new(AtomicUsize::new(0));
436 let (notify, waiter) = Notify::<DropCounter>::new();
437
438 notify.notify(DropCounter {
439 drops: drops.clone(),
440 });
441 drop(waiter);
442
443 assert_eq!(drops.load(Ordering::SeqCst), 1);
444 });
445 }
446
447 #[test]
448 fn taken_value_is_not_dropped_twice() {
449 loom::model(|| {
450 let drops = Arc::new(AtomicUsize::new(0));
451 let (notify, mut waiter) = Notify::<DropCounter>::new();
452
453 notify.notify(DropCounter {
454 drops: drops.clone(),
455 });
456
457 let mut cx = Context::from_waker(noop_waker());
458 let value = match Pin::new(&mut waiter).poll(&mut cx) {
459 Poll::Ready(value) => value,
460 Poll::Pending => panic!("waiter remained pending after notify"),
461 };
462
463 assert_eq!(drops.load(Ordering::SeqCst), 0);
464 drop(value);
465 assert_eq!(drops.load(Ordering::SeqCst), 1);
466 });
467 }
468
469 #[test]
470 fn notify_racing_waiter_drop_drops_value_once() {
471 loom::model(|| {
472 let drops = Arc::new(AtomicUsize::new(0));
473 let (notify, waiter) = Notify::<DropCounter>::new();
474
475 let notify_thread = {
476 let drops = drops.clone();
477 thread::spawn(move || {
478 notify.notify(DropCounter { drops });
479 })
480 };
481
482 let drop_thread = thread::spawn(move || {
483 drop(waiter);
484 });
485
486 notify_thread.join().unwrap();
487 drop_thread.join().unwrap();
488
489 assert_eq!(drops.load(Ordering::SeqCst), 1);
490 });
491 }
492
493 #[test]
494 fn poll_racing_notify_observes_one_ready_value() {
495 loom::model(|| {
496 let drops = Arc::new(AtomicUsize::new(0));
497 let (notify, mut waiter) = Notify::<DropCounter>::new();
498
499 let notify_thread = {
500 let drops = drops.clone();
501 thread::spawn(move || {
502 notify.notify(DropCounter { drops });
503 })
504 };
505
506 let mut cx = Context::from_waker(noop_waker());
507
508 match Pin::new(&mut waiter).poll(&mut cx) {
509 Poll::Ready(value) => drop(value),
510 Poll::Pending => {
511 notify_thread.join().unwrap();
512 let value = match Pin::new(&mut waiter).poll(&mut cx) {
513 Poll::Ready(value) => value,
514 Poll::Pending => panic!("waiter remained pending after notify"),
515 };
516 drop(value);
517 assert_eq!(drops.load(Ordering::SeqCst), 1);
518 return;
519 }
520 }
521
522 notify_thread.join().unwrap();
523 assert_eq!(drops.load(Ordering::SeqCst), 1);
524 });
525 }
526
527 #[test]
528 fn repeated_notify_future_set_complete_drops_both_inputs_once() {
529 loom::model(|| {
530 let drops = Arc::new(AtomicUsize::new(0));
531 let mut notify_future = NotifyFuture::<DropCounter>::new();
532 let first_notifier = notify_future.clone();
533 let second_notifier = notify_future.clone();
534
535 let first_thread = {
536 let drops = drops.clone();
537 thread::spawn(move || {
538 first_notifier.set_complete(DropCounter { drops });
539 })
540 };
541
542 let second_thread = {
543 let drops = drops.clone();
544 thread::spawn(move || {
545 second_notifier.set_complete(DropCounter { drops });
546 })
547 };
548
549 first_thread.join().unwrap();
550 second_thread.join().unwrap();
551
552 let mut cx = Context::from_waker(noop_waker());
553 let value = match Pin::new(&mut notify_future).poll(&mut cx) {
554 Poll::Ready(value) => value,
555 Poll::Pending => panic!("future remained pending after set_complete"),
556 };
557
558 assert_eq!(drops.load(Ordering::SeqCst), 1);
559 drop(value);
560 assert_eq!(drops.load(Ordering::SeqCst), 2);
561 });
562 }
563
564 #[test]
565 #[should_panic(expected = "NotifyWaiter was polled after completion")]
566 fn notify_waiter_panics_when_polled_after_completion() {
567 loom::model(|| {
568 let (notify, mut waiter) = Notify::<u32>::new();
569
570 notify.notify(1);
571
572 let mut cx = Context::from_waker(noop_waker());
573 let value = match Pin::new(&mut waiter).poll(&mut cx) {
574 Poll::Ready(value) => value,
575 Poll::Pending => panic!("waiter remained pending after notify"),
576 };
577 assert_eq!(value, 1);
578
579 let _ = Pin::new(&mut waiter).poll(&mut cx);
580 });
581 }
582
583 #[test]
584 #[should_panic(expected = "NotifyFuture was awaited by more than one task")]
585 fn notify_future_panics_when_polled_after_result_taken() {
586 loom::model(|| {
587 let mut first_waiter = NotifyFuture::<u32>::new();
588 let notifier = first_waiter.clone();
589 let mut second_waiter = first_waiter.clone();
590
591 notifier.set_complete(1);
592
593 let mut cx = Context::from_waker(noop_waker());
594 let value = match Pin::new(&mut first_waiter).poll(&mut cx) {
595 Poll::Ready(value) => value,
596 Poll::Pending => panic!("future remained pending after set_complete"),
597 };
598 assert_eq!(value, 1);
599
600 let _ = Pin::new(&mut second_waiter).poll(&mut cx);
601 });
602 }
603}