diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2019-05-28 09:32:43 -0400 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2019-05-29 07:53:39 -0400 |
commit | 53b6356ec5eac1c84610c2d2e75b527485c47f3c (patch) | |
tree | a89e769e4bf0c2b3fb719db6c2f6d2d2580e2a45 /cli/tokio_util.rs | |
parent | 3c355c2b3296cb930c37de44634b479cd7230ed6 (diff) |
Correct tokio_util::block_on() and op_fetch_module_meta_data
op_fetch_module_meta_data is an op that is used by the TypeScript
compiler. TypeScript requires this op to be sync. However the
implementation of the op does things on the event loop (like fetching
HTTP resources).
In certain situations this can lead to deadlocks. The runtime's thread
pool can be filled with ops waiting on the result of
op_fetch_module_meta_data. The runtime has a maximum number of
threads it can use (the number of logical CPUs on the system).
This patch changes tokio_util::block_on to launch a new Tokio runtime
for evaluating the future, thus bipassing the max-thread problem.
This is only an issue in op_fetch_module_meta_data. Other synchronous
ops are truly synchornous, not interacting with the event loop. TODO
comments are added to direct future development.
Diffstat (limited to 'cli/tokio_util.rs')
-rw-r--r-- | cli/tokio_util.rs | 27 |
1 files changed, 17 insertions, 10 deletions
diff --git a/cli/tokio_util.rs b/cli/tokio_util.rs index fa42846cb..9204b2ae1 100644 --- a/cli/tokio_util.rs +++ b/cli/tokio_util.rs @@ -11,14 +11,8 @@ use tokio::net::TcpStream; use tokio::runtime; pub fn create_threadpool_runtime() -> tokio::runtime::Runtime { - // This code can be simplified once the following PR is landed and - // released: https://github.com/tokio-rs/tokio/pull/1055 - use tokio_threadpool::Builder as ThreadPoolBuilder; - let mut threadpool_builder = ThreadPoolBuilder::new(); - threadpool_builder.panic_handler(|err| std::panic::resume_unwind(err)); - #[allow(deprecated)] runtime::Builder::new() - .threadpool_builder(threadpool_builder) + .panic_handler(|err| std::panic::resume_unwind(err)) .build() .unwrap() } @@ -32,15 +26,28 @@ where rt.block_on_all(future).unwrap(); } +/// THIS IS A HACK AND SHOULD BE AVOIDED. +/// +/// This creates a new tokio runtime, with many new threads, to execute the +/// given future. This is useful when we want to block the main runtime to +/// resolve a future without worrying that we'll us up all the threads in the +/// main runtime. pub fn block_on<F, R, E>(future: F) -> Result<R, E> where F: Send + 'static + Future<Item = R, Error = E>, R: Send + 'static, E: Send + 'static, { - let (tx, rx) = futures::sync::oneshot::channel(); - tokio::spawn(future.then(move |r| tx.send(r).map_err(|_| unreachable!()))); - rx.wait().unwrap() + use std::sync::mpsc::channel; + use std::thread; + let (sender, receiver) = channel(); + // Create a new runtime to evaluate the future asynchronously. + thread::spawn(move || { + let mut rt = create_threadpool_runtime(); + let r = rt.block_on(future); + sender.send(r).unwrap(); + }); + receiver.recv().unwrap() } // Set the default executor so we can use tokio::spawn(). It's difficult to |