blob: ee0995fce62c1f29c20373efc046f5ea5f6817e5 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
//! Minimal synchronous future executor used as a drop-in for the `tokio::runtime::Runtime::new()`
//! + `block_on` sync bridges scattered across the codebase (repository / installer / downloader).
//!
//! Those bridges drive `async fn`s whose `.await` points all resolve synchronously — this relies
//! on the invariant below. `CurlDownloader` no longer qualifies: it now performs real async I/O
//! via a non-blocking `reqwest::Client`, so `HttpDownloader` drives it through its own dedicated
//! `tokio::runtime::Runtime` instead (see `http_downloader::curl_runtime`), not through this
//! module. The other call sites (`file_downloader.rs`, `version_guesser.rs`,
//! `installation_manager.rs`, `composer_repository.rs`, `sync_helper.rs`) still rely on this
//! module because none of their awaited futures actually park on a reactor.
//!
//! Nesting `tokio` runtimes is forbidden ("Cannot start a runtime from within a runtime"), which is
//! why this no-reactor executor exists for those remaining call sites; it can be nested freely.
//!
//! TODO(phase-e): remove this module once the async bridges are either made genuinely synchronous or
//! consolidated onto a single shared runtime driven from `main`.
use std::future::Future;
use std::task::{Context, Poll};
/// Polls `fut` to completion on the current thread without any tokio runtime.
///
/// Relies on the invariant that no awaited future parks on a reactor (it would otherwise spin).
pub fn block_on<F: Future>(fut: F) -> F::Output {
let mut fut = std::pin::pin!(fut);
let waker = std::task::Waker::noop();
let mut cx = Context::from_waker(waker);
loop {
if let Poll::Ready(value) = fut.as_mut().poll(&mut cx) {
return value;
}
std::hint::spin_loop();
}
}
|