| author | |
| committer | |
| log | 1f1bee62e854ec9c75e8b49072d0c403c7f0a100 |
| tree | 6ecaed99e158be08245ddd275fa24e9392e6d3e6 |
| parent | b52057f05218d13901fe576bf2d472b657e58e6f |
During context switch in Io.Uring `fiber.contextSwitch` functions leaves
`*fiber.Switch` (contexts field from SwitchMessage) in the `rpi` register.
```Zig
inline fn contextSwitch(message: *const SwitchMessage) *const SwitchMessage {
return @fieldParentPtr("contexts", Io.fiber.contextSwitch(&message.contexts));
}
```
```asm
.x86_64 => asm volatile (
\\ movq 0(%%rsi), %%rax
\\ movq 8(%%rsi), %%rcx
\\ leaq 0f(%%rip), %%rdx
\\ movq %%rsp, 0(%%rax)
\\ movq %%rbp, 8(%%rax)
\\ movq %%rdx, 16(%%rax)
\\ movq 0(%%rcx), %%rsp
\\ movq 8(%%rcx), %%rbp
\\ jmpq *16(%%rcx)
\\0:
: [received_message] "={rsi}" (-> *const Switch),
: [message_to_send] "{rsi}" (s),
```
That becomes second argument to the `AscynClosure.call` but there it is
interpreted as `*SwitchMessage` which works because both points to the same
address (contexts is first field).
```Zig
fn call(
closure: *AsyncClosure,
message: *const SwitchMessage,
) callconv(.withStackAlign(.c, @alignOf(AsyncClosure))) noreturn {
```
SwitchMessage is not packed or external struct allowing reorder, padding.
Reordering fields breaks expectation that `*fiber.Switch` and `*SwitchMessage`
are the same pointers.1 files changed, 6 insertions(+), 3 deletions(-)
lib/std/Io/Uring.zig+6-3| ... | ... | @@ -1135,8 +1135,9 @@ fn mainIdleEntry() callconv(.naked) void { |
| 1135 | 1135 | |
| 1136 | 1136 | fn mainIdle( |
| 1137 | 1137 | ev: *Evented, |
| 1138 | message: *const SwitchMessage, | |
| 1138 | contexts: *const Io.fiber.Switch, | |
| 1139 | 1139 | ) callconv(.withStackAlign(.c, @max(@alignOf(Thread), @alignOf(Io.fiber.Context)))) noreturn { |
| 1140 | const message: *const SwitchMessage = @fieldParentPtr("contexts", contexts); | |
| 1140 | 1141 | message.handle(ev); |
| 1141 | 1142 | ev.idle(&ev.threads.allocated[0]); |
| 1142 | 1143 | ev.yield(@ptrCast(&ev.main_fiber_buffer), .nothing); |
| ... | ... | @@ -1414,8 +1415,9 @@ const AsyncClosure = struct { |
| 1414 | 1415 | |
| 1415 | 1416 | fn call( |
| 1416 | 1417 | closure: *AsyncClosure, |
| 1417 | message: *const SwitchMessage, | |
| 1418 | contexts: *const Io.fiber.Switch, | |
| 1418 | 1419 | ) callconv(.withStackAlign(.c, @alignOf(AsyncClosure))) noreturn { |
| 1420 | const message: *const SwitchMessage = @fieldParentPtr("contexts", contexts); | |
| 1419 | 1421 | const ev = closure.evented; |
| 1420 | 1422 | const fiber = closure.fiber; |
| 1421 | 1423 | message.handle(ev); |
| ... | ... | @@ -1779,8 +1781,9 @@ const Group = struct { |
| 1779 | 1781 | |
| 1780 | 1782 | fn call( |
| 1781 | 1783 | closure: *Group.AsyncClosure, |
| 1782 | message: *const SwitchMessage, | |
| 1784 | contexts: *const Io.fiber.Switch, | |
| 1783 | 1785 | ) callconv(.withStackAlign(.c, @alignOf(Group.AsyncClosure))) noreturn { |
| 1786 | const message: *const SwitchMessage = @fieldParentPtr("contexts", contexts); | |
| 1784 | 1787 | const ev = closure.evented; |
| 1785 | 1788 | const fiber = closure.fiber; |
| 1786 | 1789 | message.handle(ev); |