use std::sync::Arc; use std::thread::sleep; use tokio::time::Duration;
use tokio::runtime::Builder;
#[cfg(panic = "unwind")] struct PanicOnDrop;
#[cfg(panic = "unwind")] impl Drop for PanicOnDrop { fn drop(&mutself) {
panic!("Well what did you expect would happen...");
}
}
/// Checks that a suspended task can be aborted without panicking as reported in /// issue #3157: <https://github.com/tokio-rs/tokio/issues/3157>. #[test] fn test_abort_without_panic_3157() { let rt = Builder::new_multi_thread()
.enable_time()
.worker_threads(1)
.build()
.unwrap();
rt.block_on(asyncmove { let handle = tokio::spawn(asyncmove { tokio::time::sleep(Duration::new(100, 0)).await });
// wait for task to sleep.
tokio::time::sleep(Duration::from_millis(10)).await;
handle.abort(); let _ = handle.await;
});
}
/// Checks that a suspended task can be aborted inside of a current_thread /// executor without panicking as reported in issue #3662: /// <https://github.com/tokio-rs/tokio/issues/3662>. #[test] fn test_abort_without_panic_3662() { use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc;
struct DropCheck(Arc<AtomicBool>);
impl Drop for DropCheck { fn drop(&mutself) { self.0.store(true, Ordering::SeqCst);
}
}
let rt = Builder::new_current_thread().build().unwrap();
rt.block_on(asyncmove { let drop_flag = Arc::new(AtomicBool::new(false)); let drop_check = DropCheck(drop_flag.clone());
let j = tokio::spawn(asyncmove { // NB: just grab the drop check here so that it becomes part of the // task. let _drop_check = drop_check;
futures::future::pending::<()>().await;
});
let drop_flag2 = drop_flag.clone();
let task = std::thread::spawn(move || { // This runs in a separate thread so it doesn't have immediate // thread-local access to the executor. It does however transition // the underlying task to be completed, which will cause it to be // dropped (but not in this thread).
assert!(!drop_flag2.load(Ordering::SeqCst));
j.abort();
j
})
.join()
.unwrap();
let result = task.await;
assert!(drop_flag.load(Ordering::SeqCst));
assert!(result.unwrap_err().is_cancelled());
// Note: We do the following to trigger a deferred task cleanup. // // The relevant piece of code you want to look at is in: // `Inner::block_on` of `scheduler/current_thread.rs`. // // We cause the cleanup to happen by having a poll return Pending once // so that the scheduler can go into the "auxiliary tasks" mode, at // which point the task is removed from the scheduler. let i = tokio::spawn(asyncmove {
tokio::task::yield_now().await;
});
i.await.unwrap();
});
}
/// Checks that a suspended LocalSet task can be aborted from a remote thread /// without panicking and without running the tasks destructor on the wrong thread. /// <https://github.com/tokio-rs/tokio/issues/3929> #[test] fn remote_abort_local_set_3929() { struct DropCheck {
created_on: std::thread::ThreadId,
not_send: std::marker::PhantomData<*const ()>,
}
impl DropCheck { fn new() -> Self { Self {
created_on: std::thread::current().id(),
not_send: std::marker::PhantomData,
}
}
} impl Drop for DropCheck { fn drop(&mutself) { if std::thread::current().id() != self.created_on {
panic!("non-Send value dropped in another thread!");
}
}
}
let rt = Builder::new_current_thread().build().unwrap(); let local = tokio::task::LocalSet::new();
let check = DropCheck::new(); let jh = local.spawn_local(asyncmove {
futures::future::pending::<()>().await;
drop(check);
});
let jh2 = std::thread::spawn(move || {
sleep(Duration::from_millis(10));
jh.abort();
});
rt.block_on(local);
jh2.join().unwrap();
}
/// Checks that a suspended task can be aborted even if the `JoinHandle` is immediately dropped. /// issue #3964: <https://github.com/tokio-rs/tokio/issues/3964>. #[test] fn test_abort_wakes_task_3964() { let rt = Builder::new_current_thread().enable_time().build().unwrap();
rt.block_on(asyncmove { let notify_dropped = Arc::new(()); let weak_notify_dropped = Arc::downgrade(¬ify_dropped);
let handle = tokio::spawn(asyncmove { // Make sure the Arc is moved into the task let _notify_dropped = notify_dropped;
tokio::time::sleep(Duration::new(100, 0)).await
});
// wait for task to sleep.
tokio::time::sleep(Duration::from_millis(10)).await;
handle.abort();
drop(handle);
// wait for task to abort.
tokio::time::sleep(Duration::from_millis(10)).await;
// Check that the Arc has been dropped.
assert!(weak_notify_dropped.upgrade().is_none());
});
}
/// Checks that aborting a task whose destructor panics does not allow the /// panic to escape the task. #[test] #[cfg(panic = "unwind")] fn test_abort_task_that_panics_on_drop_contained() { let rt = Builder::new_current_thread().enable_time().build().unwrap();
rt.block_on(asyncmove { let handle = tokio::spawn(asyncmove { // Make sure the Arc is moved into the task let _panic_dropped = PanicOnDrop;
tokio::time::sleep(Duration::new(100, 0)).await
});
// wait for task to sleep.
tokio::time::sleep(Duration::from_millis(10)).await;
handle.abort();
drop(handle);
// wait for task to abort.
tokio::time::sleep(Duration::from_millis(10)).await;
});
}
/// Checks that aborting a task whose destructor panics has the expected result. #[test] #[cfg(panic = "unwind")] fn test_abort_task_that_panics_on_drop_returned() { let rt = Builder::new_current_thread().enable_time().build().unwrap();
rt.block_on(asyncmove { let handle = tokio::spawn(asyncmove { // Make sure the Arc is moved into the task let _panic_dropped = PanicOnDrop;
tokio::time::sleep(Duration::new(100, 0)).await
});
// wait for task to sleep.
tokio::time::sleep(Duration::from_millis(10)).await;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.