Skip to content

Commit

Permalink
coro: refactor quite a bit
Browse files Browse the repository at this point in the history
Wakeup and yields must be matched with expected state.
Reaps and deinits should now be memory safe.
And some other improvements.
  • Loading branch information
Cloudef committed Jun 18, 2024
1 parent 6894083 commit 36849f1
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 106 deletions.
2 changes: 1 addition & 1 deletion docs/pages/aio-immediate.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ try aio.multi(.{
```

The `.link_next` field of operation can be used to link the operation to the next operation.
When linking operations, the next operation won't start until the previous operation is complete.
When linking operations, the next operation won't start until this operation is complete.

#### Using batch

Expand Down
6 changes: 3 additions & 3 deletions docs/pages/aio-operations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ counter: Counter = .nop,
link_next: bool = false,
```

If `out_id` is set, the id of the operation will be written into that address.
If `out_id` is set, the id of the operation will be stored into that address.
The `id` can then be used in future operations to refer to this operation.
If `out_error` is set, the error of the operation will be written into that address, in case the operation failed.
If there was no failure a `error.Success` will be store in that address.
If `out_error` is set, the error of the operation will be stored into that address, in case the operation failed.
If there was no failure a `error.Success` will be stored in that address.
`counter` can be used to set either decreasing or increasing counter.
When operation completes it will either decrease or increase the `u16` stored at the address.
`link_next` can be used to link the next operation into this operation.
Expand Down
33 changes: 28 additions & 5 deletions docs/pages/coro-context-switches.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,40 @@ This part of the API is likely to change.
:::


## Context switches
## Paired context switches

To yield running task to the caller use the following.
The function takes a enum value as a argument representing the yield state of the task.

```zig
coro.yield();
coro.yield(SomeEnum.value);
```

To continue running the task from where it left, use the following.
This can also be used to cancel any IO operations.
To continue running the task from where it left, you need to issue the same enum value to the following function.
If the task currently isn't being yielded in the supplied state, the call is no-op.

```zig
coro.wakeup();
coro.wakeupFromState(task, SomeEnum.value);
```

This is the preferred way to handle the control flow between tasks.

## Canceling IO

While it's possible to cancel IO by using the `aio.Cancel` operations. It is also possible to cancel
all IO operations currently blocking as task by doing the following.
If the task currently isn't being yielded by IO then the call is no-op.

```zig
coro.wakeupFromIo(task);
```

## Unpaired wakeup

Sometimes it's useful to be able to wakeup the task from any yielding state.

```zig
coro.wakeup(task);
```

In this case the task will wake up no matter what its yielding state is currently.
3 changes: 2 additions & 1 deletion docs/pages/coro-io.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ Below is a full example of simple server / client program using the `coro` api.
Use `aio.Cancel` operation to cancel the currently running operations in a task.
The `out_error` of such operation will then be set as `error.OperationCanceled`.

Alternatively it's possible to call `scheduler.wakeup(task);` which also cancels all currently running io on that task.
Alternatively it's possible to call `scheduler.wakeup(task);` or `scheduler.wakeupFromIo(task)`
which also cancels all currently running io on that task.
2 changes: 2 additions & 0 deletions docs/pages/coro-scheduler.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@ var task = try scheduler.spawn(entrypoint, .{ 1, "args" }, .{});
### Reaping tasks

Following removes a task, freeing its memory and canceling all running IO operations for that task.
The reap may be delayed in case the task is currently doing IO, the IO operations will be actively canceled.

```zig
scheduler.reap(task);
```

Alternatively reap all the tasks using the following.
The reap may be delayed in case the tasks are currently doing IO, the IO operations will be actively canceled.

```zig
scheduler.reapAll();
Expand Down
8 changes: 6 additions & 2 deletions src/aio.zig
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ pub const Dynamic = struct {
const ti = @typeInfo(@TypeOf(operations));
if (comptime ti == .Struct and ti.Struct.is_tuple) {
return self.io.queue(operations.len, &struct { ops: @TypeOf(operations) }{ .ops = operations });
} else if (comptime ti == .Array) {
return self.io.queue(operations.len, &struct { ops: @TypeOf(operations) }{ .ops = operations });
} else {
return self.io.queue(1, &struct { ops: @TypeOf(.{operations}) }{ .ops = .{operations} });
}
Expand All @@ -78,8 +80,10 @@ pub inline fn batch(operations: anytype) ImmediateError!CompletionResult {
const ti = @typeInfo(@TypeOf(operations));
if (comptime ti == .Struct and ti.Struct.is_tuple) {
return IO.immediate(operations.len, &struct { ops: @TypeOf(operations) }{ .ops = operations });
} else if (comptime ti == .Array) {
return IO.immediate(operations.len, &struct { ops: @TypeOf(operations) }{ .ops = operations });
} else {
@compileError("expected a tuple of operations");
@compileError("expected a tuple or array of operations");
}
}

Expand All @@ -93,7 +97,7 @@ pub inline fn multi(operations: anytype) (ImmediateError || error{SomeOperationF
/// Completes a single operation immediately, blocks until complete
pub inline fn single(operation: anytype) (ImmediateError || OperationError)!void {
var op: @TypeOf(operation) = operation;
var err: @TypeOf(op.out_error.?.*) = error.Success;
var err: @TypeOf(operation).Error = error.Success;
op.out_error = &err;
_ = try batch(.{op});
if (err != error.Success) return err;
Expand Down
Loading

0 comments on commit 36849f1

Please sign in to comment.