| ... | @@ -2560,17 +2560,31 @@ fn batchWait(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout) Io.Batch. | ... | @@ -2560,17 +2560,31 @@ fn batchWait(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout) Io.Batch. |
| 2560 | const deadline = timeout.toDeadline(t_io) catch return error.UnsupportedClock; | 2560 | const deadline = timeout.toDeadline(t_io) catch return error.UnsupportedClock; |
| 2561 | const max_poll_ms = std.math.maxInt(i32); | 2561 | const max_poll_ms = std.math.maxInt(i32); |
| 2562 | while (true) { | 2562 | while (true) { |
| 2563 | const timeout_ms: i32 = if (deadline) |d| t: { | 2563 | const timeout_ms: i32 = t: { |
| | 2564 | if (b.user.complete_head != complete_tail) { |
| | 2565 | // It is legal to call batchWait with already completed |
| | 2566 | // operations in the ring. In such case, we need to avoid |
| | 2567 | // blocking in the poll syscall, but we can still take this |
| | 2568 | // opportunity to find additional ready operations. |
| | 2569 | break :t 0; |
| | 2570 | } |
| | 2571 | const d = deadline orelse break :t -1; |
| 2564 | const duration = d.durationFromNow(t_io) catch return error.UnsupportedClock; | 2572 | const duration = d.durationFromNow(t_io) catch return error.UnsupportedClock; |
| 2565 | if (duration.raw.nanoseconds <= 0) return error.Timeout; | 2573 | if (duration.raw.nanoseconds <= 0) return error.Timeout; |
| 2566 | break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds())); | 2574 | break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds())); |
| 2567 | } else -1; | 2575 | }; |
| 2568 | const syscall = try Syscall.start(); | 2576 | const syscall = try Syscall.start(); |
| 2569 | const rc = posix.system.poll(&poll_buffer, poll_i, timeout_ms); | 2577 | const rc = posix.system.poll(&poll_buffer, poll_i, timeout_ms); |
| 2570 | syscall.finish(); | 2578 | syscall.finish(); |
| 2571 | switch (posix.errno(rc)) { | 2579 | switch (posix.errno(rc)) { |
| 2572 | .SUCCESS => { | 2580 | .SUCCESS => { |
| 2573 | if (rc == 0) { | 2581 | if (rc == 0) { |
| | 2582 | if (b.user.complete_head != complete_tail) { |
| | 2583 | // Since there are already completions available in the |
| | 2584 | // queue, this is neither a timeout nor a case for |
| | 2585 | // retrying. |
| | 2586 | return; |
| | 2587 | } |
| 2574 | // Although spurious timeouts are OK, when no deadline is | 2588 | // Although spurious timeouts are OK, when no deadline is |
| 2575 | // passed we must not return `error.Timeout`. | 2589 | // passed we must not return `error.Timeout`. |
| 2576 | if (deadline == null) continue; | 2590 | if (deadline == null) continue; |
| ... | @@ -2677,8 +2691,6 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa | ... | @@ -2677,8 +2691,6 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa |
| 2677 | b.user.complete_tail = complete_tail; | 2691 | b.user.complete_tail = complete_tail; |
| 2678 | } | 2692 | } |
| 2679 | | 2693 | |
| 2680 | var any_done = false; | | |
| 2681 | | | |
| 2682 | while (submit_head != submit_tail) : (submit_head = submit_head.next(len)) { | 2694 | while (submit_head != submit_tail) : (submit_head = submit_head.next(len)) { |
| 2683 | const op = ring[submit_head.index(len)]; | 2695 | const op = ring[submit_head.index(len)]; |
| 2684 | const operation = &operations[op]; | 2696 | const operation = &operations[op]; |
| ... | @@ -2688,7 +2700,6 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa | ... | @@ -2688,7 +2700,6 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa |
| 2688 | .noop => |*o| { | 2700 | .noop => |*o| { |
| 2689 | _ = o.status.unstarted; | 2701 | _ = o.status.unstarted; |
| 2690 | o.status = .{ .result = {} }; | 2702 | o.status = .{ .result = {} }; |
| 2691 | any_done = true; | | |
| 2692 | submitComplete(ring, &complete_tail, op); | 2703 | submitComplete(ring, &complete_tail, op); |
| 2693 | }, | 2704 | }, |
| 2694 | .file_read_streaming => |*o| { | 2705 | .file_read_streaming => |*o| { |
| ... | @@ -2696,7 +2707,6 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa | ... | @@ -2696,7 +2707,6 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa |
| 2696 | switch (try ntReadFile(o.file.handle, o.data, &metadata.iosb)) { | 2707 | switch (try ntReadFile(o.file.handle, o.data, &metadata.iosb)) { |
| 2697 | .status => { | 2708 | .status => { |
| 2698 | o.status = .{ .result = ntReadFileResult(&metadata.iosb) }; | 2709 | o.status = .{ .result = ntReadFileResult(&metadata.iosb) }; |
| 2699 | any_done = true; | | |
| 2700 | submitComplete(ring, &complete_tail, op); | 2710 | submitComplete(ring, &complete_tail, op); |
| 2701 | }, | 2711 | }, |
| 2702 | .pending => { | 2712 | .pending => { |
| ... | @@ -2725,11 +2735,10 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa | ... | @@ -2725,11 +2735,10 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa |
| 2725 | o.status = .{ .result = ntReadFileResult(&metadata.iosb) }; | 2735 | o.status = .{ .result = ntReadFileResult(&metadata.iosb) }; |
| 2726 | }, | 2736 | }, |
| 2727 | } | 2737 | } |
| 2728 | any_done = true; | | |
| 2729 | metadata.pending = false; | 2738 | metadata.pending = false; |
| 2730 | submitComplete(ring, &complete_tail, op); | 2739 | submitComplete(ring, &complete_tail, op); |
| 2731 | } | 2740 | } |
| 2732 | if (any_done) return; | 2741 | if (b.user.complete_head != complete_tail) return; |
| 2733 | if (!any_pending) return; | 2742 | if (!any_pending) return; |
| 2734 | const alertable_syscall = try AlertableSyscall.start(); | 2743 | const alertable_syscall = try AlertableSyscall.start(); |
| 2735 | const delay_rc = windows.ntdll.NtDelayExecution(windows.TRUE, &delay_interval); | 2744 | const delay_rc = windows.ntdll.NtDelayExecution(windows.TRUE, &delay_interval); |