-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Define agents and agent clusters #2521
Conversation
This requires #2520 to land first. Ideally we also sort out tc39/ecma262#882 first, though with implementations close to shipping somehow this is better than nothing. The other open issue is worklets (see https://drafts.css-houdini.org/worklets/), but that is potentially easy. @bfgeek can a worklet ever be owned by something other than a document? Do we want to allow shared memory with worklets, ever? |
@bzbarsky I suspect you may also find this interesting and worthy of nitpicking as it effectively attempts to formalize the boundaries of processes and shared memory within the browser. |
I'd like to not merge this until we get tc39/ecma262#882 sorted out. We can have the discussion over there, but this is a pretty serious mismatch with my understanding of the purpose of the agent formalism. If we did this then there'd be no point in agents and we could just use realms. |
Worklets can only be owned by a document at the moment, I don't see I need yet to break that at all yet. Shared memory - no, at the moment. We'd also disallow the futex apis. There may be a need later on, but we can cross that bridge when we come to it. |
@bfgeek okay, so we'd basically put each worklet in its own agent cluster. Then it can create SharedArrayBuffer (as each JavaScript environment can) but not share it with anyone. |
@annevk Great, that makes sense at the moment. |
Learned something new from @flagxor in WebAudio/web-audio-api#1194 (comment): https://tc39.github.io/ecma262/#sec-agentcansuspend. We'll need to actually define the value of the [[CanBlock]] field of agents (true for workers, false elsewhere it sounds like, including worklets). Not sure if we need to define any other values, though if tc39/ecma262#882 (comment) ends up being applied, there might be a lot. (I'm not sure we want to block on defining all those though and waiting for another ECMAScript revision. SharedArrayBuffer seems close to shipping, so we should focus on the overall outline and then work through the specifics. In particular, not having it part of the serialize and deserialize algorithm for another month seems strictly worse.) |
I landed a new approach based on the updates in tc39/ecma262#882. I'll need decisions on w3c/css-houdini-drafts#385 and w3c/ServiceWorker#1115 though and @domenic will need to agree with using global objects as our way of defining agents until such a time arrives where can properly allocate agent clusters and agents at specific points in the various standards. |
Still going through my morning email but I wanted to add a reminder to us that we should be able to write web platform tests for the [[CanBlock]] stuff in each different context. (Maybe not worklets yet since nobody's shipped them?) |
Oh, I actually read your message now. I'm not really OK with saying global objects === agents. I think we should not merge anything until we have event loop === agents. It's just way too misleading for implementers otherwise. |
I'm not saying global objects === agents. I suggest reading the PR first. I think event loop === agents is the wrong way to go as they're obviously very different. |
OK, I'll read the PR. I still am pretty sure event loops are === agents in implementations and that we want to reflect that in the spec, since SAB makes so much of the event loop machinery observable (i.e. ordering between independent event loops). But we'll see. Sorry for jumping the gun. |
I could be convinced that we want to align event loops (in particular those for browsing contexts) with the scope of agents and have agents effectively hold an event loop, but I don't think that would actually match implementations. E.g., if you have a cross-origin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, so I think this approach works, but it's very confusing right now because it makes it look like we define a distinct agent for each Window.
Maybe a way to phrase this is to flip it and define five classes of agents (one for each type of global), and then say something about how e.g. each URSOBC creates a single Window-agent. (As does each WorkerGlobalScope, WorkletGlobalScope, etc.) You can then add a note about how with these definitions, every Realm belongs to an agent.
Upon re-reading the spec I see I had previously misread and thought it said that each URSOBC got its own event loop. I think that may still be necessary with the stuff SAB makes observable, but I am not sure, and we don't need to block on redefining event loop, since this approach appears good. I will file a separate issue to check on that.
source
Outdated
|
||
<p>JavaScript defines the concept of an <span>agent</span>. Until such a time that this standard | ||
has a better handle on lifetimes, we define an <span>agent</span> from the perspective of a | ||
<span>global object</span>: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little unclear on what lifetimes have to do with this, and what would be wrong with a definition based on global objects that we plan on fixing in the future
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the future I'd just want CreateAgentCluster followed by CreateAgent at the appropriate places. But we don't clearly define when those things happen today.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh. I'm not sure exactly what the advantages would be of specifying the exact creation time of an agent, but I guess it seems like a reasonable path. Maybe make that more explicit, e.g.
NOTE: in the future, when this specification has a better handle on lifetimes, we hope to define exactly when agents and agent clusters are created.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The advantage is that it's much more clear to implementations when they can allocate a new process and where the boundaries are. That is, the lifetimes are more clear.
source
Outdated
<span>global object</span>: | ||
|
||
<dl class="switch"> | ||
<dt><code>Window</code></dt> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is confusing. It makes it look like each Window has an agent. But e.g. a same-origin iframe's Window should not have its own agent, since that Window's realm is part of the parent Window's agent. Remember per AWB's comment: realms cannot be shared between two agents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it clear from the definition what the agent is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not to me. The <dl>
structure makes it look like you are defining a distinct agent for each global object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not what the paragraph before says.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It says an agent is defined "from the perspective of" a global object. I have no idea what that means precisely, but my best guess is that you look at each global object in turn, and from its perspective you generate an agent, using the following definition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I don't want to generate agents, since you can't do that after the fact. I just want to explain their scope and features in relation to global objects, which are a fairly well understood concept.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you see my comment above suggesting a way around this?
Maybe a way to phrase this is to flip it and define five classes of agents (one for each type of global), and then say something about how e.g. each URSOBC creates a single Window-agent. (As does each WorkerGlobalScope, WorkletGlobalScope, etc.) You can then add a note about how with these definitions, every Realm belongs to an agent.
I don't think this is "generating agents"; it's just defining what agents exist, given a known set of globals.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed that, thanks. I can give that a try. It would actually be useful to have names for these agents in discussion as well.
source
Outdated
<dd><p>The <span>agent</span>'s [[CanBlock]] is false, and its set of <span data-x="JavaScript | ||
realm">JavaScript realms</span> consists of this <code>Window</code> object's <span | ||
data-x="concept-global-object-realm">Realm</span>, and any other <span | ||
data-x="concept-global-object-realm">Realm</span> of <code>Window</code> objects whose |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Realms
source
Outdated
<dt><code>Window</code></dt> | ||
<dd><p>The set containing <var>globalObject</var>'s <span>agent</span>'s set of realms's | ||
<span data-x="concept-realm-global">global objects</span> and any | ||
<code>DedicatedWorkerGlobalScope</code> object whose <span>the worker's owners</span> contains |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nits: "DedicatedWorkerGlobalScope objects"; "the worker's owners" -> "owners"
source
Outdated
<li><var>globalObject</var>,</li> | ||
<li>the <span data-x="concept-relevant-global">relevant global object</span> of | ||
<var>globalObject</var>'s single <span data-x="the worker's owners">the worker's | ||
owner</span>,</li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: just "owner"
source
Outdated
<var>globalObject</var>'s single <span data-x="the worker's owners">the worker's | ||
owner</span>,</li> | ||
<li>any <span data-x="concept-relevant-global">relevant global object</span> of | ||
<var>globalObject</var>'s <span>the worker's workers</span> that is not a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: linking text should be just "workers"
source
Outdated
<li>the <span data-x="concept-relevant-global">relevant global object</span> of | ||
<var>globalObject</var>'s single <span data-x="the worker's owners">the worker's | ||
owner</span>,</li> | ||
<li>any <span data-x="concept-relevant-global">relevant global object</span> of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do workers have relevant global objects? I think the relevant global object of a worker is the global it was created in, not the WorkerGlobalScope that was created. Not sure what the spec uses for this; maybe "associated WorkerGlobalScope" or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"the worker's workers" are global objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or documents, and the "or documents" is important for why I use relevant global object here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, I seem to have been just confused here.
source
Outdated
<code>ServiceWorkerGlobalScope</code>)</dt> | ||
<dd><p>The set containing <var>globalObject</var> and any <span | ||
data-x="concept-relevant-global">relevant global object</span> of <var>globalObject</var>'s | ||
<span>the worker's workers</span> that is not a <code>SharedWorkerGlobalScope</code> objects.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nits: just "workers" for the link text; no plural on "objects"
source
Outdated
|
||
<div class="example"> | ||
<p>The following pairs of global objects are each within the same <span>can-share-with global | ||
objects</span>, and thus can use <code>SharedArrayBuffer</code> instances to share memory with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: phrasing is awkward here, which is part of why I used "unit of" before. "Set of" might also work, either as part of the dfn or not.
Thoughts:
|
Reportedly Firefox only sets [[CanBlock]] to true for dedicated worker agents. I'm not sure yet why not also for shared worker agents. |
Pushed some editorial things. Really like this approach; thanks for taking it on. I think the tests we should land for this are basically the [[CanBlock]] tests. I can again work on those (but again feel free if I haven't taken over). It sounds like worklets should not get [[CanBlock]], but we're not sure yet about shared workers? @flagxor @binji thoughts from the Blink side? @lars-t-hansen @bakulf thoughts from Gecko? (Since those are the only two browsers implementing shared workers right now.) We'll have other tests for the actual agent cluster boundaries as part of #2518. I don't think we should necessarily block this on getting clarity on worklets' agent clusters since worklets are so young and fresh. But it would be good to keep the pressure on @bfgeek and others :). |
If we switch worker's owner set to only contain global objects (i.e. Windows or WorkerGlobalScopes, not Documents or WorkerGlobalScopes) as has been discussed previously, then we could:
and then the three bullets for "can directly share memory with" would reduce to
My understanding though is that this switch needs a bit more research first and we'd prefer to not hold up this PR for it. We could approximate this today by defining "the agent's Documents" (for similar-origin window agents only) and then define "a worker global object is owned by a Document or WorkerGlobalScope", which would yield
@othermaciej, I'm curious what you think of this, as it does introduce more indirection through definitions, although IMO they are reasonably intuitive ones. Also would love @annevk's thoughts. |
I don't really understand why you switched back so I don't understand if the new text is okay. E.g., now you have that a dedicated worker can share with its parent. But do you have that a dedicated worker can share with a child, if it's a dedicated worker? Also, one of the realizations I had, which I applied in my patch, is that similar-origin window agent, dedicated, shared, and service worker agent, all have the same relationship with a child descendant worker agent. If you think we should define both directions, I think it would have been clearer to just add that a dedicated worker agent can share with its parent, as that's always true. |
(I can probably investigate if we can change owner set next week. The main thing is what happens with initial about:blank documents. Should be fairly trivial...) |
The main thing is that it needs to be symmetric and reflexive. Putting that in paragraph form got fairly unwieldy. Even though, as you say, you can use one sentence to encapsulate the parent-child relationship, it's a pretty obscure sentence, and so the The other issues were that "can share memory with" was a misleading name (since e.g. a window can share with a worker nested inside another worker, but couldn't according to your definition). And that "all the agents that can share memory with each other" was not helpful or precise compared to using transitive closure over binary relations more clearly. That said, I'm not wedded to
Somehow that got dropped, dang -_-.
Yeah, I started doing that, but it ended up being a very long paragraph that was confusing to read compared to the |
@domenic I'm not entirely clear on what text your proposed three bullets would be replacing. Also not sure if the three Document-mentioning bullets would be instead or in addition. This is now deep bike shedding, but I wonder if this would be simpler if the spec didn't explicitly rely on the notion of transitive closure or two levels of relations, but rather stated the equivalence relation laws as well as the sole needed unidirectional relationship. Equivalence relations are always their own transitive closure. I'd imagine this being something like: In addition, any agent A can share memory with
Then there has to be only one rule specific to agent clusters (you share with dedicated workers you own). You explicitly state the equivalence relation laws without needed to state rules that happen to make them true. And you have all you need to define equivalence classes. It's way more obvious that this is symmetric than the original bullets for example, where you would have to read a lot of other definitions and algorithms to confirm that. I think it also ends up being a smaller number of rules, if you count the invocation of transitive closure as a rule. |
I just wanted to make a point about the |
@othermaciej with that definition for "can share memory with", what would you then say about "agent cluster"? And do you think the first bullet point could be defined as I defined it? |
New sketch: A similar-origin window agent, dedicated worker agent, shared worker agent, or service worker agent, ownerAgent, can share memory with a dedicated worker agent whose single realm's global object's owner set includes an item whose relevant realm is contained by ownerAgent. In addition, any agent A can share memory with
An agent cluster consists of all agents that can share memory with each other. This is pretty much the same as what I had, with the addition of @othermaciej's suggestion of being more explicit about the relationships in prose. |
This would replace the current three bullets in my draft that read:
These would be instead of; they are something we could accomplish today without reworking worker ownership to be global-based instead of Document-based.
This makes me uncomfortable but not in a way that I can back up. I guess I don't remember seeing an equivalence relation defined this way before, but I admit it has been many years since my math major. If you and Anne are OK with it then I guess I can be as well. I'd also like to point out that you have two levels of relations too, the unidirectional "owns" and the equivalence relation "can share memory with". But your two-level version is indeed simpler. I guess maybe my discomfort is wondering whether the definition is too circular, as opposed to a multi-stage definition of: A = owns, B = reflexive closure of A, C = symmetric closure of B, D = transitive closure of C. (And then you might have to repeat until it stabilizes?) Probably it is fine for the HTML spec though, which isn't a math textbook...
This seems OK along the lines of @othermaciej's sketch, modulo my above discomfort. However:
(or even just the last sentence by itself.) |
If you want to be fussy about math terms, what you'd say instead is: I think the way you said it is clear enough though. @domenic To be an equivalence relation, it's only necessary that the three equivalence properties be true. Often for interesting mathematical structures, these properties are implicit, and we prove them to be true. But sometimes one gives a definition of a relation that includes these properties explicitly. For example, in the Peano axioms for arithmetic, the the reflexive, symmetric and transitive properties of equality are axioms, and essentially form the definition of the equality relation on natural numbers. Based on this, it's completely kosher from a math perspective to give a definition of an equivalence relation where reflexive, symmetric and transitive properties are explicitly part of the definition. I also don't think it's a circular definition, any more than the usual definition of the Fibonacci numbers is circular. It's a definition with two base cases (dedicated worker ownership and reflexivity) and two recurrence relations that let you extend the base case. Taking the four basic rules as axioms, you can prove doubly indirect transitivity (a = b /\ b = c /\ c = d => a=d) as a theorem, just as you could in Peano arithmetic. I'm not sure this level of mathematical rigor is even necessary, but it is actually there. |
I think I found a variant of @bzbarsky's scenario that doesn't have the guarantees @lars-t-hansen (and JavaScript) is looking for (unless polling and getting nothing back is sufficient). A embeds B through an element FRAME and A and B do not cooperate with each other in any way. B opens an auxiliary browsing context B' and one child worker B''. Then A removes FRAME. At this point B' is still "alive" and B and B'' are no longer running (event loop stopped dead in its track, no final tasks processed or anything). So B and B'' have no way of telling B' and B' can only determine they stopped running through some kind of self-implemented timeout model. This follows from https://html.spec.whatwg.org/multipage/browsers.html#a-browsing-context-is-discarded which is a little more brutal than navigating (which gives you unload). I will continue with fixing the wording in this PR, but that might be something that is interesting to look into further. I came upon this while investigating the lifetime model of workers and whether they could move to be attached to global objects rather than documents as discussed in the latter part of #411. Implementations are very much aligned on documents at the moment so we should not change that here, even if it leads to slightly less elegant wording. |
Define the infrastructure for SharedArrayBuffer. This also clarifies along which boundaries a browser implementation can use processes and threads. Tests: web-platform-tests/wpt#5569. Follow-up to define similar-origin window agents upon a less shaky foundation is #2528. Because of that, similar-origin window agents are the best place to store state that would formerly go on unit of related similar-origin browsing contexts. tc39/ecma262#882 is follow-up to define agents in more detail; in particular make their implicit realms slot explicit. w3c/css-houdini-drafts#224 is follow-up to define worklet ownership better which is needed to define how they relate to agent (sub)clusters. Fixes part of #2260. Fixes #851. Fixes w3c/ServiceWorker#1115. Fixes most of w3c/css-houdini-drafts#380 (no tests and no nice grouping of multiple realms in a single agent as that is not needed).
These two new sections can also be reviewed here: https://html5.org/temp/agents.html#integration-with-the-javascript-agent-formalism. Not all the links will work though. |
It probably is not, though that may be a matter of how you spin it... A heartbeat mechanism that sends a packet every k seconds may be sufficient in principle but is awful for battery, etc. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, let's merge this (and probably the tests too).
Follows whatwg/html#2521. Worklets are not tested at this time as their API is still in flux.
I found a minor issue with a filename of one of the tests that I pushed a fix for. Safari: doesn't support shared or service workers and handles dedicated and windows per this PR. So no bug needed I think. Chrome and Edge: SharedArrayBuffer is not defined. Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1359745. |
Follows whatwg/html#2521. Worklets are not tested at this time as their API is still in flux.
Do the tests also check same-/similar-origin frames and windows? I would expect Safari may not handle that right given Phil's comments above (and we'd be happy to fix it). |
They do; see web-platform-tests/wpt#5003 for details. In particular the case
We're still finishing up the tests for SharedArrayBuffer, which is where most of the agent cluster stuff comes into play; the only tests merged so far (and thus the only bugs filed so far) are about the [[CanBlock]] aspect of agent clusters. |
This puts the infrastructure in place to define SharedArrayBuffer in
detail. See also #2260.