| ... | ... | @@ -172,9 +172,6 @@ pub fn init(k: *Kqueue, gpa: Allocator) !void { |
| 172 | 172 | .sp = @intFromPtr(idle_stack_end), |
| 173 | 173 | .fp = 0, |
| 174 | 174 | .pc = @intFromPtr(&mainIdleEntry), |
| 175 | | .x18 = asm ("" |
| 176 | | : [x18] "={x18}" (-> u64), |
| 177 | | ), |
| 178 | 175 | }, |
| 179 | 176 | .x86_64 => .{ |
| 180 | 177 | .rsp = @intFromPtr(idle_stack_end - 1), |
| ... | ... | @@ -548,7 +545,6 @@ const Context = switch (builtin.cpu.arch) { |
| 548 | 545 | sp: u64, |
| 549 | 546 | fp: u64, |
| 550 | 547 | pc: u64, |
| 551 | | x18: u64, |
| 552 | 548 | }, |
| 553 | 549 | .x86_64 => extern struct { |
| 554 | 550 | rsp: u64, |
| ... | ... | @@ -562,12 +558,12 @@ inline fn contextSwitch(message: *const SwitchMessage) *const SwitchMessage { |
| 562 | 558 | return @fieldParentPtr("contexts", switch (builtin.cpu.arch) { |
| 563 | 559 | .aarch64 => asm volatile ( |
| 564 | 560 | \\ ldp x0, x2, [x1] |
| 565 | | \\ ldp x3, x18, [x2, #16] |
| 561 | \\ ldr x3, [x2, #16] |
| 566 | 562 | \\ mov x4, sp |
| 567 | 563 | \\ stp x4, fp, [x0] |
| 568 | 564 | \\ adr x5, 0f |
| 569 | 565 | \\ ldp x4, fp, [x2] |
| 570 | | \\ stp x5, x18, [x0, #16] |
| 566 | \\ str x5, [x0, #16] |
| 571 | 567 | \\ mov sp, x4 |
| 572 | 568 | \\ br x3 |
| 573 | 569 | \\0: |
| ... | ... | @@ -761,12 +757,18 @@ fn fiberEntry() callconv(.naked) void { |
| 761 | 757 | : |
| 762 | 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 | 766 | else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)), |
| 765 | 767 | } |
| 766 | 768 | } |
| 767 | 769 | |
| 768 | 770 | const AsyncClosure = struct { |
| 769 | | event_loop: *Kqueue, |
| 771 | kqueue: *Kqueue, |
| 770 | 772 | fiber: *Fiber, |
| 771 | 773 | start: *const fn (context: *const anyopaque, result: *anyopaque) void, |
| 772 | 774 | result_align: Alignment, |
| ... | ... | @@ -777,7 +779,7 @@ const AsyncClosure = struct { |
| 777 | 779 | } |
| 778 | 780 | |
| 779 | 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 | 783 | const fiber = closure.fiber; |
| 782 | 784 | std.log.debug("{*} performing async", .{fiber}); |
| 783 | 785 | closure.start(closure.contextPointer(), fiber.resultBytes(closure.result_align)); |
| ... | ... | @@ -787,7 +789,7 @@ const AsyncClosure = struct { |
| 787 | 789 | if (@atomicRmw(bool, &closure.already_awaited, .Xchg, true, .acq_rel)) break :r null; |
| 788 | 790 | break :r a; |
| 789 | 791 | }; |
| 790 | | closure.event_loop.yield(ready_awaiter, .nothing); |
| 792 | closure.kqueue.yield(ready_awaiter, .nothing); |
| 791 | 793 | unreachable; // switched to dead fiber |
| 792 | 794 | } |
| 793 | 795 | |
| ... | ... | @@ -881,19 +883,52 @@ fn async( |
| 881 | 883 | fn concurrent( |
| 882 | 884 | userdata: ?*anyopaque, |
| 883 | 885 | result_len: usize, |
| 884 | | result_alignment: std.mem.Alignment, |
| 886 | result_alignment: Alignment, |
| 885 | 887 | context: []const u8, |
| 886 | | context_alignment: std.mem.Alignment, |
| 888 | context_alignment: Alignment, |
| 887 | 889 | start: *const fn (context: *const anyopaque, result: *anyopaque) void, |
| 888 | 890 | ) error{OutOfMemory}!*Io.AnyFuture { |
| 889 | 891 | 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); |
| 897 | 932 | } |
| 898 | 933 | |
| 899 | 934 | fn await( |
| ... | ... | @@ -903,11 +938,11 @@ fn await( |
| 903 | 938 | result_alignment: std.mem.Alignment, |
| 904 | 939 | ) void { |
| 905 | 940 | 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); |
| 911 | 946 | } |
| 912 | 947 | |
| 913 | 948 | fn cancel( |