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 {
172172 .sp = @intFromPtr(idle_stack_end),
173173 .fp = 0,
174174 .pc = @intFromPtr(&mainIdleEntry),
175 .x18 = asm (""
176 : [x18] "={x18}" (-> u64),
177 ),
178175 },
179176 .x86_64 => .{
180177 .rsp = @intFromPtr(idle_stack_end - 1),
......@@ -548,7 +545,6 @@ const Context = switch (builtin.cpu.arch) {
548545 sp: u64,
549546 fp: u64,
550547 pc: u64,
551 x18: u64,
552548 },
553549 .x86_64 => extern struct {
554550 rsp: u64,
......@@ -562,12 +558,12 @@ inline fn contextSwitch(message: *const SwitchMessage) *const SwitchMessage {
562558 return @fieldParentPtr("contexts", switch (builtin.cpu.arch) {
563559 .aarch64 => asm volatile (
564560 \\ ldp x0, x2, [x1]
565 \\ ldp x3, x18, [x2, #16]
561 \\ ldr x3, [x2, #16]
566562 \\ mov x4, sp
567563 \\ stp x4, fp, [x0]
568564 \\ adr x5, 0f
569565 \\ ldp x4, fp, [x2]
570 \\ stp x5, x18, [x0, #16]
566 \\ str x5, [x0, #16]
571567 \\ mov sp, x4
572568 \\ br x3
573569 \\0:
......@@ -761,12 +757,18 @@ fn fiberEntry() callconv(.naked) void {
761757 :
762758 : [AsyncClosure_call] "X" (&AsyncClosure.call),
763759 ),
760 .aarch64 => asm volatile (
761 \\ mov x0, sp
762 \\ b %[AsyncClosure_call]
763 :
764 : [AsyncClosure_call] "X" (&AsyncClosure.call),
765 ),
764766 else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)),
765767 }
766768}
767769
768770const AsyncClosure = struct {
769 event_loop: *Kqueue,
771 kqueue: *Kqueue,
770772 fiber: *Fiber,
771773 start: *const fn (context: *const anyopaque, result: *anyopaque) void,
772774 result_align: Alignment,
......@@ -777,7 +779,7 @@ const AsyncClosure = struct {
777779 }
778780
779781 fn call(closure: *AsyncClosure, message: *const SwitchMessage) callconv(.withStackAlign(.c, @alignOf(AsyncClosure))) noreturn {
780 message.handle(closure.event_loop);
782 message.handle(closure.kqueue);
781783 const fiber = closure.fiber;
782784 std.log.debug("{*} performing async", .{fiber});
783785 closure.start(closure.contextPointer(), fiber.resultBytes(closure.result_align));
......@@ -787,7 +789,7 @@ const AsyncClosure = struct {
787789 if (@atomicRmw(bool, &closure.already_awaited, .Xchg, true, .acq_rel)) break :r null;
788790 break :r a;
789791 };
790 closure.event_loop.yield(ready_awaiter, .nothing);
792 closure.kqueue.yield(ready_awaiter, .nothing);
791793 unreachable; // switched to dead fiber
792794 }
793795
......@@ -881,19 +883,52 @@ fn async(
881883fn concurrent(
882884 userdata: ?*anyopaque,
883885 result_len: usize,
884 result_alignment: std.mem.Alignment,
886 result_alignment: Alignment,
885887 context: []const u8,
886 context_alignment: std.mem.Alignment,
888 context_alignment: Alignment,
887889 start: *const fn (context: *const anyopaque, result: *anyopaque) void,
888890) error{OutOfMemory}!*Io.AnyFuture {
889891 const k: *Kqueue = @ptrCast(@alignCast(userdata));
890 _ = k;
891 _ = result_len;
892 _ = result_alignment;
893 _ = context;
894 _ = context_alignment;
895 _ = start;
896 @panic("TODO");
892 assert(result_alignment.compare(.lte, Fiber.max_result_align)); // TODO
893 assert(context_alignment.compare(.lte, Fiber.max_context_align)); // TODO
894 assert(result_len <= Fiber.max_result_size); // TODO
895 assert(context.len <= Fiber.max_context_size); // TODO
896
897 const fiber = try Fiber.allocate(k);
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);
897932}
898933
899934fn await(
......@@ -903,11 +938,11 @@ fn await(
903938 result_alignment: std.mem.Alignment,
904939) void {
905940 const k: *Kqueue = @ptrCast(@alignCast(userdata));
906 _ = k;
907 _ = any_future;
908 _ = result;
909 _ = result_alignment;
910 @panic("TODO");
941 const future_fiber: *Fiber = @ptrCast(@alignCast(any_future));
942 if (@atomicLoad(?*Fiber, &future_fiber.awaiter, .acquire) != Fiber.finished)
943 k.yield(null, .{ .register_awaiter = &future_fiber.awaiter });
944 @memcpy(result, future_fiber.resultBytes(result_alignment));
945 k.recycle(future_fiber);
911946}
912947
913948fn cancel(