[whatwg] Workers: What can be done in a worker after call to close()?

Hi,

When implementing the close() function for Firefox we chose to set the
closing flag and clear pending events only. As the worker script is
calling close() on itself we figured that the worker should retain
maximum functionality until it has finished execution (otherwise it
could just not call close() and rely on some kind of postMessage() and
terminate() combo). Therefore we do not enforce any timeout for the
currently executing script and we continue to allow postMessage()
calls and synchronous XHR to proceed. Since the closing flag is set in
response to close() the worker is guaranteed to finish as soon as the
currently running script finishes. We always enforce a timeout for any
code that runs in response to the close event that gets fired after
the current script finishes, though.

If the code that calls close() never returns (like the while(1) { }
example above) then the worker will never finish, as pointed out
above, but that's no different than having a worker script that
consists only of a while(1) { } loop and we don't think it's important
to prevent. If a worker script is written in this way then a
terminate() call is still a valid solution.

Also, since we try to retain maximum functionality after close() we
also allow errors to propagate as shown above.

If anyone is curious the basic strategy we use in response to close
functions (like close(), terminate(), and for UA-generated events like
when the main worker object is GC'd) can be found in the following
table:

http://mxr.mozilla.org/mozilla-central/source/dom/src/threads/nsDOMWorker.h#202

-Ben

On Tue, Mar 30, 2010 at 6:38 PM, Dmitry Titov <dimich at chromium.org> wrote:
>
> On Tue, Mar 30, 2010 at 5:58 PM, Drew Wilson <atwilson at google.com> wrote:
>>
>> I'll note that the spec gives the UA an significant amount of latitude
>> about its behavior after close() is called:
>> User agents may invoke the "kill a worker" processing model on a worker at
>> any time, e.g. in response to user requests, in response to CPU quota
>> management, or when a worker stops being an?active needed worker?if the
>> worker continues executing even after its?closing?flag was set to true.
>> Essentially, UAs can kill a worker at any time, and since the "kill a
>> worker" algorithm allows UAs to abort the script after a user-agent-defined
>> amount of time (including zero), it seems like almost any behavior
>> post-close is compliant. This seems like a guaranteed source of
>> cross-browser incompatibilities.
>
> Yes, and this, after many hours of troubles, may eventually crystallize into
> "don't have any code after close() in your worker code" rule-of-thumb for
> web developers. Which is basically a bad thing...
> This is why it could be better to specify explicitly that either execution
> is immediately terminated or it runs until JS exits with full functionality
> of the worker, not in a special almost-closed mode. Having a timeout
>
>>
>> I've always operated under the impression that the intent of the spec is
>> to allow pending worker operations to complete, but still give UAs the
>> ability to abort scripts that don't exit in a timely manner (so close()
>> should not immediately abort the script), but I don't see anything in the
>> spec regarding this.
>> For #2 below, I believe that exceptions in worker context should *always*
>> be reported, regardless of closing state. Section 4.6 (Runtime script
>> errors) makes no mention of tying this behavior to the closing flag.
>
> This applies as long as the browser still executes the code after close().
> In WebKit V8 case, we terminate execution almost instantly, so we don't even
> run the code that causes an error :-) If we are not to terminate execution
> instantly, then it'd be nice to say the script runs until it ends (or parent
> document closes, which actually terminates the script forcefully), and not
> have a requirement to stop the queue or disconnect ports, as to not create a
> whole new 'mode of worker execution' which needs to have a spec on its own
> since all other features will need to be mentions (like sync APIs).
> It's not clear why a fixed timeout would be useful. It would create some
> randomness in what a worker can still do after?calling?close(). I think web
> developers would then rather do those things before calling close(), to
> avoid random results.
> But if we say close() lets script run until completion (but prevents further
> messages/events from dispatching), then perhaps we don't need it at all -
> there is nothing then that script in the worker can not do to the same
> effect (unregister onmessage, clear timers etc).
> That means letting worker to call close() on itself only makes additional
> sense if it is specified as immediate termination. It could be useful and it
> can be specified in deterministic manner.
> On a separate note, I agree with giving workers some time before terminating
> them in case the parent page closes - but this is the case when forces
> outside and async to the worker need to close it. I think
> it's?different?when worker's own script wants to terminate - it could do its
> last wishes before calling close() as well.
>
>>
>> -atw
>>
>>
>> On Tue, Mar 30, 2010 at 4:44 PM, Dmitry Titov <dimich at chromium.org> wrote:
>>>
>>> Hi!
>>> Trying to fix some bugs for Workers, I've got some questions about
>>> close() method on WorkerGlobalScope.
>>> In particular, the spec seems to imply that after?calling?close() inside
>>> the worker, the JS does not get terminated right away, but rather continue
>>> to execute, while an internal 'closing' flag is set and a message
>>> queue?associated?with the worker discards all the tasks, existing and
>>> future. Also, all ports are immediately disentangled.
>>> This seems to leave some questions without explicit answer, with
>>> differences in current implementations:
>>> 1. Does this code in a?worker?continues looping until the parent page
>>> unloads:
>>> ?...
>>> ?close();
>>> ?while(true) {}
>>> WebKit V8 terminates, WebKit JCS terminates after a timeout, FF does not
>>> terminate.
>>> 2. Do the errors propagate back to Worker object after close()?
>>> ...
>>> close();
>>> nonExistingFunction(); ?<<-- throws, if not processed locally, posts
>>> error info to the Worker object.
>>> In WebKit and FF errors propagate, although it does not seem consistent
>>> while worker closed all the ports and is in a dormant state.
>>> 3. Should synchronous operations work after close()? Asynchronous ones
>>> perhaps should not, because of the event loop queue which is stopped...
>>> ...
>>> close();
>>> xhr.open("GET", "foo.com", false);
>>> xhr.send();
>>> WebKit: does not work (mostly), FF - does work.
>>> Perhaps it would be simpler to either say nothing is
>>> executed/posted/fired after close() (immediate termination), or to enable
>>> worker run unimpeded (with ports open, etc) until it naturally yields from
>>> JS.
>>> Any opinions?
>>> Thanks,
>>> Dmitry
>>>
>>
>
>

Received on Wednesday, 31 March 2010 10:03:02 UTC