[whatwg] onclose events for MessagePort

Jonas Sicking jonas at sicking.cc
Thu Oct 10 14:52:46 PDT 2013

On Thu, Oct 10, 2013 at 8:26 AM, Ehsan Akhgari <ehsan at mozilla.com> wrote:
> On Thu, Oct 10, 2013 at 2:58 AM, Jonas Sicking <jonas at sicking.cc> wrote:
>> On Wed, Oct 9, 2013 at 3:06 PM, Ehsan Akhgari <ehsan at mozilla.com> wrote:
>> > OK, so I gave this some thought and I and Olli managed to convince each
>> > other that finding a solution to the problem of dispatching a generic
>> > onclose event is impossible since there is no deterministic point in
>> > time
>> > before a worker is GCed when we know that it will be GCed soon.
>> >
>> > So with that behind us, how about we add an explicit event to be fired
>> > when
>> > the other side of a message channel gets destroyed in a catastrophic way
>> > which is not observable from the web content code running on that side,
>> > such
>> > as a process crash for example?  The basic idea behind why this more
>> > restricted proposal is useful is that barring the catastrophic failure
>> > case,
>> > applications can detect the other cases why further communication may be
>> > impossible (such as navigating away from the page) themselves and notify
>> > the
>> > other side of the channel as desired -- it is only the catastrophic
>> > termination case which is not detectable from content script.
>> >
>> > How about we add another event named "channeldropped" (pending
>> > bikeshedding)
>> > which is fired on a message port if the owner global context of its
>> > entangled port is terminated in a catastrophic way?  Needless to say,
>> > the
>> > event will be queued asynchronously with the termination of the other
>> > side,
>> > and it will not be affected by garbage collection.
>> I could see the GC case not being solvable.
>> But is there a reason that we couldn't also fire the event if the
>> other side is forcefully terminated through a navigation or a
>> Worker.terminate() call?
> The reason I did not extend this to navigation and Worker.terminate() is
> that at least in theory the authors should be able to detect those in their
> application and use postMessage() to communicate that information if desired
> (assuming that you can handle window.onunload and have control over the code
> calling terminate(), respectively.)
> Although perhaps my argument is a bit weaker about terminate() than
> navigation.
> Do you see a good reason why we should not leave those cases to authors?

While technically possible for a webpage to handle ports that were
passed to a worker and send a signal before the worker is terminated,
it is really hard.

First off it means that you have to create a separate MessageChannel
just for the close-signal. You can't get the worker to to send the
message without first finishing both the currently running task, and
also processing all the tasks on the workers task queue. This would
defeat the whole purpose of terminate(). So you need to keep a
separate channel specifically to send the close message.

Second, you need to track all the ports that are own by a specific
worker so that you know which channels to send a close message for.

Third, since the close message comes from a separate channel than
other messages, it means that you have to deal with races. When you
get a message from the separate channel that the main channel is
dying, there might still be message in the pipe for the main channel.
But there is no way to know when you got the last one. Timeouts are
probably the only way, and that's obviously racy/slow.

In short: The pain! It is burning!

For navigation things are better since the caller can always use an
onpagehide/onunload send a signal saying that the port is going away.

It occurs to me that all of the proposals here does expose some amount
of GC behavior. Even a "channeldropped" message which is sent only
when the other side crashes exposes GC behavior. If GC happens to run
before the crash and then collect the MessageChannel ports, then no
channel exists at the time of crash, and thus no event is sent.
However if the GC runs later, or if it doesn't successfully collect
the MessageChannel ports, then the "channeldropped" event does fire.

That's not to say that this solution wouldn't work. Exposing some
amount of GC behavior might be ok. But it does mean that we should
have a realistic bar as we discuss expanding the event to more
situations than just process crashes.

One solution which I think would never expose GC behavior is to simply
have a property on the MessagePort which indicates if the owner of the
other side has been killed or navigated away from. No event would fire
as that property changes value.

Since it's a property, it can only be read if a reference to the
MessagePort is being held. As long as such a reference exists neither
side of the MessageChannel can be GCed.

/ Jonas

>> > --
>> > Ehsan
>> > <http://ehsanakhgari.org/>
>> >
>> >
>> > On Tue, Oct 1, 2013 at 6:14 PM, Jonas Sicking <jonas at sicking.cc> wrote:
>> >>
>> >> On Tue, Oct 1, 2013 at 11:13 AM, Boris Zbarsky <bzbarsky at mit.edu>
>> >> wrote:
>> >> > On 10/1/13 2:11 PM, Ian Hickson wrote:
>> >> >>
>> >> >> How often do we expect two tabs to be talking to each other though?
>> >> >
>> >> > Or a page to an out-of-process subframe?
>> >>
>> >> Or an out-of-process worker. I would think that in Chrome
>> >> SharedWorkers can come from a separate process, though that might
>> >> change if/when chrome switches to out-of-process iframes.
>> >>
>> >> / Jonas
>> >
>> >

More information about the whatwg mailing list