Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 45 additions & 26 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -123489,6 +123489,46 @@ interface <dfn interface>SharedWorkerGlobalScope</dfn> : <span>WorkerGlobalScope
<li><p>Return false.</p></li>
</ol>

<div class="note" id="note-worker-lifetime-terminology-relationships">
<p>The following relationships hold between these terms:</p>

<ul>
<li><p>Every <code>WorkerGlobalScope</code> that is <span data-x="active needed worker">actively
needed</span> or <span data-x="protected worker">protected</span> is <span data-x="permissible
worker">permissible</span>.</p></li>

<li><p>Every <code>WorkerGlobalScope</code> that is <span data-x="protected
worker">protected</span> is <span data-x="active needed worker">actively needed</span>.</p></li>
</ul>

<p>However, the converses do not always hold:</p>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused by this wording. Below you're saying workers can be actively needed but not protected, you supply a specific example that proves this is true, and then right here on this line, you say "this relationship does not hold". Should we just change this paragraph to say something like "The following are also true:"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. I changed to "However, the converses do not always hold." If that's still confusing we can retreat to something like "However, note the following:".


<ul>
<li><p>A <code>WorkerGlobalScope</code> can be <span data-x="active needed worker">actively
needed</span> but not <span data-x="protected worker">protected</span>, if it's a dedicated
worker with no outstanding async work that is still performing computation on behalf of a fully
active owner, but whose corresponding <code>Worker</code> object has been garbage collected. <a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does it mean for its Worker object to be garbage collected at this point, but its owner set is still a fully active Document? Is this the case where a fully active Document owner .close()s a dedicated worker and loses a reference to the associated Worker object, yet there is still one single long-running single task running on the worker's event loop? At that point, we just haven't made it to https://html.spec.whatwg.org/#worker-processing-model:concept-WorkerGlobalScope-owner-set-2 yet, so the WorkerGlobalScope is considered actively needed (from its perspective)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically, yes, although close()ing is not needed. In more detail, GCing the (outside) Worker object does not have any impact on the (inside) WorkerGlobalScope's owner set. The owner set only gets elements removed when:

  • The document is destroyed, or
  • The worker event loop is destroyed

A simple case would be something like:

// outside, in the document
{
  let worker = new Worker("do-work.js");
} // `worker` goes out of scope and is eligible for GC
// inside, in the worker
while (true) {
  // keep the event loop spinning forever so we never reach
  // https://html.spec.whatwg.org/#worker-processing-model:concept-WorkerGlobalScope-owner-set-2
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so we're just referencing GC'ing the the (outside) Worker as a mechanism that runs a teardown things that change the protected status, but goes just shy of changing the actively needed status, right? How does the worker's ports get emptied during GC, is it via https://html.spec.whatwg.org/multipage/web-messaging.html#ports-and-garbage-collection:disentangle?

Anyways, consider this suggestion:

A WorkerGlobalScope can be actively needed but not protected. Consider a dedicated worker
whose event loop's current task is still performing a computation on a behalf of a fully active
owner that has either called close() on the associated Worker object, or garbage collected
it altogether. This worker's ports collection is empty, so it is no longer protected, however its
event loop has not yet yielded to remove its owner from the owner set, so it is still actively
needed.

Thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so we're just referencing GC'ing the the (outside) Worker as a mechanism that runs a teardown things that change the protected status, but goes just shy of changing the actively needed status, right?

Exactly.

How does the worker's ports get emptied during GC, is it via https://html.spec.whatwg.org/multipage/web-messaging.html#ports-and-garbage-collection:disentangle?

Yes, as far as I can tell. https://html.spec.whatwg.org/multipage/workers.html#:~:text=This%20object%20must%20never%20be%20garbage%20collected%20before%20the%20DedicatedWorkerGlobalScope%20object. also kind of implies that their lifetime is tied together (although it's not explicit).

Anyways, consider this suggestion:

I'll incorporate the last part of that. Some notes on the first part:

  • You reference the nonexistent worker.close() method. You might mean worker.terminate(), but that terminates the worker which is stronger and will kill even actively needed workers by stopping their script.
  • You omit the "no outstanding async work". That seems important to include because "If global has outstanding timers, database transactions, or network connections", it is protected.

href="#ports-and-garbage-collection">Because of the garbage collection</a>, the <span
data-x="the worker's ports">ports</span> collection is empty, so it is no longer protected.
However, its event loop has not yet yielded to <a
href="#step-empty-worker-global-scope-owner-set">empty its owner set</a>, so it is still
actively needed.</p></li>

<li><p>A <code>WorkerGlobalScope</code> can be <span data-x="permissible
worker">permissible</span> but not <span data-x="protected worker">protected</span> or <span
data-x="active needed worker">actively needed</span>, if all the <code>Document</code>s in its
transitive set of owners are in <a href="#note-bfcache">bfcache</a>, or if it's a
<code>SharedWorkerGlobalScope</code> with no current owners being kept alive for the duration of
the <span>between-loads shared worker timeout</span>.</p></li>
</ul>
</div>

<p class="note" id="note-between-loads-shared-worker-timeout-lifetime">The <span>between-loads
shared worker timeout</span> only influences the definition of <span data-x="permissible
worker">permissible</span>, not <span data-x="protected worker">protected</span>, and so
implementations are not required to keep shared workers alive for that duration. Rather, they are
required to close shared workers after the timeout is reached.</p>

<p>A <code>WorkerGlobalScope</code> <var>global</var> is <dfn data-x="suspendable
worker">suspendable</dfn> if the following algorithm returns true:</p>

Expand All @@ -123511,33 +123551,15 @@ interface <dfn interface>SharedWorkerGlobalScope</dfn> : <span>WorkerGlobalScope
they stop being <span data-x="protected worker">protected</span> and when they stop being <span
data-x="permissible worker">permissible</span>.</p></li>

<li><p>Workers get <a href="#step-suspending-workers">suspended or un-suspended</a> based on
whether they are <span data-x="suspendable worker">suspendable</span>.</p></li>

<li><p>Workers that have been closed, but keep executing, <a
href="#terminate-rampant-workers">can be terminated</a> at the user agent's discretion, once
they stop being <span data-x="active needed worker">actively needed</span>.</p></li>
</ul>

<p>Note that every <code>WorkerGlobalScope</code> that is <span data-x="active needed
worker">actively needed</span> is <span data-x="protected worker">protected</span>, and every
<code>WorkerGlobalScope</code> that is <span data-x="protected worker">protected</span> is <span
data-x="permissible worker">permissible</span>. (But the converses do not hold.)</p>

<p>An important difference between <span data-x="protected worker">protected</span> and <span
data-x="permissible worker">permissible</span> is that a <code>WorkerGlobalScope</code> is <span
data-x="protected worker">protected</span> only if its transitive set of owners contains at least
one <span>fully active</span> <code>Document</code>, whereas a <code>WorkerGlobalScope</code> can
be <span data-x="permissible worker">permissible</span> even if all the <code>Document</code>s in
its transitive set of owners are in <a href="#note-bfcache">bfcache</a>.</p>
<li><p>Workers get <a href="#step-suspending-workers">suspended or un-suspended</a> based on
whether they are <span data-x="suspendable worker">suspendable</span>.</p></li>
</ul>
</div>

<p class="note" id="note-between-loads-shared-worker-timeout-lifetime">The <span>between-loads
shared worker timeout</span> only influences the definition of <span data-x="permissible
worker">permissible</span>, not <span data-x="protected worker">protected</span>, and so
implementations are not required to keep shared workers alive for that duration. Rather, they are
required to close shared workers after the timeout is reached.</p>


<h4 id="worker-processing-model"><span id="processing-model-10"></span>Processing model</h4>

Expand Down Expand Up @@ -123831,11 +123853,8 @@ interface <dfn interface>SharedWorkerGlobalScope</dfn> : <span>WorkerGlobalScope
<p>Disentangle all the ports in the list of <span>the worker's ports</span>.</p>
</li>

<li>
<!-- this has no normative impact but makes it clearer that the worker is irrelevant now, and
doesn't have to survive until its Documents all die off too --> <p><span data-x="list
empty">Empty</span> <var>worker global scope</var>'s <span>owner set</span>.</p>
</li>
<li id="step-empty-worker-global-scope-owner-set"><p><span data-x="list empty">Empty</span>
<var>worker global scope</var>'s <span>owner set</span>.</p></li>
</ol>
</li>
</ol>
Expand Down