From 27cd411d8e5a4244480fb1aa0e0a4f5d941439f6 Mon Sep 17 00:00:00 2001 From: Scott Haseley <shaseley@chromium.org> Date: Thu, 4 Apr 2024 09:47:37 -0700 Subject: [PATCH] Editorial: Clean up spec markdown (#75) Editorial: Clean up spec markdown --- spec/controlling-tasks.md | 95 +++++----- spec/index.bs | 13 ++ spec/introduction.md | 3 +- spec/patches.md | 62 +++---- spec/privacy.md | 3 +- spec/scheduling-tasks.md | 354 +++++++++++++++++--------------------- spec/security.md | 9 +- 7 files changed, 249 insertions(+), 290 deletions(-) diff --git a/spec/controlling-tasks.md b/spec/controlling-tasks.md index 115b662..734f31f 100644 --- a/spec/controlling-tasks.md +++ b/spec/controlling-tasks.md @@ -1,15 +1,12 @@ -Controlling Tasks {#sec-controlling-tasks} -===================== +# Controlling Tasks # {#sec-controlling-tasks} -Tasks scheduled through the {{Scheduler}} interface can be controlled with a -{{TaskController}} by passing the {{TaskSignal}} provided by -{{AbortController/signal|controller.signal}} as the -{{SchedulerPostTaskOptions/signal|option}} when calling {{Scheduler/postTask()}}. -The {{TaskController}} interface supports aborting and changing the priority of -a task or group of tasks. +Tasks scheduled through the {{Scheduler}} interface can be controlled with a {{TaskController}} by +passing the {{TaskSignal}} provided by {{AbortController/signal|controller.signal}} as the +{{SchedulerPostTaskOptions/signal|option}} when calling {{Scheduler/postTask()}}. The +{{TaskController}} interface supports aborting and changing the priority of a task or group of +tasks. -The `TaskPriorityChangeEvent` Interface {#sec-task-priority-change-event} ---------------------- +## The `TaskPriorityChangeEvent` Interface ## {#sec-task-priority-change-event} <pre class='idl'> [Exposed=(Window, Worker)] @@ -27,19 +24,17 @@ The `TaskPriorityChangeEvent` Interface {#sec-task-priority-change-event} <dl class="domintro non-normative"> <dt><code>event . {{TaskPriorityChangeEvent/previousPriority}}</code></dt> <dd> - <p>Returns the {{TaskPriority}} of the corresponding {{TaskSignal}} prior to - this `prioritychange` event. + <p>Returns the {{TaskPriority}} of the corresponding {{TaskSignal}} prior to this + `prioritychange` event. <p>The new {{TaskPriority}} can be read with `event.target.priority`. </dd> </dl> -The <dfn attribute for=TaskPriorityChangeEvent>previousPriority</dfn> getter -steps are to return the value that the corresponding attribute was initialized -to. +The <dfn attribute for=TaskPriorityChangeEvent>previousPriority</dfn> getter steps are to return the +value that the corresponding attribute was initialized to. -The `TaskController` Interface {#sec-task-controller} ---------------------- +## The `TaskController` Interface ## {#sec-task-controller} <pre class='idl'> dictionary TaskControllerInit { @@ -54,22 +49,21 @@ The `TaskController` Interface {#sec-task-controller} }; </pre> -Note: {{TaskController}}'s {{AbortController/signal}} getter, which is -inherited from {{AbortController}}, returns a {{TaskSignal}} object. +Note: {{TaskController}}'s {{AbortController/signal}} getter, which is inherited from +{{AbortController}}, returns a {{TaskSignal}} object. <dl class="domintro non-normative"> <dt><code>controller = new {{TaskController/TaskController()|TaskController}}( |init| )</code> <dd> - <p> Returns a new {{TaskController}} whose {{AbortController/signal}} is - set to a newly created {{TaskSignal}} with its {{TaskSignal/priority}} - initialized to |init|'s {{TaskControllerInit/priority}}. + <p> Returns a new {{TaskController}} whose {{AbortController/signal}} is set to a newly created + {{TaskSignal}} with its {{TaskSignal/priority}} initialized to |init|'s + {{TaskControllerInit/priority}}. </dd> <dt><code>controller . {{TaskController/setPriority()|setPriority}}( |priority| )</code> <dd> - <p>Invoking this method will change the associated {{TaskSignal}}'s - [=TaskSignal/priority=], signal the priority change to any observers, and - cause `prioritychange` events to be dispatched. + <p>Invoking this method will change the associated {{TaskSignal}}'s [=TaskSignal/priority=], + signal the priority change to any observers, and cause `prioritychange` events to be dispatched. </dd> </dl> @@ -82,12 +76,10 @@ inherited from {{AbortController}}, returns a {{TaskSignal}} object. 1. Set [=this's=] [=AbortController/signal=] to |signal|. </div> -The <dfn method for=TaskController><code>setPriority(|priority|)</code></dfn> -method steps are to [=TaskSignal/signal priority change=] on [=this=]'s -[=AbortController/signal=] given |priority|. +The <dfn method for=TaskController><code>setPriority(|priority|)</code></dfn> method steps are to +[=TaskSignal/signal priority change=] on [=this=]'s [=AbortController/signal=] given |priority|. -The `TaskSignal` Interface {#sec-task-signal} ---------------------- +## The `TaskSignal` Interface ## {#sec-task-signal} <pre class='idl'> dictionary TaskSignalAnyInit { @@ -104,9 +96,9 @@ The `TaskSignal` Interface {#sec-task-signal} }; </pre> -Note: {{TaskSignal}} inherits from {{AbortSignal}} and can be used in APIs that -accept an {{AbortSignal}}. Additionally, {{Scheduler/postTask()}} accepts an -{{AbortSignal}}, which can be useful if dynamic prioritization is not needed. +Note: {{TaskSignal}} inherits from {{AbortSignal}} and can be used in APIs that accept an +{{AbortSignal}}. Additionally, {{Scheduler/postTask()}} accepts an {{AbortSignal}}, which can be +useful if dynamic prioritization is not needed. <dl class="domintro non-normative"> <dt><code>TaskSignal . <a method for=TaskSignal lt="any(signals, init)">any</a>(|signals|, |init|)</code> @@ -137,30 +129,32 @@ A {{TaskSignal}} object has associated <dfn for=TaskSignal>dependent signals</df of {{TaskSignal}} objects that are dependent on the object for their [=TaskSignal/priority=]), which is initially empty. -A {{TaskSignal}} object has an associated <dfn for=TaskSignal>dependent</dfn> (a -boolean), which is initially false. +A {{TaskSignal}} object has an associated <dfn for=TaskSignal>dependent</dfn> (a boolean), which is +initially false. -<br> +<hr> -The <dfn attribute for="TaskSignal">priority</dfn> getter steps are to return -[=this=]'s [=TaskSignal/priority=]. +The <dfn attribute for="TaskSignal">priority</dfn> getter steps are to return [=this=]'s +[=TaskSignal/priority=]. -The <dfn attribute for=TaskSignal><code>onprioritychange</code></dfn> attribute -is an [=event handler IDL attribute=] for the `onprioritychange` -[=event handler=], whose [=event handler event type=] is -<dfn event for=TaskSignal>prioritychange</dfn>. +The <dfn attribute for=TaskSignal><code>onprioritychange</code></dfn> attribute is an [=event +handler IDL attribute=] for the `onprioritychange` [=event handler=], whose [=event handler event +type=] is <dfn event for=TaskSignal>prioritychange</dfn>. -To <dfn for="TaskSignal">add a priority change algorithm</dfn> |algorithm| to a -{{TaskSignal}} object |signal|, [=set/append=] |algorithm| to |signal|'s -[=TaskSignal/priority change algorithms=]. +The static <dfn method for=TaskSignal><code>any(|signals|, |init|)</code></dfn> method steps are to +return the result of [=creating a dependent task signal=] from |signals| and |init|. -<br> +<hr> A {{TaskSignal}} <dfn for=TaskSignal lt="has fixed priority|have fixed priority">has fixed priority</dfn> if it is a [=TaskSignal/dependent=] signal with a null [=TaskSignal/source signal=]. +To <dfn for="TaskSignal">add a priority change algorithm</dfn> |algorithm| to a {{TaskSignal}} +object |signal|, [=set/append=] |algorithm| to |signal|'s [=TaskSignal/priority change algorithms=]. + <div algorithm> - The static <dfn method for=TaskSignal><code>any(|signals|, |init|)</code></dfn> method steps are: + To <dfn>create a dependent task signal</dfn> from a [=list=] of {{AbortSignal}} objects |signals| + and a {{TaskSignalAnyInit}} |init|: 1. Let |resultSignal| be the result of <a for=AbortSignal>creating a dependent signal</a> from |signals| using the {{TaskSignal}} interface and the [=current realm=]. @@ -180,8 +174,8 @@ if it is a [=TaskSignal/dependent=] signal with a null [=TaskSignal/source signa </div> <div algorithm> - To <dfn for="TaskSignal">signal priority change</dfn> on a {{TaskSignal}} - object |signal|, given a {{TaskPriority}} |priority|: + To <dfn for="TaskSignal">signal priority change</dfn> on a {{TaskSignal}} object |signal|, given a + {{TaskPriority}} |priority|: 1. If |signal|'s [=TaskSignal/priority changing=] is true, then [=exception/throw=] a "{{NotAllowedError!!exception}}" {{DOMException}}. @@ -205,7 +199,6 @@ A [=TaskSignal/dependent=] {{TaskSignal}} object must not be garbage collected w [=TaskSignal/source signal=] is non-null and it has registered event listeners for its {{TaskSignal/prioritychange}} event or its [=TaskSignal/priority change algorithms=] is non-empty. -Examples {#sec-controlling-tasks-examples} ---------------------- +## Examples ## {#sec-controlling-tasks-examples} **TODO**(shaseley): Add examples. diff --git a/spec/index.bs b/spec/index.bs index 33961b9..2511923 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -69,6 +69,19 @@ Include MDN Panels: maybe top: -0.8em; left: -0.8em; } + +/* WHATWG-style <hr>s, instead of WICG-style. Specific selector is necessary to override WICG styles. */ +:not(.head) > :not(.head) + hr { + display: block; + background: none; + border: none; + padding: 0; + margin: 2em 0; + height: auto; +} +:not(.head) > :not(.head) + hr::before { + content: none; +} </style> <pre class=link-defaults> diff --git a/spec/introduction.md b/spec/introduction.md index 57fc991..a5a7fe1 100644 --- a/spec/introduction.md +++ b/spec/introduction.md @@ -1,5 +1,4 @@ -Introduction {#intro} -===================== +# Introduction # {#intro} <div class="non-normative"> diff --git a/spec/patches.md b/spec/patches.md index c855ba8..6b990b5 100644 --- a/spec/patches.md +++ b/spec/patches.md @@ -1,14 +1,11 @@ -Modifications to Other Standards {#sec-patches} -===================== +# Modifications to Other Standards # {#sec-patches} -The HTML Standard {#sec-patches-html} ---------------------- +## The HTML Standard ## {#sec-patches-html} ### `WindowOrWorkerGlobalScope` ### {#sec-patches-html-windoworworkerglobalscope} -Each object implementing the {{WindowOrWorkerGlobalScope}} mixin has a -corresponding <dfn for="WindowOrWorkerGlobalScope">scheduler</dfn>, which -is initialized as a new {{Scheduler}}. +Each object implementing the {{WindowOrWorkerGlobalScope}} mixin has a corresponding +<dfn for="WindowOrWorkerGlobalScope">scheduler</dfn>, which is initialized as a new {{Scheduler}}. <pre class='idl'> partial interface mixin WindowOrWorkerGlobalScope { @@ -16,43 +13,38 @@ is initialized as a new {{Scheduler}}. }; </pre> -The <dfn attribute for="WindowOrWorkerGlobalScope">scheduler</dfn> attribute's -getter steps are to return [=this=]'s [=WindowOrWorkerGlobalScope/scheduler=]. - +The <dfn attribute for="WindowOrWorkerGlobalScope">scheduler</dfn> attribute's getter steps are to +return [=this=]'s [=WindowOrWorkerGlobalScope/scheduler=]. ### <a href="https://html.spec.whatwg.org/multipage/webappapis.html#definitions-3">Event loop: definitions</a> ### {#sec-patches-html-event-loop-definitions} -Replace: For each [=event loop=], every [=task source=] must be associated with -a specific [=task queue=]. +Replace: For each [=event loop=], every [=task source=] must be associated with a specific [=task +queue=]. -With: For each [=event loop=], every [=task source=] that is not a -[=scheduler task source=] must be associated with a specific [=task queue=]. +With: For each [=event loop=], every [=task source=] that is not a [=scheduler task source=] must be +associated with a specific [=task queue=]. ### <a href="https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model">Event loop: processing model</a> ### {#sec-patches-html-event-loop-processing} Add the following steps to the event loop processing steps, before step 1: - 1. Let |queues| be the [=set=] of the [=event loop=]'s [=task queues=] that - contain at least one <a for="task">runnable</a> <a for="/">task</a>. - 1. Let |schedulers| be the [=set=] of all {{Scheduler}} objects whose - [=relevant agent's=] [=agent/event loop=] is this event loop and that - [=have a runnable task=]. - 1. If |schedulers| and |queues| are both [=list/empty=], skip to the - <code>microtasks</code> step below. + 1. Let |queues| be the [=set=] of the [=event loop=]'s [=task queues=] that contain at least one + [=task/runnable=] [=task=]. + 1. Let |schedulers| be the [=set=] of all {{Scheduler}} objects whose [=relevant agent's=] + [=agent/event loop=] is this event loop and that [=have a runnable task=]. + 1. If |schedulers| and |queues| are both [=list/empty=], skip to the <code>microtasks</code> step + below. Modify step 1 to read: - 1. Let |taskQueue| be one of the following, chosen in an - [=implementation-defined=] manner: - * If |queues| is not [=list/empty=], one of the [=task queues=] in |queues|, - chosen in an [=implementation-defined=] manner. - * If |schedulers| is not [=list/empty=], the result of - [=selecting the task queue of the next scheduler task=] from one of the - {{Scheduler}}s in |schedulers|, chosen in an [=implementation-defined=] - manner. - -Issue: The |taskQueue| in this step will either be a [=set=] of [=tasks=] or a -[=set=] of [=scheduler tasks=]. The steps that follow only [=set/remove=] an -[=set/item=], so they are *roughly* compatible. Ideally, there would be a -common task queue interface that supports a `pop()` method that would return a -plain [=task=], but that would invlove a fair amount of refactoring. + 1. Let |taskQueue| be one of the following, chosen in an [=implementation-defined=] manner: + * If |queues| is not [=list/empty=], one of the [=task queues=] in |queues|, chosen in an + [=implementation-defined=] manner. + * If |schedulers| is not [=list/empty=], the result of [=selecting the task queue of the next + scheduler task=] from one of the {{Scheduler}}s in |schedulers|, chosen in an + [=implementation-defined=] manner. + +Issue: The |taskQueue| in this step will either be a [=set=] of [=tasks=] or a [=set=] of +[=scheduler tasks=]. The steps that follow only [=set/remove=] an [=set/item=], so they are +*roughly* compatible. Ideally, there would be a common task queue interface that supports a `pop()` +method that would return a plain [=task=], but that would involve a fair amount of refactoring. diff --git a/spec/privacy.md b/spec/privacy.md index 7cada1e..0be3fee 100644 --- a/spec/privacy.md +++ b/spec/privacy.md @@ -1,5 +1,4 @@ -Privacy Considerations {#sec-privacy} -===================== +# Privacy Considerations # {#sec-privacy} <div class="non-normative"> diff --git a/spec/scheduling-tasks.md b/spec/scheduling-tasks.md index 922b311..7a7ec89 100644 --- a/spec/scheduling-tasks.md +++ b/spec/scheduling-tasks.md @@ -1,8 +1,6 @@ -Scheduling Tasks {#sec-scheduling-tasks} -===================== +# Scheduling Tasks # {#sec-scheduling-tasks} -Task Priorities {#sec-task-priorities} ---------------------- +## Task Priorities ## {#sec-task-priorities} This spec formalizes three priorities to support scheduling tasks: @@ -14,24 +12,22 @@ This spec formalizes three priorities to support scheduling tasks: }; </pre> -<dfn enum-value for=TaskPriority>user-blocking</dfn> is the highest priority, -and is meant to be used for tasks that are blocking the user's ability to -interact with the page, such as rendering the core experience or responding to -user input. +<dfn enum-value for=TaskPriority>user-blocking</dfn> is the highest priority, and is meant to be +used for tasks that are blocking the user's ability to interact with the page, such as rendering the +core experience or responding to user input. -<dfn enum-value for=TaskPriority>user-visible</dfn> is the second highest -priority, and is meant to be used for tasks that visible to the user but not -necessarily blocking user actions, such as rendering secondary parts of the -page. This is the default priority. +<dfn enum-value for=TaskPriority>user-visible</dfn> is the second highest priority, and is meant to +be used for tasks that visible to the user but not necessarily blocking user actions, such as +rendering secondary parts of the page. This is the default priority. -<dfn enum-value for=TaskPriority>background</dfn> is the lowest priority, and -is meant to be used for tasks that are not time-critical, such as background -log processing or initializing certain third party libraries. +<dfn enum-value for=TaskPriority>background</dfn> is the lowest priority, and is meant to be used +for tasks that are not time-critical, such as background log processing or initializing certain +third party libraries. -Note: Tasks scheduled through a given {{Scheduler}} run in *strict priority -order*, meaning the scheduler will always run "{{TaskPriority/user-blocking}}" -tasks before "{{TaskPriority/user-visible}}" tasks, which in turn always run -before "{{TaskPriority/background}}" tasks. +Note: Tasks scheduled through a given {{Scheduler}} run in *strict priority order*, meaning the +scheduler will always run "{{TaskPriority/user-blocking}}" tasks before +"{{TaskPriority/user-visible}}" tasks, which in turn always run before "{{TaskPriority/background}}" +tasks. <div algorithm> {{TaskPriority}} |p1| is <dfn for="TaskPriority">less than</dfn> @@ -41,8 +37,7 @@ before "{{TaskPriority/background}}" tasks. </div> -The `Scheduler` Interface {#sec-scheduler} ---------------------- +## The `Scheduler` Interface ## {#sec-scheduler} <xmp class='idl'> dictionary SchedulerPostTaskOptions { @@ -60,112 +55,96 @@ The `Scheduler` Interface {#sec-scheduler} }; </xmp> -Note: The {{SchedulerPostTaskOptions/signal}} option can be either an -{{AbortSignal}} or a {{TaskSignal}}, but is defined as an {{AbortSignal}} since -it is a superclass of {{TaskSignal}}. For cases where the priority might -change, a {{TaskSignal}} is needed. But for cases where only cancellation is -needed, an {{AbortSignal}} would suffice, potentially making it easier to -integrate the API into existing code that uses {{AbortSignal|AbortSignals}}. +Note: The {{SchedulerPostTaskOptions/signal}} option can be either an {{AbortSignal}} or a +{{TaskSignal}}, but is defined as an {{AbortSignal}} since it is a superclass of {{TaskSignal}}. For +cases where the priority might change, a {{TaskSignal}} is needed. But for cases where only +cancellation is needed, an {{AbortSignal}} would suffice, potentially making it easier to integrate +the API into existing code that uses {{AbortSignal|AbortSignals}}. <dl class="domintro non-normative"> <dt><code>result = scheduler . {{Scheduler/postTask()|postTask}}( |callback|, |options| )</code></dt> <dd> - <p>Returns a promise that is fulfilled with the return value of |callback|, - or rejected with the {{AbortSignal}}'s [=AbortSignal/abort reason=] if the - task is aborted. If |callback| throws an error during execution, the promise - returned by {{Scheduler/postTask()}} will be rejected with that error. + <p>Returns a promise that is fulfilled with the return value of |callback|, or rejected with the + {{AbortSignal}}'s [=AbortSignal/abort reason=] if the task is aborted. If |callback| throws an + error during execution, the promise returned by {{Scheduler/postTask()}} will be rejected with + that error. - <p>The task's {{TaskPriority|priority}} is determined by the combination of - |option|'s {{SchedulerPostTaskOptions/priority}} and - {{SchedulerPostTaskOptions/signal}}: + <p>The task's {{TaskPriority|priority}} is determined by the combination of |option|'s + {{SchedulerPostTaskOptions/priority}} and {{SchedulerPostTaskOptions/signal}}: <ul> - <li>If |option|'s {{SchedulerPostTaskOptions/priority}} is specified, then - that {{TaskPriority}} will be used to schedule the task, and the task's - priority is immutable.</li> + <li><p>If |option|'s {{SchedulerPostTaskOptions/priority}} is specified, then that + {{TaskPriority}} will be used to schedule the task, and the task's priority is immutable. - <li>Otherwise, if |option|'s {{SchedulerPostTaskOptions/signal}} is - specified and is a {{TaskSignal}} object, then the task's priority is - determined by |option|'s {{SchedulerPostTaskOptions/signal}}'s - [=TaskSignal/priority=]. In this case the task's priority is *dynamic*, - and can be changed by calling {{TaskController/setPriority()|controller.setPriority()}} - for the associated {{TaskController}}.</li> + <li><p>Otherwise, if |option|'s {{SchedulerPostTaskOptions/signal}} is specified and is a + {{TaskSignal}} object, then the task's priority is determined by |option|'s + {{SchedulerPostTaskOptions/signal}}'s [=TaskSignal/priority=]. In this case the task's + priority is *dynamic*, and can be changed by calling + {{TaskController/setPriority()|controller.setPriority()}} for the associated + {{TaskController}}. - <li>Otherwise, the task's priority defaults to "{{TaskPriority/user-visible}}".</li> - </ul></p> + <li><p>Otherwise, the task's priority defaults to "{{TaskPriority/user-visible}}". + </ul> <p>If |option|'s {{SchedulerPostTaskOptions/signal}} is specified, then the - {{SchedulerPostTaskOptions/signal}} is used by the {{Scheduler}} to - determine if the task is aborted. + {{SchedulerPostTaskOptions/signal}} is used by the {{Scheduler}} to determine if the task is + aborted. - <p>If |option|'s {{SchedulerPostTaskOptions/delay}} is specified and greater - than 0, then the execution of the task will be delayed for at least - {{SchedulerPostTaskOptions/delay}} milliseconds. + <p>If |option|'s {{SchedulerPostTaskOptions/delay}} is specified and greater than 0, then the + execution of the task will be delayed for at least {{SchedulerPostTaskOptions/delay}} + milliseconds. </dd> </dl> A {{Scheduler}} object has an associated <dfn for="Scheduler">static priority task queue map</dfn>, -which is a [=map=] from {{TaskPriority}} to [=scheduler task queue=]. This map -is initialized to a new empty [=map=]. +which is a [=map=] from {{TaskPriority}} to [=scheduler task queue=]. This map is initialized to a +new empty [=map=]. A {{Scheduler}} object has an associated <dfn for="Scheduler">dynamic priority task queue map</dfn>, -which is a [=map=] from {{TaskSignal}} to [=scheduler task queue=]. This map is -initialized to a new empty [=map=]. - -Note: We implement *dynamic prioritization* by enqueuing tasks associated with -a specific {{TaskSignal}} into the same [=scheduler task queue=], and changing -that queue's priority in response to `prioritychange` events. The -[=Scheduler/dynamic priority task queue map=] holds the -[=scheduler task queues=] whose priorities can change, and the map key is the -{{TaskSignal}} which all tasks in the queue are associated with. +which is a [=map=] from {{TaskSignal}} to [=scheduler task queue=]. This map is initialized to a new +empty [=map=]. + +Note: We implement *dynamic prioritization* by enqueuing tasks associated with a specific +{{TaskSignal}} into the same [=scheduler task queue=], and changing that queue's priority in +response to `prioritychange` events. The [=Scheduler/dynamic priority task queue map=] holds the +[=scheduler task queues=] whose priorities can change, and the map key is the {{TaskSignal}} which +all tasks in the queue are associated with. <br/></br> -The values of the [=Scheduler/static priority task queue map=] are -[=scheduler task queues=] whose priorities do not change. Tasks with *static -priorities* — those that were scheduled with an explicit -{{SchedulerPostTaskOptions/priority}} option or a -{{SchedulerPostTaskOptions/signal}} option that is null or is an {{AbortSignal}} -— are placed in these queues, based on {{TaskPriority}}, which is the -key for the map. +The values of the [=Scheduler/static priority task queue map=] are [=scheduler task queues=] whose +priorities do not change. Tasks with *static priorities* — those that were scheduled with an +explicit {{SchedulerPostTaskOptions/priority}} option or a {{SchedulerPostTaskOptions/signal}} +option that is null or is an {{AbortSignal}} — are placed in these queues, based on +{{TaskPriority}}, which is the key for the map. <br/><br/> -An alternative, and logicially equivalent implementation, would be to maintain a -single per-{{TaskPriority}} [=scheduler task queue=], and move tasks between -[=scheduler task queues=] in response to a {{TaskSignal}}'s -[=TaskSignal/priority=] changing, inserting based on -[=scheduler task/enqueue order=]. This approach would simplify -[=selecting the task queue of the next scheduler task=], but make priority -changes more complex. - - -A {{Scheduler}} object has a numeric <dfn for="Scheduler">next enqueue order</dfn> -which is initialized to 1. - -Note: The [=Scheduler/next enqueue order=] is a strictly increasing number that -is used to determine task execution order across [=scheduler task queues=] of the -same {{TaskPriority}} within the same {{Scheduler}}. A logically equivalent -alternative would be to place the [=Scheduler/next enqueue order=] on the -[=event loop=], since the only requirements are that the number be strictly +An alternative, and logicially equivalent implementation, would be to maintain a single +per-{{TaskPriority}} [=scheduler task queue=], and move tasks between [=scheduler task queues=] in +response to a {{TaskSignal}}'s [=TaskSignal/priority=] changing, inserting based on [=scheduler +task/enqueue order=]. This approach would simplify [=selecting the task queue of the next scheduler +task=], but make priority changes more complex. + + +A {{Scheduler}} object has a numeric <dfn for="Scheduler">next enqueue order</dfn> which is +initialized to 1. + +Note: The [=Scheduler/next enqueue order=] is a strictly increasing number that is used to determine +task execution order across [=scheduler task queues=] of the same {{TaskPriority}} within the same +{{Scheduler}}. A logically equivalent alternative would be to place the [=Scheduler/next enqueue +order=] on the [=event loop=], since the only requirements are that the number be strictly increasing and not be repeated within a {{Scheduler}}. Issue: Would it be simpler to just use a timestamp here? The <dfn method for=Scheduler title="postTask(callback, options)">postTask(|callback|, |options|)</dfn> -method steps are to return the result of [=scheduling a postTask task=] for [=this=] -given |callback| and |options|. +method steps are to return the result of [=scheduling a postTask task=] for [=this=] given +|callback| and |options|. -Definitions {#sec-scheduling-tasks-definitions} ---------------------- +## Definitions ## {#sec-scheduling-tasks-definitions} A <dfn>scheduler task</dfn> is a [=/task=] with an additional numeric <dfn for="scheduler task">enqueue order</dfn> [=struct/item=], initially set to 0. -A [=scheduler task=] |t1| is <dfn for="scheduler task">older than</dfn> -[=scheduler task=] |t2| if |t1|'s [=scheduler task/enqueue order=] less than |t2|'s -[=scheduler task/enqueue order=]. - -<br/> - The following [=task sources=] are defined as <dfn>scheduler task sources</dfn>, and must only be used for [=scheduler tasks=]. @@ -181,9 +160,16 @@ A <dfn>scheduler task queue</dfn> is a [=struct=] with the following [=struct/it : <dfn for="scheduler task queue">tasks</dfn> :: A [=set=] of [=scheduler tasks=]. + +## Processing Model ## {#sec-scheduling-tasks-processing-model} + +<div algorithm> + A [=scheduler task=] |t1| is <dfn for="scheduler task">older than</dfn> [=scheduler task=] |t2| if + |t1|'s [=scheduler task/enqueue order=] less than |t2|'s [=scheduler task/enqueue order=]. +</div> + <div algorithm> - To <dfn lt="create a scheduler task queue|creating a scheduler task queue">create a scheduler task queue</dfn> - with {{TaskPriority}} |priority|: + To <dfn>create a scheduler task queue</dfn> with {{TaskPriority}} |priority|: 1. Let |queue| be a new [=scheduler task queue=]. 1. Set |queue|'s [=scheduler task queue/priority=] to |priority|. @@ -191,173 +177,153 @@ A <dfn>scheduler task queue</dfn> is a [=struct=] with the following [=struct/it 1. Return |queue|. </div> -A [=scheduler task queue=] |queue|'s <dfn for="scheduler task queue">first runnable task</dfn> -is the first [=scheduler task=] in |queue|'s [=scheduler task queue/tasks=] that is -[=task/runnable=]. - -Processing Model {#sec-scheduling-tasks-processing-model} ---------------------- +<div algorithm> + A [=scheduler task queue=] |queue|'s <dfn for="scheduler task queue">first runnable task</dfn> is + the first [=scheduler task=] in |queue|'s [=scheduler task queue/tasks=] that is + [=task/runnable=]. +</div> ### Queueing and Removing Scheduler Tasks ### {#sec-queuing-scheduler-tasks} -<div algorithm="queue a scheduler task"> - To <dfn lt="queue a scheduler task|queuing a scheduler task">queue a scheduler task</dfn> - on a [=scheduler task queue=] |queue|, which performs a series of steps |steps|, - given a numeric |enqueue order|, a [=task source=] |source|, and a [=document=] |document|: +<div algorithm> + To <dfn>queue a scheduler task</dfn> on a [=scheduler task queue=] |queue|, which performs a + series of steps |steps|, given a numeric |enqueue order|, a [=task source=] |source|, and a + [=document=] |document|: 1. Let |task| be a new [=scheduler task=]. 1. Set |task|'s [=scheduler task/enqueue order=] to |enqueue order|. 1. Set |task|'s <a attribute for="task">steps</a> to |steps|. 1. Set |task|'s <a attribute for="task">source</a> to |source|. 1. Set |task|'s <a attribute for="task">document</a> to |document|. - 1. Set |task|'s <a attribute for="task">script evaluation environment settings - object set</a> to a new empty [=set=]. + 1. Set |task|'s <a attribute for="task">script evaluation environment settings object set</a> to a + new empty [=set=]. 1. [=set/Append=] |task| to |queue|'s [=scheduler task queue/tasks=]. 1. Return |task|. - Issue: We should consider refactoring the HTML spec to add a constructor for - [=/task=]. One problem is we need the new task to be a [=scheduler task=] - rather than a [=/task=]. + Issue: We should consider refactoring the HTML spec to add a constructor for [=/task=]. One + problem is we need the new task to be a [=scheduler task=] rather than a [=/task=]. </div> <div algorithm> - To <dfn for="scheduler task queue">remove</dfn> a [=scheduler task=] |task| from - [=scheduler task queue=] |queue|, [=set/remove=] |task| from |queue|'s - [=scheduler task queue/tasks=]. + To <dfn for="scheduler task queue">remove</dfn> a [=scheduler task=] |task| from [=scheduler task + queue=] |queue|, [=set/remove=] |task| from |queue|'s [=scheduler task queue/tasks=]. </div> ### Scheduling Tasks ### {#sec-scheduler-alg-scheduling-tasks} -<div algorithm="schedule a postTask task"> - To <dfn lt="schedule a postTask task|scheduling a postTask task">schedule a postTask task</dfn> - for {{Scheduler}} |scheduler| given a {{SchedulerPostTaskCallback}} |callback| and - {{SchedulerPostTaskOptions}} |options|, run the following steps: +<div algorithm> + To <dfn>schedule a postTask task</dfn> for {{Scheduler}} |scheduler| given a + {{SchedulerPostTaskCallback}} |callback| and {{SchedulerPostTaskOptions}} |options|: 1. Let |result| be [=a new promise=]. 1. Let |signal| be |options|["{{SchedulerPostTaskOptions/signal}}"] if - |options|["{{SchedulerPostTaskOptions/signal}}"] [=map/exists=], or - otherwise null. - 1. If |signal| is not null and it is [=AbortSignal/aborted=], then - [=reject=] |result| with |signal|'s [=AbortSignal/abort reason=] and return - |result|. + |options|["{{SchedulerPostTaskOptions/signal}}"] [=map/exists=], or otherwise null. + 1. If |signal| is not null and it is [=AbortSignal/aborted=], then [=reject=] |result| with + |signal|'s [=AbortSignal/abort reason=] and return |result|. 1. Let |priority| be |options|["{{SchedulerPostTaskOptions/priority}}"] if - |options|["{{SchedulerPostTaskOptions/priority}}"] [=map/exists=], or - otherwise null. - 1. Let |queue| be the result of [=selecting the scheduler task queue=] for - |scheduler| given |signal| and |priority|. + |options|["{{SchedulerPostTaskOptions/priority}}"] [=map/exists=], or otherwise null. + 1. Let |queue| be the result of [=selecting the scheduler task queue=] for |scheduler| given + |signal| and |priority|. 1. Let |delay| be |options|["{{SchedulerPostTaskOptions/delay}}"]. - 1. If |delay| is greater than 0, then [=run steps after a timeout=] given - |scheduler|'s [=relevant global object=], "`scheduler-postTask`", - |delay|, and the following steps: - 1. [=Schedule a task to invoke a callback=] for |scheduler| given |queue|, - |signal|, |callback|, and |result|. - 1. Otherwise, [=schedule a task to invoke a callback=] for |scheduler| given - |queue|, |signal|, |callback|, and |result|. + 1. If |delay| is greater than 0, then [=run steps after a timeout=] given |scheduler|'s [=relevant + global object=], "`scheduler-postTask`", |delay|, and the following steps: + 1. [=Schedule a task to invoke a callback=] for |scheduler| given |queue|, |signal|, |callback|, + and |result|. + 1. Otherwise, [=schedule a task to invoke a callback=] for |scheduler| given |queue|, |signal|, + |callback|, and |result|. 1. Return |result|. </div> -Issue: [=Run steps after a timeout=] doesn't necessarily account for suspension; -see [whatwg/html#5925](https://github.com/whatwg/html/issues/5925). +Issue: [=Run steps after a timeout=] doesn't necessarily account for suspension; see +[whatwg/html#5925](https://github.com/whatwg/html/issues/5925). -<div algorithm="select the scheduler task queue"> - To <dfn lt="select the scheduler task queue|selecting the scheduler task queue">select the scheduler task queue</dfn> - for a {{Scheduler}} |scheduler| given an {{AbortSignal}} or null |signal|, and - a {{TaskPriority}} or null |priority|: +<div algorithm> + To <dfn>select the scheduler task queue</dfn> for a {{Scheduler}} |scheduler| given an + {{AbortSignal}} or null |signal|, and a {{TaskPriority}} or null |priority|: 1. If |priority| is null, |signal| is not null and [=implements=] the {{TaskSignal}} interface, and |signal| [=TaskSignal/has fixed priority=], then set |priority| to |signal|'s [=TaskSignal/priority=]. 1. If |priority| is null and |signal| is not null and [=implements=] the {{TaskSignal}} interface, then - 1. If |scheduler|'s [=Scheduler/dynamic priority task queue map=] does not - [=map/contain=] |signal|, then - 1. Let |queue| be the result of [=creating a scheduler task queue=] given - |signal|'s [=TaskSignal/priority=]. + 1. If |scheduler|'s [=Scheduler/dynamic priority task queue map=] does not [=map/contain=] + |signal|, then + 1. Let |queue| be the result of [=creating a scheduler task queue=] given |signal|'s + [=TaskSignal/priority=]. 1. Set [=Scheduler/dynamic priority task queue map=][|signal|] to |queue|. - 1. [=TaskSignal/Add a priority change algorithm=] to |signal| that - runs the following steps: - 1. Set |queue|'s [=scheduler task queue/priority=] to |signal|'s - {{TaskSignal/priority}}. + 1. [=TaskSignal/Add a priority change algorithm=] to |signal| that runs the following steps: + 1. Set |queue|'s [=scheduler task queue/priority=] to |signal|'s {{TaskSignal/priority}}. 1. Return [=Scheduler/dynamic priority task queue map=][|signal|]. 1. Otherwise |priority| is used to determine the task queue: 1. If |priority| is null, set |priority| to "{{TaskPriority/user-visible}}". - 1. If |scheduler|'s [=Scheduler/static priority task queue map=] does not - [=map/contain=] |priority|, then - 1. Let |queue| be the result of [=creating a scheduler task queue=] given - |priority|. + 1. If |scheduler|'s [=Scheduler/static priority task queue map=] does not [=map/contain=] + |priority|, then + 1. Let |queue| be the result of [=creating a scheduler task queue=] given |priority|. 1. Set [=Scheduler/static priority task queue map=][|priority|] to |queue|. 1. Return [=Scheduler/static priority task queue map=][|priority|]. </div> <div algorithm> - To <dfn>schedule a task to invoke a callback</dfn> for {{Scheduler}} - |scheduler| given a [=scheduler task queue=] |queue|, an {{AbortSignal}} or - null |signal|, a SchedulerPostTaskCallback |callback|, and a promise |result|: + To <dfn>schedule a task to invoke a callback</dfn> for {{Scheduler}} |scheduler| given a + [=scheduler task queue=] |queue|, an {{AbortSignal}} or null |signal|, a SchedulerPostTaskCallback + |callback|, and a promise |result|: 1. Let |global| be the [=relevant global object=] for |scheduler|. - 1. Let |document| be |global|'s <a attribute for="Window">associated `Document`</a> - if |global| is a {{Window}} object; otherwise null. + 1. Let |document| be |global|'s <a attribute for="Window">associated `Document`</a> if |global| is + a {{Window}} object; otherwise null. 1. Let |enqueue order| be |scheduler|'s [=Scheduler/next enqueue order=]. 1. Increment |scheduler|'s [=Scheduler/next enqueue order=] by 1. - 1. Let |task| be the result of [=queuing a scheduler task=] on |queue| given - |enqueue order|, [=the posted task task source=], and |document|, and that - performs the following steps: - 1. Let |callback result| be the result of [=invoking=] |callback|. If that - threw an exception, then [=reject=] |result| with that, otherwise resolve - |result| with |callback result|. - 1. If |signal| is not null, then [=AbortSignal/add|add the following=] abort - steps to it: + 1. Let |task| be the result of [=queuing a scheduler task=] on |queue| given |enqueue order|, + [=the posted task task source=], and |document|, and that performs the following steps: + 1. Let |callback result| be the result of [=invoking=] |callback|. If that threw an exception, + then [=reject=] |result| with that, otherwise resolve |result| with |callback result|. + 1. If |signal| is not null, then [=AbortSignal/add|add the following=] abort steps to it: 1. [=scheduler task queue/Remove=] |task| from |queue|. 1. [=Reject=] |result| with |signal|'s [=AbortSignal/abort reason=]. - Issue: Because this algorithm can be called from [=in parallel=] steps, parts - of this and other algorithms are racy. Specifically, the - [=Scheduler/next enqueue order=] should be updated atomically, and accessing - the [=scheduler task queues=] should occur atomically. The latter also affects - the event loop task queues (see [this issue](https://github.com/whatwg/html/issues/6475)). + Issue: Because this algorithm can be called from [=in parallel=] steps, parts of this and other + algorithms are racy. Specifically, the [=Scheduler/next enqueue order=] should be updated + atomically, and accessing the [=scheduler task queues=] should occur atomically. The latter also + affects the event loop task queues (see [this issue](https://github.com/whatwg/html/issues/6475)). </div> ### Selecting the Next Task to Run ### {#sec-scheduler-alg-select-next-task} -<div algorithm="has a runnable task"> - A {{Scheduler}} |scheduler| <dfn lt="has a runnable task|have a runnable task">has a runnable task</dfn> - if the result of [=getting the runnable task queues=] for |scheduler| is non-[=list/empty=]. +<div algorithm> + A {{Scheduler}} |scheduler| <dfn lt="has a runnable task|have a runnable task">has a runnable + task</dfn> if the result of [=getting the runnable task queues=] for |scheduler| is + non-[=list/empty=]. </div> -<div algorithm="get the runnable task queues"> - To <dfn lt="get the runnable task queues|getting the runnable task queues">get the runnable task queues</dfn> - for a {{Scheduler}} |scheduler|, run the following steps: - - 1. Let |queues| be the result of [=map/get the values|getting the values=] of - |scheduler|'s [=Scheduler/static priority task queue map=]. - 1. [=list/Extend=] |queues| with the result of [=map/get the values|getting the values=] - of |scheduler|'s [=Scheduler/dynamic priority task queue map=]. - 1. [=list/Remove=] from |queues| any |queue| such that |queue|'s [=scheduler task queue/tasks=] - do not contain a [=task/runnable=] [=scheduler task=]. +<div algorithm> + To <dfn>get the runnable task queues</dfn> for a {{Scheduler}} |scheduler|: + + 1. Let |queues| be the result of [=map/get the values|getting the values=] of |scheduler|'s + [=Scheduler/static priority task queue map=]. + 1. [=list/Extend=] |queues| with the result of [=map/get the values|getting the values=] of + |scheduler|'s [=Scheduler/dynamic priority task queue map=]. + 1. [=list/Remove=] from |queues| any |queue| such that |queue|'s [=scheduler task queue/tasks=] do + not contain a [=task/runnable=] [=scheduler task=]. 1. Return |queues|. </div> <div algorithm> - The result of <dfn>selecting the task queue of the next scheduler task</dfn> - for {{Scheduler}} |scheduler| is a [=set=] of [=scheduler tasks=] as defined - by the following steps: + The result of <dfn>selecting the task queue of the next scheduler task</dfn> for {{Scheduler}} + |scheduler| is a [=set=] of [=scheduler tasks=] as defined by the following steps: 1. Let |queues| be the result of [=getting the runnable task queues=] for |scheduler|. 1. If |queues| is [=list/empty=] return null. 1. [=set/Remove=] from |queues| any |queue| such that |queue|'s [=scheduler task queue/priority=] is [=TaskPriority/less than=] any other [=set/item=] of |queues|. - 1. Let |queue| be the [=scheduler task queue=] in |queues| whose - [=scheduler task queue/first runnable task=] is the - [=scheduler task/older than|oldest=]. + 1. Let |queue| be the [=scheduler task queue=] in |queues| whose [=scheduler task queue/first + runnable task=] is the [=scheduler task/older than|oldest=]. <br/><span class=note>Two tasks cannot have the same age since [=scheduler task/enqueue order=] is unique.</span> 1. Return |queue|'s [=scheduler task queue/tasks=]. - Note: The next task to run is the oldest, highest priority [=task/runnable=] - [=scheduler task=]. + Note: The next task to run is the oldest, highest priority [=task/runnable=] [=scheduler task=]. </div> -Examples {#sec-scheduling-tasks-examples} ---------------------- +## Examples ## {#sec-scheduling-tasks-examples} **TODO**(shaseley): Add examples. diff --git a/spec/security.md b/spec/security.md index 8d20ab9..23d3c54 100644 --- a/spec/security.md +++ b/spec/security.md @@ -1,5 +1,4 @@ -Security Considerations {#sec-security} -===================== +# Security Considerations # {#sec-security} <div class="non-normative"> *This section is non-normative.* @@ -9,8 +8,7 @@ whether or not any information is potentially leaked between origins by timing-based side-channel attacks. </div> -`postTask` as a High-Resolution Timing Source {#sec-security-high-res-timer} ---------------------- +## `postTask` as a High-Resolution Timing Source ## {#sec-security-high-res-timer} <div class="non-normative"> This API cannot be used as a high-resolution timing source. Like @@ -22,8 +20,7 @@ their delay expires and not run instantly, the precision available to callers is further reduced. </div> -Monitoring Another Origin's Tasks {#sec-security-monitoring-tasks} ---------------------- +## Monitoring Another Origin's Tasks ## {#sec-security-monitoring-tasks} <div class="non-normative"> The second consideration is whether {{Scheduler/postTask()}} leaks any