authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-23 06:02:46-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:51-07:00
log5578c760a77bd43ce13c9352f68f7e44c5440c8f
treec7ea4e56a539dc7c07e005b43951d240c2453320
parent6a64c9b7c8971486a818d8cb2ae44bb4dab4497f

std.Io.Kqueue: implement wait queue per fd

Solves the issue when one kevent() call would clobber another if they used the same file descriptor as an identifier.

1 files changed, 52 insertions(+), 21 deletions(-)

lib/std/Io/Kqueue.zig+52-21
...@@ -423,17 +423,35 @@ fn idle(k: *Kqueue, thread: *Thread) void {...@@ -423,17 +423,35 @@ fn idle(k: *Kqueue, thread: *Thread) void {
423 return;423 return;
424 },424 },
425 _ => {425 _ => {
426 const fiber: *Fiber = @ptrFromInt(event.udata);426 const event_head_fiber: *Fiber = @ptrFromInt(event.udata);
427 assert(fiber.queue_next == null);427 const event_tail_fiber = thread.wait_queues.fetchSwapRemove(.{
428 fiber.resultPointer(Completion).* = .{428 .ident = event.ident,
429 .filter = event.filter,
430 }).?.value;
431 assert(event_tail_fiber.queue_next == null);
432
433 // TODO reevaluate this logic
434 event_head_fiber.resultPointer(Completion).* = .{
429 .flags = event.flags,435 .flags = event.flags,
430 .fflags = event.fflags,436 .fflags = event.fflags,
431 .data = event.data,437 .data = event.data,
432 };438 };
433 if (maybe_ready_fiber == null) maybe_ready_fiber = fiber else if (maybe_ready_queue) |*ready_queue| {439
434 ready_queue.tail.queue_next = fiber;440 queue_ready: {
435 ready_queue.tail = fiber;441 const head: *Fiber = if (maybe_ready_fiber == null) f: {
436 } else maybe_ready_queue = .{ .head = fiber, .tail = fiber };442 maybe_ready_fiber = event_head_fiber;
443 const next = event_head_fiber.queue_next orelse break :queue_ready;
444 event_head_fiber.queue_next = null;
445 break :f next;
446 } else event_head_fiber;
447
448 if (maybe_ready_queue) |*ready_queue| {
449 ready_queue.tail.queue_next = head;
450 ready_queue.tail = event_tail_fiber;
451 } else {
452 maybe_ready_queue = .{ .head = head, .tail = event_tail_fiber };
453 }
454 }
437 },455 },
438 };456 };
439 if (maybe_ready_queue) |ready_queue| k.schedule(thread, ready_queue);457 if (maybe_ready_queue) |ready_queue| k.schedule(thread, ready_queue);
...@@ -1477,7 +1495,6 @@ fn netRead(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Strea...@@ -1477,7 +1495,6 @@ fn netRead(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Strea
14771495
1478 while (true) {1496 while (true) {
1479 try k.checkCancel();1497 try k.checkCancel();
1480 std.debug.print("calling readv\n", .{});
1481 const rc = posix.system.readv(fd, dest.ptr, @intCast(dest.len));1498 const rc = posix.system.readv(fd, dest.ptr, @intCast(dest.len));
1482 switch (posix.errno(rc)) {1499 switch (posix.errno(rc)) {
1483 .SUCCESS => return @intCast(rc),1500 .SUCCESS => return @intCast(rc),
...@@ -1486,19 +1503,33 @@ fn netRead(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Strea...@@ -1486,19 +1503,33 @@ fn netRead(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Strea
1486 .AGAIN => {1503 .AGAIN => {
1487 const thread: *Thread = .current();1504 const thread: *Thread = .current();
1488 const fiber = thread.currentFiber();1505 const fiber = thread.currentFiber();
1489 const changes = [_]posix.Kevent{1506 const ident: u32 = @bitCast(fd);
1490 .{1507 const filter = std.c.EVFILT.READ;
1491 .ident = @as(u32, @bitCast(fd)),1508 const gop = thread.wait_queues.getOrPut(k.gpa, .{
1492 .filter = std.c.EVFILT.READ,1509 .ident = ident,
1493 .flags = std.c.EV.ADD | std.c.EV.ONESHOT,1510 .filter = filter,
1494 .fflags = 0,1511 }) catch return error.SystemResources;
1495 .data = 0,1512 if (gop.found_existing) {
1496 .udata = @intFromPtr(fiber),1513 const tail_fiber = gop.value_ptr.*;
1497 },1514 assert(tail_fiber.queue_next == null);
1498 };1515 tail_fiber.queue_next = fiber;
1499 assert(0 == (posix.kevent(thread.kq_fd, &changes, &.{}, null) catch |err| {1516 gop.value_ptr.* = fiber;
1500 @panic(@errorName(err)); // TODO1517 } else {
1501 }));1518 gop.value_ptr.* = fiber;
1519 const changes = [_]posix.Kevent{
1520 .{
1521 .ident = ident,
1522 .filter = filter,
1523 .flags = std.c.EV.ADD | std.c.EV.ONESHOT,
1524 .fflags = 0,
1525 .data = 0,
1526 .udata = @intFromPtr(fiber),
1527 },
1528 };
1529 assert(0 == (posix.kevent(thread.kq_fd, &changes, &.{}, null) catch |err| {
1530 @panic(@errorName(err)); // TODO
1531 }));
1532 }
1502 yield(k, null, .nothing);1533 yield(k, null, .nothing);
1503 continue;1534 continue;
1504 },1535 },