authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-23 03:38:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:51-07:00
log92b8378814697880ac3b5942abb47db4e5eeb958
tree919da25a6a27eed15187bfc0ca244289101a7daf
parentdd945bf1f8963452f5acf448dd26c73d2d7b29f6

concurrent and await


1 files changed, 58 insertions(+), 23 deletions(-)

lib/std/Io/Kqueue.zig+58-23
...@@ -172,9 +172,6 @@ pub fn init(k: *Kqueue, gpa: Allocator) !void {...@@ -172,9 +172,6 @@ pub fn init(k: *Kqueue, gpa: Allocator) !void {
172 .sp = @intFromPtr(idle_stack_end),172 .sp = @intFromPtr(idle_stack_end),
173 .fp = 0,173 .fp = 0,
174 .pc = @intFromPtr(&mainIdleEntry),174 .pc = @intFromPtr(&mainIdleEntry),
175 .x18 = asm (""
176 : [x18] "={x18}" (-> u64),
177 ),
178 },175 },
179 .x86_64 => .{176 .x86_64 => .{
180 .rsp = @intFromPtr(idle_stack_end - 1),177 .rsp = @intFromPtr(idle_stack_end - 1),
...@@ -548,7 +545,6 @@ const Context = switch (builtin.cpu.arch) {...@@ -548,7 +545,6 @@ const Context = switch (builtin.cpu.arch) {
548 sp: u64,545 sp: u64,
549 fp: u64,546 fp: u64,
550 pc: u64,547 pc: u64,
551 x18: u64,
552 },548 },
553 .x86_64 => extern struct {549 .x86_64 => extern struct {
554 rsp: u64,550 rsp: u64,
...@@ -562,12 +558,12 @@ inline fn contextSwitch(message: *const SwitchMessage) *const SwitchMessage {...@@ -562,12 +558,12 @@ inline fn contextSwitch(message: *const SwitchMessage) *const SwitchMessage {
562 return @fieldParentPtr("contexts", switch (builtin.cpu.arch) {558 return @fieldParentPtr("contexts", switch (builtin.cpu.arch) {
563 .aarch64 => asm volatile (559 .aarch64 => asm volatile (
564 \\ ldp x0, x2, [x1]560 \\ ldp x0, x2, [x1]
565 \\ ldp x3, x18, [x2, #16]561 \\ ldr x3, [x2, #16]
566 \\ mov x4, sp562 \\ mov x4, sp
567 \\ stp x4, fp, [x0]563 \\ stp x4, fp, [x0]
568 \\ adr x5, 0f564 \\ adr x5, 0f
569 \\ ldp x4, fp, [x2]565 \\ ldp x4, fp, [x2]
570 \\ stp x5, x18, [x0, #16]566 \\ str x5, [x0, #16]
571 \\ mov sp, x4567 \\ mov sp, x4
572 \\ br x3568 \\ br x3
573 \\0:569 \\0:
...@@ -761,12 +757,18 @@ fn fiberEntry() callconv(.naked) void {...@@ -761,12 +757,18 @@ fn fiberEntry() callconv(.naked) void {
761 :757 :
762 : [AsyncClosure_call] "X" (&AsyncClosure.call),758 : [AsyncClosure_call] "X" (&AsyncClosure.call),
763 ),759 ),
760 .aarch64 => asm volatile (
761 \\ mov x0, sp
762 \\ b %[AsyncClosure_call]
763 :
764 : [AsyncClosure_call] "X" (&AsyncClosure.call),
765 ),
764 else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)),766 else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)),
765 }767 }
766}768}
767769
768const AsyncClosure = struct {770const AsyncClosure = struct {
769 event_loop: *Kqueue,771 kqueue: *Kqueue,
770 fiber: *Fiber,772 fiber: *Fiber,
771 start: *const fn (context: *const anyopaque, result: *anyopaque) void,773 start: *const fn (context: *const anyopaque, result: *anyopaque) void,
772 result_align: Alignment,774 result_align: Alignment,
...@@ -777,7 +779,7 @@ const AsyncClosure = struct {...@@ -777,7 +779,7 @@ const AsyncClosure = struct {
777 }779 }
778780
779 fn call(closure: *AsyncClosure, message: *const SwitchMessage) callconv(.withStackAlign(.c, @alignOf(AsyncClosure))) noreturn {781 fn call(closure: *AsyncClosure, message: *const SwitchMessage) callconv(.withStackAlign(.c, @alignOf(AsyncClosure))) noreturn {
780 message.handle(closure.event_loop);782 message.handle(closure.kqueue);
781 const fiber = closure.fiber;783 const fiber = closure.fiber;
782 std.log.debug("{*} performing async", .{fiber});784 std.log.debug("{*} performing async", .{fiber});
783 closure.start(closure.contextPointer(), fiber.resultBytes(closure.result_align));785 closure.start(closure.contextPointer(), fiber.resultBytes(closure.result_align));
...@@ -787,7 +789,7 @@ const AsyncClosure = struct {...@@ -787,7 +789,7 @@ const AsyncClosure = struct {
787 if (@atomicRmw(bool, &closure.already_awaited, .Xchg, true, .acq_rel)) break :r null;789 if (@atomicRmw(bool, &closure.already_awaited, .Xchg, true, .acq_rel)) break :r null;
788 break :r a;790 break :r a;
789 };791 };
790 closure.event_loop.yield(ready_awaiter, .nothing);792 closure.kqueue.yield(ready_awaiter, .nothing);
791 unreachable; // switched to dead fiber793 unreachable; // switched to dead fiber
792 }794 }
793795
...@@ -881,19 +883,52 @@ fn async(...@@ -881,19 +883,52 @@ fn async(
881fn concurrent(883fn concurrent(
882 userdata: ?*anyopaque,884 userdata: ?*anyopaque,
883 result_len: usize,885 result_len: usize,
884 result_alignment: std.mem.Alignment,886 result_alignment: Alignment,
885 context: []const u8,887 context: []const u8,
886 context_alignment: std.mem.Alignment,888 context_alignment: Alignment,
887 start: *const fn (context: *const anyopaque, result: *anyopaque) void,889 start: *const fn (context: *const anyopaque, result: *anyopaque) void,
888) error{OutOfMemory}!*Io.AnyFuture {890) error{OutOfMemory}!*Io.AnyFuture {
889 const k: *Kqueue = @ptrCast(@alignCast(userdata));891 const k: *Kqueue = @ptrCast(@alignCast(userdata));
890 _ = k;892 assert(result_alignment.compare(.lte, Fiber.max_result_align)); // TODO
891 _ = result_len;893 assert(context_alignment.compare(.lte, Fiber.max_context_align)); // TODO
892 _ = result_alignment;894 assert(result_len <= Fiber.max_result_size); // TODO
893 _ = context;895 assert(context.len <= Fiber.max_context_size); // TODO
894 _ = context_alignment;896
895 _ = start;897 const fiber = try Fiber.allocate(k);
896 @panic("TODO");898 std.log.debug("allocated {*}", .{fiber});
899
900 const closure: *AsyncClosure = .fromFiber(fiber);
901 fiber.* = .{
902 .required_align = {},
903 .context = switch (builtin.cpu.arch) {
904 .x86_64 => .{
905 .rsp = @intFromPtr(closure) - @sizeOf(usize),
906 .rbp = 0,
907 .rip = @intFromPtr(&fiberEntry),
908 },
909 .aarch64 => .{
910 .sp = @intFromPtr(closure),
911 .fp = 0,
912 .pc = @intFromPtr(&fiberEntry),
913 },
914 else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)),
915 },
916 .awaiter = null,
917 .queue_next = null,
918 .cancel_thread = null,
919 .awaiting_completions = .initEmpty(),
920 };
921 closure.* = .{
922 .kqueue = k,
923 .fiber = fiber,
924 .start = start,
925 .result_align = result_alignment,
926 .already_awaited = false,
927 };
928 @memcpy(closure.contextPointer(), context);
929
930 k.schedule(.current(), .{ .head = fiber, .tail = fiber });
931 return @ptrCast(fiber);
897}932}
898933
899fn await(934fn await(
...@@ -903,11 +938,11 @@ fn await(...@@ -903,11 +938,11 @@ fn await(
903 result_alignment: std.mem.Alignment,938 result_alignment: std.mem.Alignment,
904) void {939) void {
905 const k: *Kqueue = @ptrCast(@alignCast(userdata));940 const k: *Kqueue = @ptrCast(@alignCast(userdata));
906 _ = k;941 const future_fiber: *Fiber = @ptrCast(@alignCast(any_future));
907 _ = any_future;942 if (@atomicLoad(?*Fiber, &future_fiber.awaiter, .acquire) != Fiber.finished)
908 _ = result;943 k.yield(null, .{ .register_awaiter = &future_fiber.awaiter });
909 _ = result_alignment;944 @memcpy(result, future_fiber.resultBytes(result_alignment));
910 @panic("TODO");945 k.recycle(future_fiber);
911}946}
912947
913fn cancel(948fn cancel(