-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rt: move block_on to handle #3097
Changes from all commits
d43812d
7bb036e
43094fb
e4727ff
14ee0c2
54fc4fb
46e0cdf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,12 @@ | ||
use crate::future::poll_fn; | ||
use crate::park::Park; | ||
use crate::runtime::blocking::task::BlockingTask; | ||
use crate::runtime::task::{self, JoinHandle}; | ||
use crate::runtime::{blocking, context, driver, Spawner}; | ||
use crate::runtime::{basic_scheduler, blocking, context, driver, Spawner}; | ||
use crate::util::error::CONTEXT_MISSING_ERROR; | ||
|
||
use std::future::Future; | ||
use std::task::Poll::{Pending, Ready}; | ||
use std::{error, fmt}; | ||
|
||
/// Handle to the runtime. | ||
|
@@ -201,6 +204,105 @@ impl Handle { | |
let _ = self.blocking_spawner.spawn(task, &self); | ||
handle | ||
} | ||
|
||
/// Run a future to completion on the Tokio runtime. This is the | ||
/// runtime's entry point. | ||
/// | ||
/// This runs the given future on the runtime, blocking until it is | ||
/// complete, and yielding its resolved result. Any tasks or timers | ||
/// which the future spawns internally will be executed on the runtime. | ||
/// | ||
/// # Multi thread scheduler | ||
/// | ||
/// When the multi thread scheduler is used this will allow futures | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would mention it will also run spawned tasks on the runtime worker threads. |
||
/// to run within the io driver and timer context of the overall runtime. | ||
/// | ||
/// # Current thread scheduler | ||
/// | ||
/// When the current thread scheduler is enabled `block_on` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While this is the behavior of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, my initial thinking was that the handle should follow the Runtime's behavior, but it does complicate the shutdown logic as well as seems a bit weird given the "current_thread" name... Perhaps, |
||
/// can be called concurrently from multiple threads. The first call | ||
/// will take ownership of the io and timer drivers. This means | ||
/// other threads which do not own the drivers will hook into that one. | ||
/// When the first `block_on` completes, other threads will be able to | ||
/// "steal" the driver to allow continued execution of their futures. | ||
/// | ||
/// # Panics | ||
/// | ||
/// This function panics if the provided future panics, or if called within an | ||
/// asynchronous execution context. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```no_run | ||
/// use tokio::runtime::Runtime; | ||
/// | ||
/// // Create the runtime | ||
/// let rt = Runtime::new().unwrap(); | ||
/// // Get a handle to rhe runtime | ||
/// let handle = rt.handle(); | ||
/// | ||
/// // Execute the future, blocking the current thread until completion using the handle | ||
/// handle.block_on(async { | ||
/// println!("hello"); | ||
/// }); | ||
/// ``` | ||
pub fn block_on<F: Future>(&self, future: F) -> F::Output { | ||
match &self.spawner { | ||
Spawner::Basic(exec) => self | ||
.block_on_with_basic_scheduler::<F, crate::park::thread::ParkThread>( | ||
future, exec, None, | ||
), | ||
#[cfg(feature = "rt-multi-thread")] | ||
Spawner::ThreadPool(_) => { | ||
let _enter = self.enter(); | ||
let mut enter = crate::runtime::enter(true); | ||
enter.block_on(future).expect("failed to park thread") | ||
} | ||
} | ||
} | ||
|
||
pub(crate) fn block_on_with_basic_scheduler<F: Future, P: Park>( | ||
&self, | ||
future: F, | ||
spawner: &basic_scheduler::Spawner, | ||
scheduler: Option<&basic_scheduler::BasicScheduler<P>>, | ||
) -> F::Output { | ||
let _enter = self.enter(); | ||
|
||
pin!(future); | ||
|
||
// Attempt to steal the dedicated parker and block_on the future if we can there, | ||
// otherwise, lets select on a notification that the parker is available | ||
// or the future is complete. | ||
loop { | ||
if let Some(mut inner) = scheduler.and_then(basic_scheduler::BasicScheduler::take_inner) | ||
{ | ||
return inner.block_on(future); | ||
} | ||
|
||
let mut enter = crate::runtime::enter(false); | ||
|
||
let notified = spawner.notify().notified(); | ||
pin!(notified); | ||
|
||
if let Some(out) = enter | ||
.block_on(poll_fn(|cx| { | ||
if notified.as_mut().poll(cx).is_ready() { | ||
return Ready(None); | ||
} | ||
|
||
if let Ready(out) = future.as_mut().poll(cx) { | ||
return Ready(Some(out)); | ||
} | ||
|
||
Pending | ||
})) | ||
.expect("Failed to `Enter::block_on`") | ||
{ | ||
return out; | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// Error returned by `try_current` when no Runtime has been started | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is incorrect, this is not the entry point but just an additional
block_on
?