Skip to content

Commit

Permalink
Update waitAsync signature to latest spec (#2362)
Browse files Browse the repository at this point in the history
* Update `waitAsync` signature to latest spec

Looks like Chrome implements this now and the spec has also changed
since this was first implemented. Relatively easy to update the
implementation though!

Closes #2361

* Update UI tests for new stable Rust
  • Loading branch information
alexcrichton authored Nov 19, 2020
1 parent eb0ff9b commit e0ffa8f
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 80 deletions.
110 changes: 65 additions & 45 deletions crates/futures/src/task/multithread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,68 +115,88 @@ impl Task {
None => return,
};

// Also the same as `singlethread.rs`, flag ourselves as ready to
// receive a notification.
let prev = self.atomic.state.swap(SLEEPING, SeqCst);
debug_assert_eq!(prev, AWAKE);

let poll = {
let mut cx = Context::from_waker(&self.waker);
inner.future.as_mut().poll(&mut cx)
};

match poll {
// Same as `singlethread.rs` (noticing a pattern?) clean up
// resources associated with the future ASAP.
Poll::Ready(()) => {
*borrow = None;
}

// Unlike `singlethread.rs` we are responsible for ensuring there's
// a closure to handle the notification that a Future is ready. In
// the single-threaded case the notification itself enqueues work,
// but in the multithreaded case we don't know what thread a
// notification comes from so we need to ensure the current running
// thread is the one that enqueues the work. To do that we execute
// `Atomics.waitAsync`, creating a local Promise on our own thread
// which will resolve once `Atomics.notify` is called.
//
// We could be in one of two states as we execute this:
//
// * `SLEEPING` - we'll get notified via `Atomics.notify`
// and then this Promise will resolve.
//
// * `AWAKE` - the Promise will immediately be resolved and
// we'll execute the work on the next microtask queue.
Poll::Pending => {
drop(wait_async(&self.atomic.state, SLEEPING).then(&inner.closure));
loop {
// Also the same as `singlethread.rs`, flag ourselves as ready to
// receive a notification.
let prev = self.atomic.state.swap(SLEEPING, SeqCst);
debug_assert_eq!(prev, AWAKE);

let poll = {
let mut cx = Context::from_waker(&self.waker);
inner.future.as_mut().poll(&mut cx)
};

match poll {
// Same as `singlethread.rs` (noticing a pattern?) clean up
// resources associated with the future ASAP.
Poll::Ready(()) => {
*borrow = None;
}

// Unlike `singlethread.rs` we are responsible for ensuring there's
// a closure to handle the notification that a Future is ready. In
// the single-threaded case the notification itself enqueues work,
// but in the multithreaded case we don't know what thread a
// notification comes from so we need to ensure the current running
// thread is the one that enqueues the work. To do that we execute
// `Atomics.waitAsync`, creating a local Promise on our own thread
// which will resolve once `Atomics.notify` is called.
//
// We could be in one of two states as we execute this:
//
// * `SLEEPING` - we'll get notified via `Atomics.notify`
// and then this Promise will resolve.
//
// * `AWAKE` - the Promise will immediately be resolved and
// we'll execute the work on the next microtask queue.
Poll::Pending => {
match wait_async(&self.atomic.state, SLEEPING) {
Some(promise) => drop(promise.then(&inner.closure)),
// our state has already changed so we can just do the work
// again inline.
None => continue,
}
}
}
break;
}
}
}

fn wait_async(ptr: &AtomicI32, current_value: i32) -> js_sys::Promise {
// If `Atomics.waitAsync` isn't defined (as it isn't defined anywhere today)
// then we use our fallback, otherwise we use the native function.
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.
return if Atomics::get_wait_async().is_undefined() {
crate::task::wait_async_polyfill::wait_async(ptr, current_value)
Some(crate::task::wait_async_polyfill::wait_async(
ptr,
current_value,
))
} else {
let mem = wasm_bindgen::memory().unchecked_into::<js_sys::WebAssembly::Memory>();
Atomics::wait_async(
&mem.buffer(),
ptr as *const AtomicI32 as i32 / 4,
current_value,
)
let array = js_sys::Int32Array::new(&mem.buffer());
let result = Atomics::wait_async(&array, ptr as *const AtomicI32 as i32 / 4, current_value);
if result.async_() {
Some(result.value())
} else {
None
}
};

#[wasm_bindgen]
extern "C" {
type Atomics;
type WaitAsyncResult;

#[wasm_bindgen(static_method_of = Atomics, js_name = waitAsync)]
fn wait_async(buf: &JsValue, index: i32, value: i32) -> js_sys::Promise;
fn wait_async(buf: &js_sys::Int32Array, index: i32, value: i32) -> WaitAsyncResult;

#[wasm_bindgen(static_method_of = Atomics, js_name = waitAsync, getter)]
fn get_wait_async() -> JsValue;

#[wasm_bindgen(method, getter, structural, js_name = async)]
fn async_(this: &WaitAsyncResult) -> bool;

#[wasm_bindgen(method, getter, structural)]
fn value(this: &WaitAsyncResult) -> js_sys::Promise;
}
}
48 changes: 24 additions & 24 deletions crates/macro/ui-tests/async-errors.stderr
Original file line number Diff line number Diff line change
@@ -1,52 +1,52 @@
error[E0277]: the trait bound `std::result::Result<(), ()>: wasm_bindgen::__rt::IntoJsResult` is not satisfied
error[E0277]: the trait bound `std::result::Result<(), ()>: IntoJsResult` is not satisfied
--> $DIR/async-errors.rs:30:1
|
30 | #[wasm_bindgen]
| ^^^^^^^^^^^^^^^ the trait `wasm_bindgen::__rt::IntoJsResult` is not implemented for `std::result::Result<(), ()>`
| ^^^^^^^^^^^^^^^ the trait `IntoJsResult` is not implemented for `std::result::Result<(), ()>`
|
= help: the following implementations were found:
<std::result::Result<(), E> as wasm_bindgen::__rt::IntoJsResult>
<std::result::Result<T, E> as wasm_bindgen::__rt::IntoJsResult>
= note: required by `wasm_bindgen::__rt::IntoJsResult::into_js_result`
<std::result::Result<(), E> as IntoJsResult>
<std::result::Result<T, E> as IntoJsResult>
= note: required by `into_js_result`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `std::result::Result<(), BadType>: wasm_bindgen::__rt::IntoJsResult` is not satisfied
error[E0277]: the trait bound `std::result::Result<(), BadType>: IntoJsResult` is not satisfied
--> $DIR/async-errors.rs:32:1
|
32 | #[wasm_bindgen]
| ^^^^^^^^^^^^^^^ the trait `wasm_bindgen::__rt::IntoJsResult` is not implemented for `std::result::Result<(), BadType>`
| ^^^^^^^^^^^^^^^ the trait `IntoJsResult` is not implemented for `std::result::Result<(), BadType>`
|
= help: the following implementations were found:
<std::result::Result<(), E> as wasm_bindgen::__rt::IntoJsResult>
<std::result::Result<T, E> as wasm_bindgen::__rt::IntoJsResult>
= note: required by `wasm_bindgen::__rt::IntoJsResult::into_js_result`
<std::result::Result<(), E> as IntoJsResult>
<std::result::Result<T, E> as IntoJsResult>
= note: required by `into_js_result`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `wasm_bindgen::JsValue: std::convert::From<BadType>` is not satisfied
error[E0277]: the trait bound `wasm_bindgen::JsValue: From<BadType>` is not satisfied
--> $DIR/async-errors.rs:34:1
|
34 | #[wasm_bindgen]
| ^^^^^^^^^^^^^^^ the trait `std::convert::From<BadType>` is not implemented for `wasm_bindgen::JsValue`
| ^^^^^^^^^^^^^^^ the trait `From<BadType>` is not implemented for `wasm_bindgen::JsValue`
|
= help: the following implementations were found:
<wasm_bindgen::JsValue as std::convert::From<&'a T>>
<wasm_bindgen::JsValue as std::convert::From<&'a std::string::String>>
<wasm_bindgen::JsValue as std::convert::From<&'a str>>
<wasm_bindgen::JsValue as std::convert::From<MyType>>
<wasm_bindgen::JsValue as From<&'a String>>
<wasm_bindgen::JsValue as From<&'a T>>
<wasm_bindgen::JsValue as From<&'a str>>
<wasm_bindgen::JsValue as From<MyType>>
and 62 others
= note: required because of the requirements on the impl of `std::convert::Into<wasm_bindgen::JsValue>` for `BadType`
= note: required because of the requirements on the impl of `wasm_bindgen::__rt::IntoJsResult` for `BadType`
= note: required by `wasm_bindgen::__rt::IntoJsResult::into_js_result`
= note: required because of the requirements on the impl of `Into<wasm_bindgen::JsValue>` for `BadType`
= note: required because of the requirements on the impl of `IntoJsResult` for `BadType`
= note: required by `into_js_result`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `std::result::Result<BadType, wasm_bindgen::JsValue>: wasm_bindgen::__rt::IntoJsResult` is not satisfied
error[E0277]: the trait bound `std::result::Result<BadType, wasm_bindgen::JsValue>: IntoJsResult` is not satisfied
--> $DIR/async-errors.rs:36:1
|
36 | #[wasm_bindgen]
| ^^^^^^^^^^^^^^^ the trait `wasm_bindgen::__rt::IntoJsResult` is not implemented for `std::result::Result<BadType, wasm_bindgen::JsValue>`
| ^^^^^^^^^^^^^^^ the trait `IntoJsResult` is not implemented for `std::result::Result<BadType, wasm_bindgen::JsValue>`
|
= help: the following implementations were found:
<std::result::Result<(), E> as wasm_bindgen::__rt::IntoJsResult>
<std::result::Result<T, E> as wasm_bindgen::__rt::IntoJsResult>
= note: required by `wasm_bindgen::__rt::IntoJsResult::into_js_result`
<std::result::Result<(), E> as IntoJsResult>
<std::result::Result<T, E> as IntoJsResult>
= note: required by `into_js_result`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
4 changes: 2 additions & 2 deletions crates/macro/ui-tests/missing-catch.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0277]: the trait bound `std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>: wasm_bindgen::convert::FromWasmAbi` is not satisfied
error[E0277]: the trait bound `std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>: FromWasmAbi` is not satisfied
--> $DIR/missing-catch.rs:6:9
|
6 | pub fn foo() -> Result<JsValue, JsValue>;
| ^^^ the trait `wasm_bindgen::convert::FromWasmAbi` is not implemented for `std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>`
| ^^^ the trait `FromWasmAbi` is not implemented for `std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>`
6 changes: 3 additions & 3 deletions crates/macro/ui-tests/pub-not-copy.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
error[E0277]: the trait bound `String: std::marker::Copy` is not satisfied
--> $DIR/pub-not-copy.rs:5:16
|
3 | #[wasm_bindgen]
| --------------- required by this bound in `__wbg_get_a_field::assert_copy`
| --------------- required by this bound in `assert_copy`
4 | pub struct A {
5 | pub field: String,
| ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String`
| ^^^^^^ the trait `std::marker::Copy` is not implemented for `String`
8 changes: 4 additions & 4 deletions crates/macro/ui-tests/start-function.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ error[E0277]: the trait bound `std::result::Result<wasm_bindgen::JsValue, ()>: w
|
= help: the following implementations were found:
<std::result::Result<(), E> as wasm_bindgen::__rt::Start>
= note: required by `wasm_bindgen::__rt::Start::start`
= note: required by `start`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>: wasm_bindgen::__rt::Start` is not satisfied
Expand All @@ -29,7 +29,7 @@ error[E0277]: the trait bound `std::result::Result<wasm_bindgen::JsValue, wasm_b
|
= help: the following implementations were found:
<std::result::Result<(), E> as wasm_bindgen::__rt::Start>
= note: required by `wasm_bindgen::__rt::Start::start`
= note: required by `start`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `std::result::Result<wasm_bindgen::JsValue, ()>: wasm_bindgen::__rt::Start` is not satisfied
Expand All @@ -40,7 +40,7 @@ error[E0277]: the trait bound `std::result::Result<wasm_bindgen::JsValue, ()>: w
|
= help: the following implementations were found:
<std::result::Result<(), E> as wasm_bindgen::__rt::Start>
= note: required by `wasm_bindgen::__rt::Start::start`
= note: required by `start`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>: wasm_bindgen::__rt::Start` is not satisfied
Expand All @@ -51,5 +51,5 @@ error[E0277]: the trait bound `std::result::Result<wasm_bindgen::JsValue, wasm_b
|
= help: the following implementations were found:
<std::result::Result<(), E> as wasm_bindgen::__rt::Start>
= note: required by `wasm_bindgen::__rt::Start::start`
= note: required by `start`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
4 changes: 2 additions & 2 deletions crates/macro/ui-tests/traits-not-implemented.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0277]: the trait bound `A: wasm_bindgen::convert::IntoWasmAbi` is not satisfied
error[E0277]: the trait bound `A: IntoWasmAbi` is not satisfied
--> $DIR/traits-not-implemented.rs:8:12
|
8 | pub fn foo(a: A);
| ^^^ the trait `wasm_bindgen::convert::IntoWasmAbi` is not implemented for `A`
| ^^^ the trait `IntoWasmAbi` is not implemented for `A`

0 comments on commit e0ffa8f

Please sign in to comment.