| ... | @@ -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, sp | 562 | \\ mov x4, sp |
| 567 | \\ stp x4, fp, [x0] | 563 | \\ stp x4, fp, [x0] |
| 568 | \\ adr x5, 0f | 564 | \\ 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, x4 | 567 | \\ mov sp, x4 |
| 572 | \\ br x3 | 568 | \\ 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 | } |
| 767 | | 769 | |
| 768 | const AsyncClosure = struct { | 770 | const 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 | } |
| 778 | | 780 | |
| 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 fiber | 793 | unreachable; // switched to dead fiber |
| 792 | } | 794 | } |
| 793 | | 795 | |
| ... | @@ -881,19 +883,52 @@ fn async( | ... | @@ -881,19 +883,52 @@ fn async( |
| 881 | fn concurrent( | 883 | fn 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 | } |
| 898 | | 933 | |
| 899 | fn await( | 934 | fn 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 | } |
| 912 | | 947 | |
| 913 | fn cancel( | 948 | fn cancel( |