Re: Synchronous postMessage for Workers?

On Mon, Feb 13, 2012 at 2:44 PM, Ian Hickson <ian@hixie.ch> wrote:
> On Thu, 17 Nov 2011, Joshua Bell wrote:
>>
>> Wouldn't it be lovely if the Worker script could simply make a
>> synchronous call to fetch data from the Window?
>
> It wouldn't be so much a synchronous call, so much as a blocking get.
>
>
> On Thu, 17 Nov 2011, Jonas Sicking wrote:
>>
>> We can only allow child workers to block on parent workers. Never the
>> other way around.
>
> Indeed. And it would have to be limited to the built-in ports that workers
> have, because regular ports can be shunted all over the place and you
> could end up with a deadlock situation.
>
> It would be easy enough to add a blocking get on DedicatedWorkerGlobalScope.
> Is this something for which there's a lot of demand?
>
>   // blocking get
>   // no self.onmessage handler needed
>   ...
>   var message = self.getMessage();
>   ...
>
> An alternative is to add continuations to the platform:
>
>   // continuation
>   // (this is not a formal proposal, just a illustration of the concept)
>   var message;
>   self.onmessage = function (event) {
>     message = event;
>     signal('got message'); // queues a task to resume from yieldUntil()
>   };
>   ...
>   yieldUntil('got message');
>   ...
>
> This would be a more general solution and would be applicable in many
> other parts of the platform. As we get more and more async APIs, I think
> it might be worth considering adding this.
>
> We could add it to HTML as an API rather than adding it to JS as a
> language construct. It would be relatively easy to define, if much harder
> to implement:
>
>   yieldUntil(id) - spin the event loop until the signal() API unblocks
>                    this script
>
>   signal(id)     - unblock the script with the oldest invokation of
>                    yieldUntil() called with the given ID, if any
>
> Given our definition of "spin the event loop", this doesn't even result,
> per the spec, in nested event loops or anything like that. Note that per
> this definition, "signal" just queues a task to resume the earlier script,
> it is not your typical coroutine. That is:
>
>   setTimeout(function () {
>     console.log('2');
>     signal('test');
>     console.log('3');
>   }, 1000);
>   console.log('1');
>   yieldUntil('test');
>   console.log('4');
>
> ...logs 1, 2, 3, 4, not 1, 2, 4, 3.
>
> Anyone object to me adding something like this? Are there any better
> solutions? Should we just tell authors to get used to the async style?

Spinning the event loop is very bug prone. When calling the yieldUntil
function basically anything can happen, including re-entering the same
code. Protecting against the entire world changing under you is very
hard. Add to that that it's very racy. I.e. changes may or may not
happen under you depending on when exactly you call yieldUntil, and
which order events come in.

This is something we've been fighting with in Gecko for a long time.
Code that spins the event loop has very often lead to terrible bugs
and so we've been trying to get rid of it as much as possible. And
that despite being used to very random things happening under us since
we often call out into unknown/hostile code (js-code in a webpage).

/ Jonas

Received on Tuesday, 14 February 2012 16:08:38 UTC