Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify sync vs async nature of Worker::postMessage #5485

Closed
RReverser opened this issue Apr 25, 2020 · 8 comments · Fixed by web-platform-tests/wpt#23270
Closed

Clarify sync vs async nature of Worker::postMessage #5485

RReverser opened this issue Apr 25, 2020 · 8 comments · Fixed by web-platform-tests/wpt#23270

Comments

@RReverser
Copy link
Member

While debugging some cross-browser issues with using WebAssembly threads, I eventually ended up with the following pure-JS example that works differently in different browsers:

let w = new Worker(`data:text/javascript,
postMessage(null);
onmessage = e => Atomics.store(e.data, 0, 1);
`);
w.onmessage = () => {
  console.log('Spawned');
  let a = new Int32Array(new SharedArrayBuffer(4));
  w.postMessage(a);
  while(Atomics.load(a, 0) === 0);
  console.log('Success');
};

For this snippet in Firefox, you'll see messages "Spawned" and "Success" printed in the console, indicating that postMessage has sent a message synchronously (queued it up on the receiver end right away).

In Chrome you'll only see "Spawned" and then the main thread gets blocked forever, which indicates that postMessage got queued up as a task on the main thread and so the Worker will never actually receive the message and won't be able to unblock the atomic.

I've tried to read the relevant bits of the spec as well as looked for existing issues, and while some (e.g. #5078, #5327, #3691) sound relevant, I don't really understand what the correct behaviour is supposed to be here.

Could someone please clarify it and possibly add a WPT test so that I could file a bug for the corresponding browser? /cc @annevk @domenic @zcorpan @surma

@surma
Copy link
Contributor

surma commented Apr 25, 2020

I am happy to write the WPT once we have determined what the expected behavior is.

(Just one thing to clarify: While the example by @RReverser is written using SABs and Atomics, they are not required to make this an observable interop issue. See this Twitter thread)

@RReverser
Copy link
Member Author

While the example by @RReverser is written using SABs and Atomics, they are not required to make this an observable interop issue.

Yeah they're here just for visibility; I could use something as simple as console.log (that's what I did initially) but it has own issues in Firefox because it can't print anything while main thread is locked.

Hence, I think Atomics make a better base for a WPT.

@annevk
Copy link
Member

annevk commented Apr 26, 2020

Nice find. This probably isn't helped with browsers typically having same-thread, cross-thread, and cross-process paths for messaging (and might not use MessageChannel for dedicated workers despite the specification doing so). Immediate queuing is what I'd expect and what the specification requires (it says "Add a task that runs the following steps to the port message queue of targetPort:" without having queued a task to run those steps), but the specification doesn't really consider thread or process boundaries as pointed out in those issues you found. Inter-agent and inter-agent-cluster communication are poorly formalized.

Ideally (see also the end of https://infra.spec.whatwg.org/#algorithms):

  1. The various postMessage() APIs are consistent in observable behavior. Performance differences are acceptable.
  2. The various postMessage() APIs do not require a particular implementation strategy.

@RReverser
Copy link
Member Author

The various postMessage() APIs are consistent in observable behavior. Performance differences are acceptable.

As long as this doesn't result in self.postMessage() becoming async as well, this sounds perfectly reasonable to me.

That is, I think implementation-specific delays in postMessage are perfectly acceptable as long as the message still gets sent and not blocked on the current thread's event loop forever.

@annevk
Copy link
Member

annevk commented Apr 26, 2020

By becoming "async" do you mean "queues a task"? And self.postMessage() is a different API depending on what self is.

@RReverser
Copy link
Member Author

By becoming "async" do you mean "queues a task"?

Yeah. I'd rather hope that both would become "synchronous" (not blocked on current thread).

And self.postMessage() is a different API depending on what self is.

Oh yeah, sorry, I forgot that this context got lost in the Twitter thread. I meant messaging from worker to main window, which currently works as expected across browsers. E.g.:

new Worker(`data:text/javascript,
postMessage(42);
while(true);
`).onmessage = e => console.log(e.data);

Prints 42 everywhere.

@annevk
Copy link
Member

annevk commented Apr 27, 2020

Yeah, I agree that's what we should aim for. postMessage() queuing a task doesn't make much sense to me. I could see it going "in parallel", but delaying a "block" of the thread it's running on seems kinda pointless.

@RReverser
Copy link
Member Author

Ok; I'll try and prepare a WPT test.

RReverser added a commit to RReverser/wpt that referenced this issue Apr 27, 2020
Per spec postMessage should queue a message up on the target port immediately.

Instead, when Workers are involved, some implementations queue a task up on current thread's event loop, which means that in case it gets blocked, some messages are never sent.

Resolves whatwg/html#5485.
RReverser added a commit to RReverser/wpt that referenced this issue Apr 27, 2020
Per spec postMessage should queue a message up on the target port immediately.

Instead, when Workers are involved, some implementations queue a task up on current thread's event loop, which means that in case it gets blocked, some messages are never sent.

Resolves whatwg/html#5485.
annevk pushed a commit to web-platform-tests/wpt that referenced this issue Apr 28, 2020
Per spec postMessage should queue a message up on the target port immediately.

Instead, when Workers are involved, some implementations queue a task up on current thread's event loop, which means that in case it gets blocked, some messages are never sent.

Closes whatwg/html#5485.
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue May 5, 2020
…vent loop, a=testonly

Automatic update from web-platform-tests
Test that postMessage doesn't block on event loop

Per spec postMessage should queue a message up on the target port immediately.

Instead, when Workers are involved, some implementations queue a task up on current thread's event loop, which means that in case it gets blocked, some messages are never sent.

Closes whatwg/html#5485.
--

wpt-commits: 3320205a9d70636efc03cfff340edecd0bee4694
wpt-pr: 23270
xeonchen pushed a commit to xeonchen/gecko that referenced this issue May 5, 2020
…vent loop, a=testonly

Automatic update from web-platform-tests
Test that postMessage doesn't block on event loop

Per spec postMessage should queue a message up on the target port immediately.

Instead, when Workers are involved, some implementations queue a task up on current thread's event loop, which means that in case it gets blocked, some messages are never sent.

Closes whatwg/html#5485.
--

wpt-commits: 3320205a9d70636efc03cfff340edecd0bee4694
wpt-pr: 23270
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this issue May 6, 2020
…vent loop, a=testonly

Automatic update from web-platform-tests
Test that postMessage doesn't block on event loop

Per spec postMessage should queue a message up on the target port immediately.

Instead, when Workers are involved, some implementations queue a task up on current thread's event loop, which means that in case it gets blocked, some messages are never sent.

Closes whatwg/html#5485.
--

wpt-commits: 3320205a9d70636efc03cfff340edecd0bee4694
wpt-pr: 23270

UltraBlame original commit: 69db48f9993a97aa33b2c1cfc8d424a81f0a6290
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this issue May 6, 2020
…vent loop, a=testonly

Automatic update from web-platform-tests
Test that postMessage doesn't block on event loop

Per spec postMessage should queue a message up on the target port immediately.

Instead, when Workers are involved, some implementations queue a task up on current thread's event loop, which means that in case it gets blocked, some messages are never sent.

Closes whatwg/html#5485.
--

wpt-commits: 3320205a9d70636efc03cfff340edecd0bee4694
wpt-pr: 23270

UltraBlame original commit: 69db48f9993a97aa33b2c1cfc8d424a81f0a6290
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this issue May 6, 2020
…vent loop, a=testonly

Automatic update from web-platform-tests
Test that postMessage doesn't block on event loop

Per spec postMessage should queue a message up on the target port immediately.

Instead, when Workers are involved, some implementations queue a task up on current thread's event loop, which means that in case it gets blocked, some messages are never sent.

Closes whatwg/html#5485.
--

wpt-commits: 3320205a9d70636efc03cfff340edecd0bee4694
wpt-pr: 23270

UltraBlame original commit: 69db48f9993a97aa33b2c1cfc8d424a81f0a6290
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

3 participants