Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions releases/rust/esdk/src/deps/com_amazonaws_dynamodb/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,33 @@
use std::future::Future;
use tokio::runtime::Builder;
use tokio::runtime::Handle;
use tokio::runtime::RuntimeFlavor;

pub fn escape_to_async<F, O>(fut: F) -> O
where
F: Future<Output = O> + Send,
O: Send,
{
match Handle::try_current() {
Ok(handle) => match handle.runtime_flavor() {
RuntimeFlavor::CurrentThread => std::thread::scope(move |t| {
t.spawn(move || {
Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(fut)
})
.join()
.unwrap()
}),
_ => tokio::task::block_in_place(move || handle.block_on(fut)),
},
// Any ambient runtime: run the future on a scoped thread with its own
// runtime. Blocking the calling thread is what a sync bridge does, but
// the future must never depend on the caller's runtime for progress:
// `block_in_place` + `Handle::block_on` parks a worker on a future
// that same runtime has to drive, and when that worker is the last
// one awake (the shared IO/timer driver unowned, all other workers
// parked) the future can never complete and the whole runtime
// deadlocks permanently. A fresh current-thread runtime drives the
// future independently on every flavor.
Ok(_) => std::thread::scope(move |t| {
t.spawn(move || {
Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(fut)
})
.join()
.unwrap()
}),
Err(_) => Builder::new_current_thread()
.enable_all()
.build()
Expand Down
35 changes: 20 additions & 15 deletions releases/rust/esdk/src/deps/com_amazonaws_kms/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,33 @@
use std::future::Future;
use tokio::runtime::Builder;
use tokio::runtime::Handle;
use tokio::runtime::RuntimeFlavor;

pub fn escape_to_async<F, O>(fut: F) -> O
where
F: Future<Output = O> + Send,
O: Send,
{
match Handle::try_current() {
Ok(handle) => match handle.runtime_flavor() {
RuntimeFlavor::CurrentThread => std::thread::scope(move |t| {
t.spawn(move || {
Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(fut)
})
.join()
.unwrap()
}),
_ => tokio::task::block_in_place(move || handle.block_on(fut)),
},
// Any ambient runtime: run the future on a scoped thread with its own
// runtime. Blocking the calling thread is what a sync bridge does, but
// the future must never depend on the caller's runtime for progress:
// `block_in_place` + `Handle::block_on` parks a worker on a future
// that same runtime has to drive, and when that worker is the last
// one awake (the shared IO/timer driver unowned, all other workers
// parked) the future can never complete and the whole runtime
// deadlocks permanently. A fresh current-thread runtime drives the
// future independently on every flavor.
Ok(_) => std::thread::scope(move |t| {
t.spawn(move || {
Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(fut)
})
.join()
.unwrap()
}),
Err(_) => Builder::new_current_thread()
.enable_all()
.build()
Expand Down
35 changes: 20 additions & 15 deletions releases/rust/esdk/src/escape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,33 @@
use std::future::Future;
use tokio::runtime::Builder;
use tokio::runtime::Handle;
use tokio::runtime::RuntimeFlavor;

pub(crate) fn escape_to_async<F, O>(fut: F) -> O
where
F: Future<Output = O> + Send,
O: Send,
{
match Handle::try_current() {
Ok(handle) => match handle.runtime_flavor() {
RuntimeFlavor::CurrentThread => std::thread::scope(move |t| {
t.spawn(move || {
Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(fut)
})
.join()
.unwrap()
}),
_ => tokio::task::block_in_place(move || handle.block_on(fut)),
},
// Any ambient runtime: run the future on a scoped thread with its own
// runtime. Blocking the calling thread is what a sync bridge does, but
// the future must never depend on the caller's runtime for progress:
// `block_in_place` + `Handle::block_on` parks a worker on a future
// that same runtime has to drive, and when that worker is the last
// one awake (the shared IO/timer driver unowned, all other workers
// parked) the future can never complete and the whole runtime
// deadlocks permanently. A fresh current-thread runtime drives the
// future independently on every flavor.
Ok(_) => std::thread::scope(move |t| {
t.spawn(move || {
Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(fut)
})
.join()
.unwrap()
}),
Err(_) => Builder::new_current_thread()
.enable_all()
.build()
Expand Down