mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-08 00:00:13 +02:00
runtime: fix remote abort (#3942)
This commit is contained in:
@@ -46,7 +46,7 @@ impl<T: Stack> Level<T> {
|
|||||||
() => {
|
() => {
|
||||||
T::default()
|
T::default()
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
Level {
|
Level {
|
||||||
level,
|
level,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
|
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
|
||||||
))]
|
))]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||||
|
#![allow(deprecated)]
|
||||||
|
|
||||||
//! A runtime for writing reliable network applications without compromising speed.
|
//! A runtime for writing reliable network applications without compromising speed.
|
||||||
//!
|
//!
|
||||||
|
|||||||
@@ -433,7 +433,7 @@ impl Command {
|
|||||||
/// Basic usage:
|
/// Basic usage:
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// use tokio::process::Command;;
|
/// use tokio::process::Command;
|
||||||
/// use std::process::Stdio;
|
/// use std::process::Stdio;
|
||||||
///
|
///
|
||||||
/// let command = Command::new("ls")
|
/// let command = Command::new("ls")
|
||||||
@@ -457,7 +457,7 @@ impl Command {
|
|||||||
/// Basic usage:
|
/// Basic usage:
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// use tokio::process::Command;;
|
/// use tokio::process::Command;
|
||||||
/// use std::process::{Stdio};
|
/// use std::process::{Stdio};
|
||||||
///
|
///
|
||||||
/// let command = Command::new("ls")
|
/// let command = Command::new("ls")
|
||||||
|
|||||||
@@ -285,6 +285,17 @@ where
|
|||||||
self.cancel_task();
|
self.cancel_task();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remotely abort the task
|
||||||
|
///
|
||||||
|
/// This is similar to `shutdown` except that it asks the runtime to perform
|
||||||
|
/// the shutdown. This is necessary to avoid the shutdown happening in the
|
||||||
|
/// wrong thread for non-Send tasks.
|
||||||
|
pub(super) fn remote_abort(self) {
|
||||||
|
if self.header().state.transition_to_notified_and_cancel() {
|
||||||
|
self.core().schedule(Notified(self.to_task()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ====== internal ======
|
// ====== internal ======
|
||||||
|
|
||||||
fn cancel_task(self) {
|
fn cancel_task(self) {
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ impl<T> JoinHandle<T> {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn abort(&self) {
|
pub fn abort(&self) {
|
||||||
if let Some(raw) = self.raw {
|
if let Some(raw) = self.raw {
|
||||||
raw.shutdown();
|
raw.remote_abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ pub(super) struct Vtable {
|
|||||||
/// The join handle has been dropped
|
/// The join handle has been dropped
|
||||||
pub(super) drop_join_handle_slow: unsafe fn(NonNull<Header>),
|
pub(super) drop_join_handle_slow: unsafe fn(NonNull<Header>),
|
||||||
|
|
||||||
|
/// The task is remotely aborted
|
||||||
|
pub(super) remote_abort: unsafe fn(NonNull<Header>),
|
||||||
|
|
||||||
/// Scheduler is being shutdown
|
/// Scheduler is being shutdown
|
||||||
pub(super) shutdown: unsafe fn(NonNull<Header>),
|
pub(super) shutdown: unsafe fn(NonNull<Header>),
|
||||||
}
|
}
|
||||||
@@ -33,6 +36,7 @@ pub(super) fn vtable<T: Future, S: Schedule>() -> &'static Vtable {
|
|||||||
dealloc: dealloc::<T, S>,
|
dealloc: dealloc::<T, S>,
|
||||||
try_read_output: try_read_output::<T, S>,
|
try_read_output: try_read_output::<T, S>,
|
||||||
drop_join_handle_slow: drop_join_handle_slow::<T, S>,
|
drop_join_handle_slow: drop_join_handle_slow::<T, S>,
|
||||||
|
remote_abort: remote_abort::<T, S>,
|
||||||
shutdown: shutdown::<T, S>,
|
shutdown: shutdown::<T, S>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,6 +93,11 @@ impl RawTask {
|
|||||||
let vtable = self.header().vtable;
|
let vtable = self.header().vtable;
|
||||||
unsafe { (vtable.shutdown)(self.ptr) }
|
unsafe { (vtable.shutdown)(self.ptr) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn remote_abort(self) {
|
||||||
|
let vtable = self.header().vtable;
|
||||||
|
unsafe { (vtable.remote_abort)(self.ptr) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for RawTask {
|
impl Clone for RawTask {
|
||||||
@@ -125,6 +134,11 @@ unsafe fn drop_join_handle_slow<T: Future, S: Schedule>(ptr: NonNull<Header>) {
|
|||||||
harness.drop_join_handle_slow()
|
harness.drop_join_handle_slow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn remote_abort<T: Future, S: Schedule>(ptr: NonNull<Header>) {
|
||||||
|
let harness = Harness::<T, S>::from_raw(ptr);
|
||||||
|
harness.remote_abort()
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn shutdown<T: Future, S: Schedule>(ptr: NonNull<Header>) {
|
unsafe fn shutdown<T: Future, S: Schedule>(ptr: NonNull<Header>) {
|
||||||
let harness = Harness::<T, S>::from_raw(ptr);
|
let harness = Harness::<T, S>::from_raw(ptr);
|
||||||
harness.shutdown()
|
harness.shutdown()
|
||||||
|
|||||||
@@ -177,6 +177,15 @@ impl State {
|
|||||||
prev.will_need_queueing()
|
prev.will_need_queueing()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the cancelled bit and transition the state to `NOTIFIED`.
|
||||||
|
///
|
||||||
|
/// Returns `true` if the task needs to be submitted to the pool for
|
||||||
|
/// execution
|
||||||
|
pub(super) fn transition_to_notified_and_cancel(&self) -> bool {
|
||||||
|
let prev = Snapshot(self.val.fetch_or(NOTIFIED | CANCELLED, AcqRel));
|
||||||
|
prev.will_need_queueing()
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the `CANCELLED` bit and attempt to transition to `Running`.
|
/// Set the `CANCELLED` bit and attempt to transition to `Running`.
|
||||||
///
|
///
|
||||||
/// Returns `true` if the transition to `Running` succeeded.
|
/// Returns `true` if the transition to `Running` succeeded.
|
||||||
|
|||||||
@@ -359,9 +359,6 @@ async fn join_with_select() {
|
|||||||
async fn use_future_in_if_condition() {
|
async fn use_future_in_if_condition() {
|
||||||
use tokio::time::{self, Duration};
|
use tokio::time::{self, Duration};
|
||||||
|
|
||||||
let sleep = time::sleep(Duration::from_millis(50));
|
|
||||||
tokio::pin!(sleep);
|
|
||||||
|
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = time::sleep(Duration::from_millis(50)), if false => {
|
_ = time::sleep(Duration::from_millis(50)), if false => {
|
||||||
panic!("if condition ignored")
|
panic!("if condition ignored")
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
#![cfg(feature = "full")]
|
#![cfg(feature = "full")]
|
||||||
|
|
||||||
|
use std::thread::sleep;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
/// Checks that a suspended task can be aborted without panicking as reported in
|
/// Checks that a suspended task can be aborted without panicking as reported in
|
||||||
/// issue #3157: <https://github.com/tokio-rs/tokio/issues/3157>.
|
/// issue #3157: <https://github.com/tokio-rs/tokio/issues/3157>.
|
||||||
#[test]
|
#[test]
|
||||||
@@ -24,3 +27,49 @@ fn test_abort_without_panic_3157() {
|
|||||||
let _ = handle.await;
|
let _ = handle.await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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(&mut self) {
|
||||||
|
if std::thread::current().id() != self.created_on {
|
||||||
|
panic!("non-Send value dropped in another thread!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let rt = tokio::runtime::Builder::new_current_thread()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
let local = tokio::task::LocalSet::new();
|
||||||
|
|
||||||
|
let check = DropCheck::new();
|
||||||
|
let jh = local.spawn_local(async move {
|
||||||
|
futures::future::pending::<()>().await;
|
||||||
|
drop(check);
|
||||||
|
});
|
||||||
|
|
||||||
|
let jh2 = std::thread::spawn(move || {
|
||||||
|
sleep(Duration::from_millis(50));
|
||||||
|
jh.abort();
|
||||||
|
});
|
||||||
|
|
||||||
|
rt.block_on(local);
|
||||||
|
jh2.join().unwrap();
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user