mirror of
https://github.com/tlsnotary/wasm-bindgen.git
synced 2026-01-09 13:47:56 -05:00
Revert "Use single-threaded impl when MT is impossible"
This reverts commit 7ce38b42d3.
This commit is contained in:
@@ -11,11 +11,6 @@
|
||||
* Add bindings for `CanvasState.reset()`, affecting `CanvasRenderingContext2D` and `OffscreenCanvasRenderingContext2D`.
|
||||
[#3844](https://github.com/rustwasm/wasm-bindgen/pull/3844)
|
||||
|
||||
### Fixed
|
||||
|
||||
* Allow `wasm-bindgen-futures` to run correctly when using the atomics target feature in an environment that has no support for `Atomics.waitAsync()` and without cross-origin isolation.
|
||||
[#3848](https://github.com/rustwasm/wasm-bindgen/pull/3848)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## [0.2.91](https://github.com/rustwasm/wasm-bindgen/compare/0.2.90...0.2.91)
|
||||
|
||||
@@ -50,40 +50,18 @@ pub use js_sys;
|
||||
pub use wasm_bindgen;
|
||||
|
||||
mod task {
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
#[cfg(target_feature = "atomics")]
|
||||
mod multithread;
|
||||
mod singlethread;
|
||||
#[cfg(target_feature = "atomics")]
|
||||
mod wait_async_polyfill;
|
||||
cfg_if! {
|
||||
if #[cfg(target_feature = "atomics")] {
|
||||
mod wait_async_polyfill;
|
||||
mod multithread;
|
||||
pub(crate) use multithread::*;
|
||||
|
||||
pub(crate) fn spawn(future: Pin<Box<dyn Future<Output = ()> + 'static>>) {
|
||||
cfg_if! {
|
||||
if #[cfg(target_feature = "atomics")] {
|
||||
#[wasm_bindgen::prelude::wasm_bindgen]
|
||||
extern "C" {
|
||||
/// Returns [`crossOriginIsolated`](https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated) global property.
|
||||
#[wasm_bindgen(js_name = crossOriginIsolated)]
|
||||
static CROSS_ORIGIN_ISOLATED: bool;
|
||||
}
|
||||
|
||||
if *CROSS_ORIGIN_ISOLATED {
|
||||
multithread::Task::spawn(future)
|
||||
} else {
|
||||
singlethread::Task::spawn(future)
|
||||
}
|
||||
} else {
|
||||
singlethread::Task::spawn(future)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait Task {
|
||||
fn run(&self);
|
||||
} else {
|
||||
mod singlethread;
|
||||
pub(crate) use singlethread::*;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +81,7 @@ pub fn spawn_local<F>(future: F)
|
||||
where
|
||||
F: Future<Output = ()> + 'static,
|
||||
{
|
||||
task::spawn(Box::pin(future));
|
||||
task::Task::spawn(Box::pin(future));
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
|
||||
@@ -19,7 +19,7 @@ struct QueueState {
|
||||
// The queue of Tasks which are to be run in order. In practice this is all the
|
||||
// synchronous work of futures, and each `Task` represents calling `poll` on
|
||||
// a future "at the right time".
|
||||
tasks: RefCell<VecDeque<Rc<dyn crate::task::Task>>>,
|
||||
tasks: RefCell<VecDeque<Rc<crate::task::Task>>>,
|
||||
|
||||
// This flag indicates whether we've scheduled `run_all` to run in the future.
|
||||
// This is used to ensure that it's only scheduled once.
|
||||
@@ -58,7 +58,7 @@ pub(crate) struct Queue {
|
||||
|
||||
impl Queue {
|
||||
// Schedule a task to run on the next tick
|
||||
pub(crate) fn schedule_task(&self, task: Rc<dyn crate::task::Task>) {
|
||||
pub(crate) fn schedule_task(&self, task: Rc<crate::task::Task>) {
|
||||
self.state.tasks.borrow_mut().push_back(task);
|
||||
// Use queueMicrotask to execute as soon as possible. If it does not exist
|
||||
// fall back to the promise resolution
|
||||
@@ -71,7 +71,7 @@ impl Queue {
|
||||
}
|
||||
}
|
||||
// Append a task to the currently running queue, or schedule it
|
||||
pub(crate) fn push_task(&self, task: Rc<dyn crate::task::Task>) {
|
||||
pub(crate) fn push_task(&self, task: Rc<crate::task::Task>) {
|
||||
// It would make sense to run this task on the same tick. For now, we
|
||||
// make the simplifying choice of always scheduling tasks for a future tick.
|
||||
self.schedule_task(task)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use super::Task as _;
|
||||
use std::cell::RefCell;
|
||||
use std::future::Future;
|
||||
use std::mem::ManuallyDrop;
|
||||
@@ -85,8 +84,27 @@ pub(crate) struct Task {
|
||||
inner: RefCell<Option<Inner>>,
|
||||
}
|
||||
|
||||
impl super::Task for Task {
|
||||
fn run(&self) {
|
||||
impl Task {
|
||||
pub(crate) fn spawn(future: Pin<Box<dyn Future<Output = ()> + 'static>>) {
|
||||
let atomic = AtomicWaker::new();
|
||||
let waker = unsafe { Waker::from_raw(AtomicWaker::into_raw_waker(atomic.clone())) };
|
||||
let this = Rc::new(Task {
|
||||
atomic,
|
||||
waker,
|
||||
inner: RefCell::new(None),
|
||||
});
|
||||
|
||||
let closure = {
|
||||
let this = Rc::clone(&this);
|
||||
Closure::new(move |_| this.run())
|
||||
};
|
||||
*this.inner.borrow_mut() = Some(Inner { future, closure });
|
||||
|
||||
// Queue up the Future's work to happen on the next microtask tick.
|
||||
crate::queue::QUEUE.with(move |queue| queue.schedule_task(this));
|
||||
}
|
||||
|
||||
pub(crate) fn run(&self) {
|
||||
let mut borrow = self.inner.borrow_mut();
|
||||
|
||||
// Same as `singlethread.rs`, handle spurious wakeups happening after we
|
||||
@@ -144,27 +162,6 @@ impl super::Task for Task {
|
||||
}
|
||||
}
|
||||
|
||||
impl Task {
|
||||
pub(crate) fn spawn(future: Pin<Box<dyn Future<Output = ()> + 'static>>) {
|
||||
let atomic = AtomicWaker::new();
|
||||
let waker = unsafe { Waker::from_raw(AtomicWaker::into_raw_waker(atomic.clone())) };
|
||||
let this = Rc::new(Task {
|
||||
atomic,
|
||||
waker,
|
||||
inner: RefCell::new(None),
|
||||
});
|
||||
|
||||
let closure = {
|
||||
let this = Rc::clone(&this);
|
||||
Closure::new(move |_| this.run())
|
||||
};
|
||||
*this.inner.borrow_mut() = Some(Inner { future, closure });
|
||||
|
||||
// Queue up the Future's work to happen on the next microtask tick.
|
||||
crate::queue::QUEUE.with(move |queue| queue.schedule_task(this));
|
||||
}
|
||||
}
|
||||
|
||||
fn wait_async(ptr: &AtomicI32, current_value: i32) -> Option<js_sys::Promise> {
|
||||
// If `Atomics.waitAsync` isn't defined then we use our fallback, otherwise
|
||||
// we use the native function.
|
||||
|
||||
@@ -21,38 +21,6 @@ pub(crate) struct Task {
|
||||
is_queued: Cell<bool>,
|
||||
}
|
||||
|
||||
impl super::Task for Task {
|
||||
fn run(&self) {
|
||||
let mut borrow = self.inner.borrow_mut();
|
||||
|
||||
// Wakeups can come in after a Future has finished and been destroyed,
|
||||
// so handle this gracefully by just ignoring the request to run.
|
||||
let inner = match borrow.as_mut() {
|
||||
Some(inner) => inner,
|
||||
None => return,
|
||||
};
|
||||
|
||||
// Ensure that if poll calls `waker.wake()` we can get enqueued back on
|
||||
// the run queue.
|
||||
self.is_queued.set(false);
|
||||
|
||||
let poll = {
|
||||
let mut cx = Context::from_waker(&inner.waker);
|
||||
inner.future.as_mut().poll(&mut cx)
|
||||
};
|
||||
|
||||
// If a future has finished (`Ready`) then clean up resources associated
|
||||
// with the future ASAP. This ensures that we don't keep anything extra
|
||||
// alive in-memory by accident. Our own struct, `Rc<Task>` won't
|
||||
// actually go away until all wakers referencing us go away, which may
|
||||
// take quite some time, so ensure that the heaviest of resources are
|
||||
// released early.
|
||||
if poll.is_ready() {
|
||||
*borrow = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Task {
|
||||
pub(crate) fn spawn(future: Pin<Box<dyn Future<Output = ()> + 'static>>) {
|
||||
let this = Rc::new(Self {
|
||||
@@ -129,4 +97,34 @@ impl Task {
|
||||
|
||||
RawWaker::new(Rc::into_raw(this) as *const (), &VTABLE)
|
||||
}
|
||||
|
||||
pub(crate) fn run(&self) {
|
||||
let mut borrow = self.inner.borrow_mut();
|
||||
|
||||
// Wakeups can come in after a Future has finished and been destroyed,
|
||||
// so handle this gracefully by just ignoring the request to run.
|
||||
let inner = match borrow.as_mut() {
|
||||
Some(inner) => inner,
|
||||
None => return,
|
||||
};
|
||||
|
||||
// Ensure that if poll calls `waker.wake()` we can get enqueued back on
|
||||
// the run queue.
|
||||
self.is_queued.set(false);
|
||||
|
||||
let poll = {
|
||||
let mut cx = Context::from_waker(&inner.waker);
|
||||
inner.future.as_mut().poll(&mut cx)
|
||||
};
|
||||
|
||||
// If a future has finished (`Ready`) then clean up resources associated
|
||||
// with the future ASAP. This ensures that we don't keep anything extra
|
||||
// alive in-memory by accident. Our own struct, `Rc<Task>` won't
|
||||
// actually go away until all wakers referencing us go away, which may
|
||||
// take quite some time, so ensure that the heaviest of resources are
|
||||
// released early.
|
||||
if poll.is_ready() {
|
||||
*borrow = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user