MessagePort attempts to fire already-queued events on a shipped message port after the message port is shipped if the port message queue was already started prior to shipping
Categories
(Core :: DOM: postMessage, defect, P2)
Tracking
()
People
(Reporter: _rvidal, Assigned: asuth)
References
Details
(Whiteboard: dom-lws-bugdash-triage)
Steps to reproduce:
Working example: https://github.com/jrvidal/message-port-repro/tree/master/transfer
We have two workers, with a parent-child relation. The follower then:
- Creates a new MessageChannel,
- Listens to one end of the channel for messages,
- Posts a message to other end of the channel, and
- Transfers the first end of the channel to the parent worker, where it is listened for messages.
All this happens synchronously in follower thread.
Actual results:
The listener set up in the follower thread gets a message:
[follower] port got hello
Note that at this time, the receiving port has been transferred to the parent worker (!).
Expected results:
Not sure if this is what should happen, but in Chrome (98.0.4758.102), it's the leader who receives the message:
[leader] port got hello
There's an extra DESTROY
flag in the example, that unsets onmessage
on the follower right after setting it. In that case the message is lost in FF, but the result is the same in Chrome.
Reporter | ||
Comment 1•4 years ago
|
||
cc asutherland bholley
This is another MessagePort-related issue we've run into on Stackblitz.
Assignee | ||
Comment 2•4 years ago
•
|
||
Blink/Chrome's behavior seems correct under the spec and Gecko/Firefox has a bug here. Thank you for your reporting the bug and continued dedication to creating minimized test cases!
The spec steps for transfer specifically transfer-receiving call for stealing all of the message events on receiving. This is very dubious from a spec language perspective, but as the second info box for entangle says:
While this specification describes this process as instantaneous, implementations are more likely to implement it via message passing. As with all algorithms, the key is "merely" that the end result be indistinguishable, in a black-box sense, from the specification.
Which is to say, the intent is quite clear that events that haven't yet been fired should be moved, so it's clear that our state machine has to handle this case. (There's some hand-waving around the port message queue and unshipped port message queue which makes things a little more awkward, but again, the intent is clear.)
In particular, what's going wrong here is:
- Because the ports are un-shipped (but entangled), our special case directly invokes Dispatch on the target port
- Because the follower has already started the port, the Dispatch method directly queues a PostMessageRunanble. This dispatch removes the message from mMessages.
- The transfer happens, but the message has already been removed so it's not visible to the state machine.
Conceptually, the current implementation wants the PostMessageRunnable to request messages from the MessagePort at Run()-time, not at dispatch time.
Assignee | ||
Updated•4 years ago
|
Updated•4 years ago
|
Assignee | ||
Updated•5 months ago
|
Description
•