| ... | @@ -1938,6 +1938,10 @@ const have_mmap = switch (native_os) { | ... | @@ -1938,6 +1938,10 @@ const have_mmap = switch (native_os) { |
| 1938 | .wasi, .windows => false, | 1938 | .wasi, .windows => false, |
| 1939 | else => true, | 1939 | else => true, |
| 1940 | }; | 1940 | }; |
| | 1941 | const have_poll = switch (native_os) { |
| | 1942 | .wasi, .windows => false, |
| | 1943 | else => true, |
| | 1944 | }; |
| 1941 | | 1945 | |
| 1942 | const open_sym = if (posix.lfs64_abi) posix.system.open64 else posix.system.open; | 1946 | const open_sym = if (posix.lfs64_abi) posix.system.open64 else posix.system.open; |
| 1943 | const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat; | 1947 | const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat; |
| ... | @@ -2507,104 +2511,104 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void { | ... | @@ -2507,104 +2511,104 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void { |
| 2507 | alertable_syscall.finish(); | 2511 | alertable_syscall.finish(); |
| 2508 | return; | 2512 | return; |
| 2509 | } | 2513 | } |
| 2510 | if (native_os == .wasi and !builtin.link_libc) @panic("TODO"); | 2514 | if (have_poll) { |
| 2511 | var poll_buffer: [poll_buffer_len]posix.pollfd = undefined; | 2515 | var poll_buffer: [poll_buffer_len]posix.pollfd = undefined; |
| 2512 | var poll_len: u32 = 0; | 2516 | var poll_len: u32 = 0; |
| 2513 | { | 2517 | { |
| 2514 | var index = b.submissions.head; | 2518 | var index = b.submissions.head; |
| 2515 | while (index != .none and poll_len < poll_buffer_len) { | 2519 | while (index != .none and poll_len < poll_buffer_len) { |
| 2516 | const submission = &b.storage[index.toIndex()].submission; | 2520 | const submission = &b.storage[index.toIndex()].submission; |
| 2517 | switch (submission.operation) { | 2521 | switch (submission.operation) { |
| 2518 | .file_read_streaming => |o| { | 2522 | .file_read_streaming => |o| { |
| 2519 | poll_buffer[poll_len] = .{ .fd = o.file.handle, .events = posix.POLL.IN, .revents = 0 }; | 2523 | poll_buffer[poll_len] = .{ .fd = o.file.handle, .events = posix.POLL.IN, .revents = 0 }; |
| 2520 | poll_len += 1; | 2524 | poll_len += 1; |
| 2521 | }, | 2525 | }, |
| | 2526 | } |
| | 2527 | index = submission.node.next; |
| 2522 | } | 2528 | } |
| 2523 | index = submission.node.next; | | |
| 2524 | } | 2529 | } |
| 2525 | } | 2530 | switch (poll_len) { |
| 2526 | switch (poll_len) { | 2531 | 0 => return, |
| 2527 | 0 => return, | 2532 | 1 => {}, |
| 2528 | 1 => {}, | 2533 | else => while (true) { |
| 2529 | else => while (true) { | 2534 | const timeout_ms: i32 = t: { |
| 2530 | const timeout_ms: i32 = t: { | 2535 | if (b.completions.head != .none) { |
| 2531 | if (b.completions.head != .none) { | 2536 | // It is legal to call batchWait with already completed |
| 2532 | // It is legal to call batchWait with already completed | 2537 | // operations in the ring. In such case, we need to avoid |
| 2533 | // operations in the ring. In such case, we need to avoid | 2538 | // blocking in the poll syscall, but we can still take this |
| 2534 | // blocking in the poll syscall, but we can still take this | 2539 | // opportunity to find additional ready operations. |
| 2535 | // opportunity to find additional ready operations. | 2540 | break :t 0; |
| 2536 | break :t 0; | | |
| 2537 | } | | |
| 2538 | const max_poll_ms = std.math.maxInt(i32); | | |
| 2539 | break :t max_poll_ms; | | |
| 2540 | }; | | |
| 2541 | const syscall = try Syscall.start(); | | |
| 2542 | const rc = posix.system.poll(&poll_buffer, poll_len, timeout_ms); | | |
| 2543 | syscall.finish(); | | |
| 2544 | switch (posix.errno(rc)) { | | |
| 2545 | .SUCCESS => { | | |
| 2546 | if (rc == 0) { | | |
| 2547 | if (b.completions.head != .none) { | | |
| 2548 | // Since there are already completions available in the | | |
| 2549 | // queue, this is neither a timeout nor a case for | | |
| 2550 | // retrying. | | |
| 2551 | return; | | |
| 2552 | } | | |
| 2553 | continue; | | |
| 2554 | } | 2541 | } |
| 2555 | var prev_index: Io.Operation.OptionalIndex = .none; | 2542 | const max_poll_ms = std.math.maxInt(i32); |
| 2556 | var index = b.submissions.head; | 2543 | break :t max_poll_ms; |
| 2557 | for (poll_buffer[0..poll_len]) |poll_entry| { | 2544 | }; |
| 2558 | const storage = &b.storage[index.toIndex()]; | 2545 | const syscall = try Syscall.start(); |
| 2559 | const submission = &storage.submission; | 2546 | const rc = posix.system.poll(&poll_buffer, poll_len, timeout_ms); |
| 2560 | const next_index = submission.node.next; | 2547 | syscall.finish(); |
| 2561 | if (poll_entry.revents != 0) { | 2548 | switch (posix.errno(rc)) { |
| 2562 | const result = try operate(t, submission.operation); | 2549 | .SUCCESS => { |
| 2563 | | 2550 | if (rc == 0) { |
| 2564 | switch (prev_index) { | 2551 | if (b.completions.head != .none) { |
| 2565 | .none => b.submissions.head = next_index, | 2552 | // Since there are already completions available in the |
| 2566 | else => b.storage[prev_index.toIndex()].submission.node.next = next_index, | 2553 | // queue, this is neither a timeout nor a case for |
| 2567 | } | 2554 | // retrying. |
| 2568 | if (next_index == .none) b.submissions.tail = prev_index; | 2555 | return; |
| 2569 | | | |
| 2570 | switch (b.completions.tail) { | | |
| 2571 | .none => b.completions.head = index, | | |
| 2572 | else => |tail_index| b.storage[tail_index.toIndex()].completion.node.next = index, | | |
| 2573 | } | 2556 | } |
| 2574 | storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } }; | 2557 | continue; |
| 2575 | b.completions.tail = index; | 2558 | } |
| 2576 | } else prev_index = index; | 2559 | var prev_index: Io.Operation.OptionalIndex = .none; |
| 2577 | index = next_index; | 2560 | var index = b.submissions.head; |
| 2578 | } | 2561 | for (poll_buffer[0..poll_len]) |poll_entry| { |
| 2579 | assert(index == .none); | 2562 | const storage = &b.storage[index.toIndex()]; |
| 2580 | return; | 2563 | const submission = &storage.submission; |
| 2581 | }, | 2564 | const next_index = submission.node.next; |
| 2582 | .INTR => continue, | 2565 | if (poll_entry.revents != 0) { |
| 2583 | else => break, | 2566 | const result = try operate(t, submission.operation); |
| 2584 | } | 2567 | |
| 2585 | }, | 2568 | switch (prev_index) { |
| | 2569 | .none => b.submissions.head = next_index, |
| | 2570 | else => b.storage[prev_index.toIndex()].submission.node.next = next_index, |
| | 2571 | } |
| | 2572 | if (next_index == .none) b.submissions.tail = prev_index; |
| | 2573 | |
| | 2574 | switch (b.completions.tail) { |
| | 2575 | .none => b.completions.head = index, |
| | 2576 | else => |tail_index| b.storage[tail_index.toIndex()].completion.node.next = index, |
| | 2577 | } |
| | 2578 | storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } }; |
| | 2579 | b.completions.tail = index; |
| | 2580 | } else prev_index = index; |
| | 2581 | index = next_index; |
| | 2582 | } |
| | 2583 | assert(index == .none); |
| | 2584 | return; |
| | 2585 | }, |
| | 2586 | .INTR => continue, |
| | 2587 | else => break, |
| | 2588 | } |
| | 2589 | }, |
| | 2590 | } |
| 2586 | } | 2591 | } |
| 2587 | { | | |
| 2588 | var tail_index = b.completions.tail; | | |
| 2589 | defer b.completions.tail = tail_index; | | |
| 2590 | var index = b.submissions.head; | | |
| 2591 | errdefer b.submissions.head = index; | | |
| 2592 | while (index != .none) { | | |
| 2593 | const storage = &b.storage[index.toIndex()]; | | |
| 2594 | const submission = &storage.submission; | | |
| 2595 | const next_index = submission.node.next; | | |
| 2596 | const result = try operate(t, submission.operation); | | |
| 2597 | | 2592 | |
| 2598 | switch (tail_index) { | 2593 | var tail_index = b.completions.tail; |
| 2599 | .none => b.completions.head = index, | 2594 | defer b.completions.tail = tail_index; |
| 2600 | else => b.storage[tail_index.toIndex()].completion.node.next = index, | 2595 | var index = b.submissions.head; |
| 2601 | } | 2596 | errdefer b.submissions.head = index; |
| 2602 | storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } }; | 2597 | while (index != .none) { |
| 2603 | tail_index = index; | 2598 | const storage = &b.storage[index.toIndex()]; |
| 2604 | index = next_index; | 2599 | const submission = &storage.submission; |
| | 2600 | const next_index = submission.node.next; |
| | 2601 | const result = try operate(t, submission.operation); |
| | 2602 | |
| | 2603 | switch (tail_index) { |
| | 2604 | .none => b.completions.head = index, |
| | 2605 | else => b.storage[tail_index.toIndex()].completion.node.next = index, |
| 2605 | } | 2606 | } |
| 2606 | b.submissions = .{ .head = .none, .tail = .none }; | 2607 | storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } }; |
| | 2608 | tail_index = index; |
| | 2609 | index = next_index; |
| 2607 | } | 2610 | } |
| | 2611 | b.submissions = .{ .head = .none, .tail = .none }; |
| 2608 | } | 2612 | } |
| 2609 | | 2613 | |
| 2610 | fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.AwaitConcurrentError!void { | 2614 | fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.AwaitConcurrentError!void { |
| ... | @@ -2644,7 +2648,11 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout | ... | @@ -2644,7 +2648,11 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout |
| 2644 | } | 2648 | } |
| 2645 | return; | 2649 | return; |
| 2646 | } | 2650 | } |
| 2647 | if (native_os == .wasi and !builtin.link_libc) @panic("TODO"); | 2651 | if (native_os == .wasi) { |
| | 2652 | // TODO call poll_oneoff |
| | 2653 | return error.ConcurrencyUnavailable; |
| | 2654 | } |
| | 2655 | if (!have_poll) return error.ConcurrencyUnavailable; |
| 2648 | var poll_buffer: [poll_buffer_len]posix.pollfd = undefined; | 2656 | var poll_buffer: [poll_buffer_len]posix.pollfd = undefined; |
| 2649 | var poll_storage: struct { | 2657 | var poll_storage: struct { |
| 2650 | gpa: std.mem.Allocator, | 2658 | gpa: std.mem.Allocator, |