Skip to content

CABI: move the call state out of the event-code enum and into the payload #500

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

Merged
merged 1 commit into from
Apr 14, 2025
Merged
Show file tree
Hide file tree
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
32 changes: 15 additions & 17 deletions design/mvp/CanonicalABI.md
Original file line number Diff line number Diff line change
Expand Up @@ -813,20 +813,13 @@ to be interpreted based on the `EventCode`. The meaning of the different
code that produces the events (specifically, in `subtask_event` and
`copy_event`).
```python
class CallState(IntEnum):
STARTING = 1
STARTED = 2
RETURNED = 3

class EventCode(IntEnum):
NONE = 0
CALL_STARTING = CallState.STARTING
CALL_STARTED = CallState.STARTED
CALL_RETURNED = CallState.RETURNED
STREAM_READ = 5
STREAM_WRITE = 6
FUTURE_READ = 7
FUTURE_WRITE = 8
SUBTASK = 1
STREAM_READ = 2
STREAM_WRITE = 3
FUTURE_READ = 4
FUTURE_WRITE = 5

EventTuple = tuple[EventCode, int, int]
```
Expand Down Expand Up @@ -966,6 +959,11 @@ only manages a few fields of state that are relevant to the caller. As with
`Task`, this section will introduce `Subtask` incrementally, starting with its
fields and initialization:
```python
class CallState(IntEnum):
STARTING = 0
STARTED = 1
RETURNED = 2

class Subtask(Waitable):
state: CallState
lenders: list[ResourceHandle]
Expand All @@ -978,10 +976,10 @@ class Subtask(Waitable):
self.finished = False
self.supertask = None
```
The `state` field of `Subtask` holds a `CallState` enum value (defined above as
part of the definition of `EventCode`) that describes the callee's current
state along the linear progression from [`STARTING`](Async.md#backpressure) to
`STARTED` to [`RETURNED`](Async.md#returning).
The `state` field of `Subtask` holds a `CallState` enum value that describes
the callee's current state along the linear progression from
[`STARTING`](Async.md#backpressure) to `STARTED` to
[`RETURNED`](Async.md#returning).

Although `Subtask` derives `Waitable`, `__init__` does not initialize the
`Waitable` base object. Instead, the `Waitable` base is only initialized when
Expand Down Expand Up @@ -2993,7 +2991,7 @@ immediately return control flow back to the `async` caller if `callee` blocks:
def subtask_event():
if subtask.state == CallState.RETURNED:
subtask.finish()
return (EventCode(subtask.state), subtaski, 0)
return (EventCode.SUBTASK, subtaski, subtask.state)
subtask.set_event(subtask_event)
assert(0 < subtaski <= Table.MAX_LENGTH < 2**28)
assert(0 <= int(subtask.state) < 2**4)
Expand Down
4 changes: 1 addition & 3 deletions design/mvp/Explainer.md
Original file line number Diff line number Diff line change
Expand Up @@ -1641,9 +1641,7 @@ record event {
}
enum event-code {
none,
call-starting,
call-started,
call-returned,
subtask,
stream-read,
stream-write,
future-read,
Expand Down
24 changes: 11 additions & 13 deletions design/mvp/canonical-abi/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,20 +506,13 @@ def exit(self):

#### Waitable State

class CallState(IntEnum):
STARTING = 1
STARTED = 2
RETURNED = 3

class EventCode(IntEnum):
NONE = 0
CALL_STARTING = CallState.STARTING
CALL_STARTED = CallState.STARTED
CALL_RETURNED = CallState.RETURNED
STREAM_READ = 5
STREAM_WRITE = 6
FUTURE_READ = 7
FUTURE_WRITE = 8
SUBTASK = 1
STREAM_READ = 2
STREAM_WRITE = 3
FUTURE_READ = 4
FUTURE_WRITE = 5

EventTuple = tuple[EventCode, int, int]

Expand Down Expand Up @@ -600,6 +593,11 @@ def drop(self):

#### Subtask State

class CallState(IntEnum):
STARTING = 0
STARTED = 1
RETURNED = 2

class Subtask(Waitable):
state: CallState
lenders: list[ResourceHandle]
Expand Down Expand Up @@ -1841,7 +1839,7 @@ def on_progress():
def subtask_event():
if subtask.state == CallState.RETURNED:
subtask.finish()
return (EventCode(subtask.state), subtaski, 0)
return (EventCode.SUBTASK, subtaski, subtask.state)
subtask.set_event(subtask_event)
assert(0 < subtaski <= Table.MAX_LENGTH < 2**28)
assert(0 <= int(subtask.state) < 2**4)
Expand Down
38 changes: 24 additions & 14 deletions design/mvp/canonical-abi/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -583,19 +583,22 @@ async def consumer(task, args):

waitretp = consumer_heap.realloc(0, 0, 8, 4)
[event] = await canon_waitable_set_wait(False, consumer_heap.memory, task, seti, waitretp)
assert(event == EventCode.CALL_RETURNED)
assert(event == EventCode.SUBTASK)
assert(consumer_heap.memory[waitretp] == subi1)
assert(consumer_heap.memory[waitretp+4] == CallState.RETURNED)
[] = await canon_subtask_drop(task, subi1)

[event] = await canon_waitable_set_wait(True, consumer_heap.memory, task, seti, waitretp)
assert(event == EventCode.CALL_STARTED)
assert(event == EventCode.SUBTASK)
assert(consumer_heap.memory[waitretp] == subi2)
assert(consumer_heap.memory[waitretp+4] == CallState.STARTED)
assert(consumer_heap.memory[retp] == 13)
fut2.set_result(None)

[event] = await canon_waitable_set_wait(False, consumer_heap.memory, task, seti, waitretp)
assert(event == EventCode.CALL_RETURNED)
assert(event == EventCode.SUBTASK)
assert(consumer_heap.memory[waitretp] == subi2)
assert(consumer_heap.memory[waitretp+4] == CallState.RETURNED)
assert(consumer_heap.memory[retp] == 44)
[] = await canon_subtask_drop(task, subi2)
fut3.set_result(None)
Expand Down Expand Up @@ -623,8 +626,9 @@ async def dtor(task, args):

[] = await canon_waitable_join(task, dtorsubi, seti)
[event] = await canon_waitable_set_wait(False, consumer_heap.memory, task, seti, waitretp)
assert(event == CallState.RETURNED)
assert(event == EventCode.SUBTASK)
assert(consumer_heap.memory[waitretp] == dtorsubi)
assert(consumer_heap.memory[waitretp+4] == CallState.RETURNED)
assert(dtor_value == 50)
[] = await canon_subtask_drop(task, dtorsubi)
[] = await canon_waitable_set_drop(task, seti)
Expand Down Expand Up @@ -695,9 +699,9 @@ async def callback(task, args):
[ctx] = await canon_context_get('i32', 0, task)
match ctx:
case 42:
assert(args[0] == EventCode.CALL_RETURNED)
assert(args[0] == EventCode.SUBTASK)
assert(args[1] == 1)
assert(args[2] == 0)
assert(args[2] == CallState.RETURNED)
await canon_subtask_drop(task, 1)
[] = await canon_context_set('i32', 0, task, 52)
return [definitions.CallbackCode.YIELD]
Expand All @@ -709,9 +713,9 @@ async def callback(task, args):
[] = await canon_context_set('i32', 0, task, 62)
return [definitions.CallbackCode.WAIT]
case 62:
assert(args[0] == EventCode.CALL_RETURNED)
assert(args[0] == EventCode.SUBTASK)
assert(args[1] == 2)
assert(args[2] == 0)
assert(args[2] == CallState.RETURNED)
await canon_subtask_drop(task, 2)
[] = await canon_task_return(task, [U32Type()], opts, [83])
return [definitions.CallbackCode.EXIT]
Expand Down Expand Up @@ -786,8 +790,9 @@ async def consumer(task, args):

retp = consumer_heap.realloc(0,0,8,4)
[event] = await canon_waitable_set_wait(False, consumer_heap.memory, task, seti, retp)
assert(event == EventCode.CALL_RETURNED)
assert(event == EventCode.SUBTASK)
assert(consumer_heap.memory[retp] == subi1)
assert(consumer_heap.memory[retp+4] == CallState.RETURNED)
await canon_subtask_drop(task, subi1)
assert(producer1_done == True)

Expand All @@ -796,8 +801,9 @@ async def consumer(task, args):
assert(producer2_done == True)

[event] = await canon_waitable_set_poll(False, consumer_heap.memory, task, seti, retp)
assert(event == EventCode.CALL_RETURNED)
assert(event == EventCode.SUBTASK)
assert(consumer_heap.memory[retp] == subi2)
assert(consumer_heap.memory[retp+4] == CallState.RETURNED)
await canon_subtask_drop(task, subi2)
assert(producer2_done == True)

Expand Down Expand Up @@ -873,13 +879,15 @@ async def consumer(task, args):

retp = consumer_heap.realloc(0,0,8,4)
[event] = await canon_waitable_set_wait(False, consumer_heap.memory, task, seti, retp)
assert(event == EventCode.CALL_RETURNED)
assert(event == EventCode.SUBTASK)
assert(consumer_heap.memory[retp] == subi1)
assert(consumer_heap.memory[retp+4] == CallState.RETURNED)
assert(producer1_done == True)

[event] = await canon_waitable_set_poll(False, consumer_heap.memory, task, seti, retp)
assert(event == EventCode.CALL_RETURNED)
assert(event == EventCode.SUBTASK)
assert(consumer_heap.memory[retp] == subi2)
assert(consumer_heap.memory[retp+4] == CallState.RETURNED)
assert(producer2_done == True)

await canon_subtask_drop(task, subi1)
Expand Down Expand Up @@ -941,14 +949,16 @@ async def core_func(task, args):

retp = lower_heap.realloc(0,0,8,4)
[event] = await canon_waitable_set_wait(False, lower_heap.memory, task, seti, retp)
assert(event == EventCode.CALL_RETURNED)
assert(event == EventCode.SUBTASK)
assert(lower_heap.memory[retp] == subi1)
assert(lower_heap.memory[retp+4] == CallState.RETURNED)

fut2.set_result(None)

[event] = await canon_waitable_set_wait(False, lower_heap.memory, task, seti, retp)
assert(event == EventCode.CALL_RETURNED)
assert(event == EventCode.SUBTASK)
assert(lower_heap.memory[retp] == subi2)
assert(lower_heap.memory[retp+4] == CallState.RETURNED)

await canon_subtask_drop(task, subi1)
await canon_subtask_drop(task, subi2)
Expand Down