Skip to content

Commit 4511b75

Browse files
committed
tidying text
1 parent 7722992 commit 4511b75

File tree

1 file changed

+69
-82
lines changed

1 file changed

+69
-82
lines changed

proposals/stack-switching/Explainer.md

Lines changed: 69 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,13 @@ design provides a form of *symmetric switching*.
8181

8282
We illustrate the proposed stack-switching mechanism using two
8383
examples: generators and task scheduling. The generators example uses
84-
asymmetric stack-switching and the task scheduling example uses
85-
symmetric stack-switching.
84+
asymmetric stack-switching. The task scheduling example has two
85+
variants: the first variant uses asymmetric stack-switching and the
86+
second variant uses symmetric stack-switching.
8687

8788
### Generators
8889

89-
The first example illustrates a generator-consumer pattern. Execution
90+
Our first example illustrates a generator-consumer pattern. Execution
9091
switches back and forth between a generator and a consumer execution
9192
stack. Whenever execution switches from the generator to the consumer
9293
the generator also passes a value to the consumer.
@@ -131,7 +132,7 @@ The overall module implementing our example has the following shape.
131132
;; corresponds to the generated values passed to consumer; no values passed
132133
;; back from generator to consumer.
133134
(tag $gen (param i32))
134-
135+
135136
;; Simple generator yielding values from 100 down to 1
136137
(func $generator ...)
137138
(elem declare func $generator)
@@ -259,7 +260,7 @@ The full definition of this module can be found
259260

260261
### Task scheduling
261262

262-
The second example demonstrates how to implement task scheduling with
263+
Our second example demonstrates how to implement task scheduling with
263264
the stack-switching instructions. Specifically, suppose we want to
264265
schedule a number of tasks, represented by functions `$task_0` to
265266
`$task_n`, to be executed concurrently. Scheduling is cooperative,
@@ -278,12 +279,10 @@ This approach is illustrated by the following skeleton code.
278279

279280
```wat
280281
(module $scheduler1
281-
282282
(type $ft (func))
283283
;; Continuation type of all tasks
284284
(type $ct (cont $ft))
285285
286-
287286
;; Tag used to yield execution in one task and resume another one.
288287
(tag $yield)
289288
@@ -444,16 +443,16 @@ continuation references. The task that we switched to is now
444443
responsible for enqueuing the previous continuation (i.e., the one
445444
received as a payload) in the task list.
446445

447-
As a minor complication, we need to encode the fact that the
448-
continuation switched to receives the current one as an argument in
449-
the type of the continuations handled by all scheduling logic. This
450-
means the type `$ct` must be recursive: a continuation of this type
446+
As a minor complication, we must encode the fact that the continuation
447+
switched to receives the current continuation as an argument in the
448+
type of the continuations handled by all scheduling logic. This means
449+
that the type `$ct` must be recursive: a continuation of this type
451450
takes a value of type `(ref null $ct)` as a parameter. In order to
452451
give the same type to continuations that have yielded execution (those
453452
created by `switch`) and those continuations that correspond to
454453
beginning the execution of a `$task_i` function (those created by
455454
`cont.new`), we add a `(ref null $ct)` parameter to all of the
456-
`$task_i` functions. Finally, observe that the event loop passes a
455+
`$task_i` functions. Finally, observe that the event loop passes a
457456
null continuation to any continuation it resumes, indicating to the
458457
resumed continuation that there is no previous continuation to enqueue
459458
in the task list.
@@ -686,34 +685,32 @@ suspended continuation will result in a trap.
686685

687686
## Further examples
688687

689-
We now provide examples using tags with result values as well as the
690-
instructions `cont.bind` and `resume.throw`.
691-
To this end, we revisit the examples from [Section
688+
We now illustrate the use of tags with result values and the
689+
instructions `cont.bind` and `resume.throw`, by adapting and extending
690+
the examples of [Section
692691
3](#introduction-to-continuation-based-stack-switching).
693692

694-
695-
696693
### Extending the generator
697694

698-
The `$generator` function introduced in [Section 3](#generators)
699-
produced the values 100 down to 1. It uses the tag `$gen`, defined as
695+
The `$generator` function in [Section 3](#generators)
696+
produces the values 100 down to 1. It uses the tag `$gen`, defined as
700697
`(tag $gen (param i32))`, to send values to the `$producer` function.
701698

702-
We now consider a situation where the producer wants to indicate to
703-
the generator to reset itself (i.e., start counting down from 100
704-
again). To this end, we allow the producer to pass a boolean flag to
705-
the generator when resuming a continuation. We use type `i32` for the
706-
flag, leading to the following definition of `$gen`:
699+
We now adapt the producer to indicate to the generator when to reset
700+
(i.e., start counting down from 100 again). The producer is adapted to
701+
pass a boolean flag to the generator when resuming a continuation.
702+
Correspondingly, the `$gen` tag is adapted to include an `i32` result
703+
type for the flag:
707704

708705
```wat
709706
(tag $gen (param i32) (result i32))
710707
```
711708

712709
In the generator, the instruction `(suspend $gen)` now has type `[i32]
713-
-> [i32]`: Its argument type represents the generated value (as in the
714-
original version of the example), the result type represents the flag
715-
obtained back from the producer. We change the generator to behave as
716-
follows, choosing between resetting or decrementing `$i`:
710+
-> [i32]`: the parameter type represents the generated value (as in
711+
the original version of the example) and the result type represents
712+
the flag obtained back from the producer. We adapt the generator to
713+
behave as follows, choosing between resetting or decrementing `$i`:
717714

718715
```wat
719716
(func $generator
@@ -734,17 +731,14 @@ follows, choosing between resetting or decrementing `$i`:
734731
)
735732
```
736733

737-
738-
In the producer, we then add some logic to pick the value of the flag,
739-
and pass it to the generator continuation on `resume`. However, this
740-
poses a challenge: The continuation created with `(cont.new $ct0
741-
(ref.func $generator)))` has the same type as before: A continuation
742-
type with no parameter or return types. In contrast, the type of the
743-
continuation received in a handler block for tag `$gen` is different
744-
from that type, due to the result type added to `$gen`: The result
745-
type of the tag becomes an additional parameter of the continuation
746-
received when handling that tag. This means that the producer now has
747-
to deal with two different continuation types:
734+
In the producer, we add logic to select the value of the flag, and
735+
pass it to the generator continuation on `resume`. However, this poses
736+
a challenge: the continuation created with `(cont.new $ct0 (ref.func
737+
$generator)))` has the same type as before: a continuation type with
738+
no parameter or return types. In contrast, the type of the
739+
continuation received in a handler block for tag `$gen` expects an
740+
`i32` due to the result type we added to `$gen`. This means that the
741+
producer must now manipulate two different continuation types:
748742

749743
```wat
750744
(type $ft0 (func))
@@ -759,12 +753,12 @@ to deal with two different continuation types:
759753
(type $ct1 (cont $ft1))
760754
```
761755

762-
To avoid making the producer function unnecessarily complicated, we
763-
want to make sure that there is only a single local variable that
764-
contains the next continuation to resume. Its type will be `(ref $ct0)`.
765-
We can then use `cont.bind` to turn the continuations received in the
766-
handler block from type `(ref $ct1)` into `(ref $ct0)` by binding the
767-
value of the flag to be passed.
756+
In order to avoid making the producer function unnecessarily
757+
complicated, we ensure that there is a single local variable that
758+
contains the next continuation to resume; its type will be `(ref
759+
$ct0)`. We can then use `cont.bind` to turn the continuations received
760+
in the handler block from type `(ref $ct1)` into `(ref $ct0)` by
761+
binding the value of the flag to be passed.
768762

769763
The overall function is then defined as follows:
770764

@@ -807,39 +801,34 @@ The overall function is then defined as follows:
807801
)
808802
```
809803

810-
811-
Here, we set the flag for resetting the generator exactly
812-
once, after it returned 42 values.
804+
Here, we set the flag for resetting the generator exactly once (after
805+
it has returned 42 values).
813806

814807
The full version of the extended generator example can be found
815808
[here](examples/generator-extended.wast).
816809

817-
### Canceling tasks
818-
819-
We now revisit the task scheduling example originally introduced
820-
in [Section 3](#task-scheduling).
821-
To yield execution, tasks either suspend to the scheduler running in
822-
the parent (first variant of example) or call a scheduling function
823-
that uses `switch` (second variant).
824-
810+
### Canceling tasks
825811

826-
We may want to adapt the example such that there is a limit on the
827-
number of tasks that can exist at the same time. Once that limit is
828-
reached, some task must be canceled before being able to schedule
829-
another one.
812+
The task scheduling examples from [Section 3](#task-scheduling) yield
813+
either by suspending to the scheduler running in the parent
814+
(asymmetric variant) or by calling a scheduling function that uses
815+
`switch` (symmetric variant).
830816

831-
We can implement this with a small addition to the previous example.
832-
Instead of adding tasks to be scheduled directly to a queue, we
833-
call the following function `$schedule_task` with any continuation that
834-
should be scheduled.
817+
Suppose we wish to adapt our schedulers to impose a limit on the
818+
number of tasks that can exist at the same time. A simple way to
819+
enforce the limit is to cancel the task at the head of the queue
820+
whenever an attempt is made to add a continuation to a full queue. We
821+
can implement this behaviour with a small modification to our previous
822+
schedulers. Instead of adding tasks to be scheduled directly to a
823+
queue, we call the following function.
835824

836825
```wat
837826
(func $schedule_task (param $c (ref null $ct))
838827
;; If the task queue is too long, cancel a task in the queue
839828
(if (i32.ge_s (call $task_queue-count) (global.get $concurrent_task_limit))
840829
(then
841830
(block $exc_handler
842-
(try_table (catch $abort $exc_handler)
831+
(try_table (catch $abort $exc_handler)
843832
(resume_throw $ct $abort (call $task_dequeue))
844833
)
845834
)
@@ -849,26 +838,24 @@ should be scheduled.
849838
)
850839
```
851840

852-
The function checks if the current number of elements in the queue has
853-
already reached the limit. If so, the function takes an existing
854-
continuation from the queue and calls `resume_throw` on it.
841+
The `$schedule_task` function checks if the current number of elements
842+
in the queue has already reached the limit. If so, the function takes
843+
an existing continuation from the queue and calls `resume_throw` on
844+
it.
855845

856-
Note that
857-
the `resume_throw` instruction is annotated with a newly defined tag, `$abort`.
858-
This tag denotes an exception that will be raised at the
846+
The `resume_throw` instruction is annotated with a newly defined tag,
847+
`$abort`. This tag denotes an exception that will be raised at the
859848
suspension point of the continuation. We then wrap the `resume_throw`
860849
instruction in a `try_table`, which installs an exception handler for
861-
`$abort`. This exception handler simply does nothing.
862-
Altogether this means that the exception raised at the suspension
863-
point cannot escape outside of the `$schedule_task` function, which
864-
then proceeds to enqueue the continuation given as a function
865-
argument.
866-
867-
Integrating the `$schedule_task` function above into the second
868-
variant of the task scheduling example (i.e., the variant using
869-
`switch`) can be found [here](examples/scheduler2-throw.wast).
870-
The changes to the first variant are analogous.
871-
850+
`$abort`. This exception handler simply swallows the exception, which
851+
means that the exception raised at the suspension point cannot escape
852+
the `$schedule_task` function. The old continuation is deallocated and
853+
the function proceeds to enqueue the new continuation.
854+
855+
The full version of the symmetric scheduling example using the
856+
`$schedule_task` function can be found
857+
[here](examples/scheduler2-throw.wast). The changes to the asymmetric
858+
scheduling example are analogous.
872859

873860
## Design considerations
874861

0 commit comments

Comments
 (0)