| ... | ... | @@ -1255,6 +1255,32 @@ const AlertableSyscall = struct { |
| 1255 | 1255 | assert(is_windows); |
| 1256 | 1256 | } |
| 1257 | 1257 | |
| 1258 | fn start() Io.Cancelable!AlertableSyscall { |
| 1259 | const thread = Thread.current orelse return .{ .thread = null }; |
| 1260 | switch (thread.cancel_protection) { |
| 1261 | .blocked => return .{ .thread = null }, |
| 1262 | .unblocked => {}, |
| 1263 | } |
| 1264 | const old_status = thread.status.fetchOr(.{ |
| 1265 | .cancelation = @enumFromInt(0b010), |
| 1266 | .awaitable = .null, |
| 1267 | }, .monotonic); |
| 1268 | switch (old_status.cancelation) { |
| 1269 | .parked => unreachable, |
| 1270 | .blocked => unreachable, |
| 1271 | .blocked_alertable => unreachable, |
| 1272 | .blocked_canceling => unreachable, |
| 1273 | .blocked_alertable_canceling => unreachable, |
| 1274 | .none => return .{ .thread = thread }, // new status is `.blocked_alertable` |
| 1275 | .canceling => { |
| 1276 | // Status is unchanged (still `.canceling`)---change to `.canceled` before return. |
| 1277 | thread.status.store(.{ .cancelation = .canceled, .awaitable = old_status.awaitable }, .monotonic); |
| 1278 | return error.Canceled; |
| 1279 | }, |
| 1280 | .canceled => return .{ .thread = null }, // new status is `.canceled` (unchanged) |
| 1281 | } |
| 1282 | } |
| 1283 | |
| 1258 | 1284 | fn checkCancel(s: AlertableSyscall) Io.Cancelable!void { |
| 1259 | 1285 | comptime assert(is_windows); |
| 1260 | 1286 | const thread = s.thread orelse return; |
| ... | ... | @@ -2501,10 +2527,10 @@ fn batchWait(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout) Io.Batch. |
| 2501 | 2527 | const op = ring[submit_head.index(len)]; |
| 2502 | 2528 | const operation = &operations[op]; |
| 2503 | 2529 | switch (operation.*) { |
| 2504 | | .noop => { |
| 2505 | | try operate(t, operation); |
| 2506 | | ring[complete_tail.index(len)] = op; |
| 2507 | | complete_tail = complete_tail.next(len); |
| 2530 | .noop => |*o| { |
| 2531 | _ = o.status.unstarted; |
| 2532 | o.status = .{ .result = {} }; |
| 2533 | submitComplete(ring, &complete_tail, op); |
| 2508 | 2534 | }, |
| 2509 | 2535 | .file_read_streaming => |*o| { |
| 2510 | 2536 | _ = o.status.unstarted; |
| ... | ... | @@ -2524,8 +2550,7 @@ fn batchWait(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout) Io.Batch. |
| 2524 | 2550 | 1 => if (timeout == .none) { |
| 2525 | 2551 | const op = map_buffer[0]; |
| 2526 | 2552 | try operate(t, &operations[op]); |
| 2527 | | ring[complete_tail.index(len)] = op; |
| 2528 | | complete_tail = complete_tail.next(len); |
| 2553 | submitComplete(ring, &complete_tail, op); |
| 2529 | 2554 | poll_i = 0; |
| 2530 | 2555 | return; |
| 2531 | 2556 | }, |
| ... | ... | @@ -2560,8 +2585,7 @@ fn batchWait(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout) Io.Batch. |
| 2560 | 2585 | ring[submit_head.index(len)] = op; |
| 2561 | 2586 | } else { |
| 2562 | 2587 | try operate(t, &operations[op]); |
| 2563 | | ring[complete_tail.index(len)] = op; |
| 2564 | | complete_tail = complete_tail.next(len); |
| 2588 | submitComplete(ring, &complete_tail, op); |
| 2565 | 2589 | } |
| 2566 | 2590 | } |
| 2567 | 2591 | return; |
| ... | ... | @@ -2584,19 +2608,49 @@ fn batchCancel(userdata: ?*anyopaque, b: *Io.Batch) void { |
| 2584 | 2608 | while (submit_head != submit_tail) : (submit_head = submit_head.next(len)) { |
| 2585 | 2609 | const op = ring[submit_head.index(len)]; |
| 2586 | 2610 | switch (operations[op]) { |
| 2587 | | .noop => { |
| 2588 | | operate(t, &operations[op]) catch unreachable; |
| 2589 | | ring[complete_tail.index(len)] = op; |
| 2590 | | complete_tail = complete_tail.next(len); |
| 2611 | .noop => |*o| { |
| 2612 | _ = o.status.unstarted; |
| 2613 | o.status = .{ .result = {} }; |
| 2614 | submitComplete(ring, &complete_tail, op); |
| 2591 | 2615 | }, |
| 2592 | 2616 | .file_read_streaming => |*o| _ = o.status.unstarted, |
| 2593 | 2617 | } |
| 2594 | 2618 | } |
| 2619 | if (is_windows) { |
| 2620 | // Iterate over pending and issue cancelations, then free the allocation for IO_STATUS_BLOCK |
| 2621 | if (b.impl.reserved) |reserved| { |
| 2622 | const gpa = t.allocator; |
| 2623 | const metadatas_ptr: [*]WinOpMetadata = @ptrCast(@alignCast(reserved)); |
| 2624 | const metadatas = metadatas_ptr[0..b.operations.len]; |
| 2625 | for (metadatas, 0..) |*metadata, op| { |
| 2626 | const done = @atomicLoad(windows.NTSTATUS, &metadata.iosb.u.Status, .acquire) != .PENDING; |
| 2627 | if (done) continue; |
| 2628 | switch (operations[op]) { |
| 2629 | .noop => unreachable, |
| 2630 | .file_read_streaming => |*o| { |
| 2631 | _ = windows.ntdll.NtCancelIoFile(o.file.handle, &metadata.iosb); |
| 2632 | }, |
| 2633 | } |
| 2634 | } |
| 2635 | for (metadatas) |*metadata| { |
| 2636 | while (@atomicLoad(windows.NTSTATUS, &metadata.iosb.u.Status, .acquire) == .PENDING) { |
| 2637 | waitForApcOrAlert(); |
| 2638 | } |
| 2639 | } |
| 2640 | gpa.free(metadatas); |
| 2641 | b.impl.reserved = null; |
| 2642 | } |
| 2643 | } |
| 2595 | 2644 | b.impl.submit_head = submit_tail; |
| 2596 | 2645 | b.impl.complete_tail = complete_tail; |
| 2597 | 2646 | b.user.complete_tail = complete_tail; |
| 2598 | 2647 | } |
| 2599 | 2648 | |
| 2649 | const WinOpMetadata = struct { |
| 2650 | iosb: windows.IO_STATUS_BLOCK, |
| 2651 | pending: bool, |
| 2652 | }; |
| 2653 | |
| 2600 | 2654 | fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.WaitError!void { |
| 2601 | 2655 | const operations = b.operations; |
| 2602 | 2656 | const len: u31 = @intCast(operations.len); |
| ... | ... | @@ -2606,16 +2660,16 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa |
| 2606 | 2660 | b.impl.submit_tail = submit_tail; |
| 2607 | 2661 | var complete_tail = b.impl.complete_tail; |
| 2608 | 2662 | |
| 2609 | | var overlapped_buffer: [poll_buffer_len]windows.OVERLAPPED = undefined; |
| 2610 | | var handles_buffer: [poll_buffer_len]windows.HANDLE = undefined; |
| 2611 | | var map_buffer: [poll_buffer_len]u32 = undefined; // handles_buffer index to operations index |
| 2612 | | var buffer_i: usize = 0; |
| 2663 | const metadatas_ptr: [*]WinOpMetadata = if (b.impl.reserved) |reserved| @ptrCast(@alignCast(reserved)) else a: { |
| 2664 | const gpa = t.allocator; |
| 2665 | const metadatas = gpa.alloc(WinOpMetadata, operations.len) catch return error.ConcurrencyUnavailable; |
| 2666 | b.impl.reserved = metadatas.ptr; |
| 2667 | @memset(metadatas, .{ .iosb = undefined, .pending = false }); |
| 2668 | break :a metadatas.ptr; |
| 2669 | }; |
| 2670 | const metadatas = metadatas_ptr[0..operations.len]; |
| 2613 | 2671 | |
| 2614 | 2672 | defer { |
| 2615 | | for (map_buffer[0..buffer_i]) |op| { |
| 2616 | | submit_head = submit_head.prev(len); |
| 2617 | | ring[submit_head.index(len)] = op; |
| 2618 | | } |
| 2619 | 2673 | b.impl.submit_head = submit_head; |
| 2620 | 2674 | b.impl.complete_tail = complete_tail; |
| 2621 | 2675 | b.user.complete_tail = complete_tail; |
| ... | ... | @@ -2624,74 +2678,76 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa |
| 2624 | 2678 | while (submit_head != submit_tail) : (submit_head = submit_head.next(len)) { |
| 2625 | 2679 | const op = ring[submit_head.index(len)]; |
| 2626 | 2680 | const operation = &operations[op]; |
| 2681 | const metadata = &metadatas[op]; |
| 2682 | metadata.* = .{ .iosb = undefined, .pending = false }; |
| 2627 | 2683 | switch (operation.*) { |
| 2628 | | .noop => { |
| 2629 | | try operate(t, operation); |
| 2630 | | ring[complete_tail.index(len)] = op; |
| 2631 | | complete_tail = complete_tail.next(len); |
| 2684 | .noop => |*o| { |
| 2685 | _ = o.status.unstarted; |
| 2686 | o.status = .{ .result = {} }; |
| 2687 | submitComplete(ring, &complete_tail, op); |
| 2632 | 2688 | }, |
| 2633 | 2689 | .file_read_streaming => |*o| { |
| 2634 | 2690 | _ = o.status.unstarted; |
| 2635 | | if (handles_buffer.len - buffer_i == 0) return error.ConcurrencyUnavailable; |
| 2636 | | const overlapped = &overlapped_buffer[buffer_i]; |
| 2637 | | overlapped.* = .{ |
| 2638 | | .Internal = 0, |
| 2639 | | .InternalHigh = 0, |
| 2640 | | .DUMMYUNIONNAME = .{ .Pointer = null }, |
| 2641 | | .hEvent = null, |
| 2642 | | }; |
| 2643 | | var n: windows.DWORD = undefined; |
| 2644 | | const buf = o.data[0]; |
| 2645 | | const buf_len = std.math.lossyCast(windows.DWORD, buf.len); |
| 2646 | | if (windows.kernel32.ReadFile(o.file.handle, buf.ptr, buf_len, &n, overlapped) == 0) { |
| 2647 | | @panic("TODO"); |
| 2691 | switch (try ntReadFile(o.file.handle, o.data, &metadata.iosb)) { |
| 2692 | .status => { |
| 2693 | o.status = .{ .result = ntReadFileResult(&metadata.iosb) }; |
| 2694 | submitComplete(ring, &complete_tail, op); |
| 2695 | }, |
| 2696 | .pending => { |
| 2697 | o.status = .{ .pending = b }; |
| 2698 | metadata.pending = true; |
| 2699 | }, |
| 2648 | 2700 | } |
| 2649 | | handles_buffer[buffer_i] = o.file.handle; |
| 2650 | | map_buffer[buffer_i] = op; |
| 2651 | | buffer_i += 1; |
| 2652 | 2701 | }, |
| 2653 | 2702 | } |
| 2654 | 2703 | } |
| 2655 | 2704 | |
| 2656 | | switch (buffer_i) { |
| 2657 | | 0 => return, |
| 2658 | | 1 => if (timeout == .none) { |
| 2659 | | const op = map_buffer[0]; |
| 2660 | | try operate(t, &operations[op]); |
| 2661 | | ring[complete_tail.index(len)] = op; |
| 2662 | | complete_tail = complete_tail.next(len); |
| 2663 | | buffer_i = 0; |
| 2664 | | return; |
| 2665 | | }, |
| 2666 | | else => {}, |
| 2667 | | } |
| 2668 | | |
| 2669 | | const handles = handles_buffer[0..buffer_i]; |
| 2670 | | const map = map_buffer[0..buffer_i]; |
| 2705 | var delay_interval: windows.LARGE_INTEGER = timeoutToWindowsInterval(timeout); |
| 2671 | 2706 | |
| 2672 | | const syscall: Syscall = try .start(); |
| 2673 | | const index_result = windows.WaitForMultipleObjectsEx(handles, false, windows.INFINITE, true); |
| 2674 | | syscall.finish(); |
| 2675 | | const index = index_result catch |err| switch (err) { |
| 2676 | | error.Unexpected => @panic("TODO"), |
| 2677 | | error.WaitAbandoned => @panic("TODO"), |
| 2678 | | error.WaitTimeOut => @panic("TODO"), |
| 2679 | | }; |
| 2680 | | var n: windows.DWORD = undefined; |
| 2681 | | if (0 == windows.kernel32.GetOverlappedResult(handles[index], &overlapped_buffer[index], &n, 0)) { |
| 2682 | | switch (windows.GetLastError()) { |
| 2683 | | .BROKEN_PIPE => @panic("TODO"), |
| 2684 | | .OPERATION_ABORTED => @panic("TODO"), |
| 2685 | | else => @panic("TODO"), |
| 2707 | while (true) { |
| 2708 | const alertable_syscall = try AlertableSyscall.start(); |
| 2709 | const delay_rc = windows.ntdll.NtDelayExecution(windows.TRUE, &delay_interval); |
| 2710 | alertable_syscall.finish(); |
| 2711 | switch (delay_rc) { |
| 2712 | .SUCCESS => { |
| 2713 | // The thread woke due to the timeout. Although spurious |
| 2714 | // timeouts are OK, when no deadline is passed we must not |
| 2715 | // return `error.Timeout`. |
| 2716 | if (timeout != .none) return error.Timeout; |
| 2717 | }, |
| 2718 | else => {}, |
| 2686 | 2719 | } |
| 2687 | | } else switch (operations[map[index]]) { |
| 2688 | | .noop => unreachable, |
| 2689 | | .file_read_streaming => |*o| { |
| 2690 | | o.status = .{ .result = n }; |
| 2691 | | }, |
| 2720 | var any_done = false; |
| 2721 | var any_pending = false; |
| 2722 | for (metadatas, 0..) |*metadata, op_usize| { |
| 2723 | if (!metadata.pending) continue; |
| 2724 | any_pending = true; |
| 2725 | const op: u31 = @intCast(op_usize); |
| 2726 | const done = @atomicLoad(windows.NTSTATUS, &metadata.iosb.u.Status, .acquire) != .PENDING; |
| 2727 | switch (operations[op]) { |
| 2728 | .noop => unreachable, |
| 2729 | .file_read_streaming => |*o| { |
| 2730 | assert(o.status.pending == b); |
| 2731 | if (!done) continue; |
| 2732 | o.status = .{ .result = ntReadFileResult(&metadata.iosb) }; |
| 2733 | }, |
| 2734 | } |
| 2735 | any_done = true; |
| 2736 | metadata.pending = false; |
| 2737 | submitComplete(ring, &complete_tail, op); |
| 2738 | } |
| 2739 | if (any_done) return; |
| 2740 | if (!any_pending) return; |
| 2692 | 2741 | } |
| 2693 | 2742 | } |
| 2694 | 2743 | |
| 2744 | fn submitComplete(ring: []u32, complete_tail: *Io.Batch.RingIndex, op: u32) void { |
| 2745 | const ct = complete_tail.*; |
| 2746 | const len: u31 = @intCast(ring.len); |
| 2747 | ring[ct.index(len)] = op; |
| 2748 | complete_tail.* = ct.next(len); |
| 2749 | } |
| 2750 | |
| 2695 | 2751 | const dirCreateDir = switch (native_os) { |
| 2696 | 2752 | .windows => dirCreateDirWindows, |
| 2697 | 2753 | .wasi => dirCreateDirWasi, |
| ... | ... | @@ -5529,7 +5585,7 @@ fn dirRealPathFileWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, |
| 5529 | 5585 | |
| 5530 | 5586 | fn realPathWindows(h_file: windows.HANDLE, out_buffer: []u8) File.RealPathError!usize { |
| 5531 | 5587 | var wide_buf: [windows.PATH_MAX_WIDE]u16 = undefined; |
| 5532 | | // TODO move GetFinalPathNameByHandle logic into std.Io.Threaded and add cancel checks |
| 5588 | // TODO move GetFinalPathNameByHandle logic into Io.Threaded and add cancel checks |
| 5533 | 5589 | try Thread.checkCancel(); |
| 5534 | 5590 | const wide_slice = try windows.GetFinalPathNameByHandle(h_file, .{}, &wide_buf); |
| 5535 | 5591 | |
| ... | ... | @@ -8617,75 +8673,88 @@ fn fileReadStreamingPosix(file: File, data: []const []u8) File.Reader.Error!usiz |
| 8617 | 8673 | } |
| 8618 | 8674 | |
| 8619 | 8675 | fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!usize { |
| 8676 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 8677 | if (ntReadFile(file.handle, data, &io_status_block)) |result| switch (result) { |
| 8678 | .status => return ntReadFileResult(&io_status_block), |
| 8679 | .pending => { |
| 8680 | // Once we get here we received PENDING so we must not return from the |
| 8681 | // function until the operation completes. |
| 8682 | defer while (@atomicLoad(windows.NTSTATUS, &io_status_block.u.Status, .acquire) == .PENDING) { |
| 8683 | waitForApcOrAlert(); |
| 8684 | }; |
| 8685 | |
| 8686 | const alertable_syscall = AlertableSyscall.start() catch |err| switch (err) { |
| 8687 | error.Canceled => |e| { |
| 8688 | _ = windows.ntdll.NtCancelIoFile(file.handle, &io_status_block); |
| 8689 | return e; |
| 8690 | }, |
| 8691 | }; |
| 8692 | defer alertable_syscall.finish(); |
| 8693 | waitForApcOrAlert(); |
| 8694 | while (@atomicLoad(windows.NTSTATUS, &io_status_block.u.Status, .acquire) == .PENDING) { |
| 8695 | alertable_syscall.checkCancel() catch |err| switch (err) { |
| 8696 | error.Canceled => |e| { |
| 8697 | _ = windows.ntdll.NtCancelIoFile(file.handle, &io_status_block); |
| 8698 | return e; |
| 8699 | }, |
| 8700 | }; |
| 8701 | waitForApcOrAlert(); |
| 8702 | } |
| 8703 | }, |
| 8704 | } else |err| return err; |
| 8705 | return ntReadFileResult(&io_status_block); |
| 8706 | } |
| 8707 | |
| 8708 | fn ntReadFileResult(io_status_block: *windows.IO_STATUS_BLOCK) !usize { |
| 8709 | switch (io_status_block.u.Status) { |
| 8710 | .SUCCESS, .END_OF_FILE, .PIPE_BROKEN => return io_status_block.Information, |
| 8711 | .PENDING => unreachable, |
| 8712 | .INVALID_DEVICE_REQUEST => return error.IsDir, |
| 8713 | .LOCK_NOT_GRANTED => return error.LockViolation, |
| 8714 | .ACCESS_DENIED => return error.AccessDenied, |
| 8715 | else => |status| return windows.unexpectedStatus(status), |
| 8716 | } |
| 8717 | } |
| 8718 | |
| 8719 | fn ntReadFile(handle: windows.HANDLE, data: []const []u8, iosb: *windows.IO_STATUS_BLOCK) Io.Cancelable!enum { status, pending } { |
| 8620 | 8720 | var index: usize = 0; |
| 8621 | 8721 | while (index < data.len and data[index].len == 0) index += 1; |
| 8622 | | if (index == data.len) return 0; |
| 8722 | if (index == data.len) { |
| 8723 | iosb.u.Status = .SUCCESS; |
| 8724 | iosb.Information = 0; |
| 8725 | return .status; |
| 8726 | } |
| 8623 | 8727 | const buffer = data[index]; |
| 8624 | 8728 | |
| 8625 | | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 8626 | 8729 | const syscall: Syscall = try .start(); |
| 8627 | 8730 | while (true) { |
| 8628 | | io_status_block.u.Status = .PENDING; |
| 8731 | iosb.u.Status = .PENDING; |
| 8629 | 8732 | switch (windows.ntdll.NtReadFile( |
| 8630 | | file.handle, |
| 8733 | handle, |
| 8631 | 8734 | null, // event |
| 8632 | 8735 | noopApc, // apc callback |
| 8633 | 8736 | null, // apc context |
| 8634 | | &io_status_block, |
| 8737 | iosb, |
| 8635 | 8738 | buffer.ptr, |
| 8636 | 8739 | @min(std.math.maxInt(u32), buffer.len), |
| 8637 | 8740 | null, // byte offset |
| 8638 | 8741 | null, // key |
| 8639 | 8742 | )) { |
| 8640 | | .SUCCESS, .END_OF_FILE, .PIPE_BROKEN => { |
| 8743 | .PENDING => { |
| 8641 | 8744 | syscall.finish(); |
| 8642 | | return io_status_block.Information; |
| 8745 | return .pending; |
| 8643 | 8746 | }, |
| 8644 | | .PENDING => break, |
| 8645 | 8747 | .CANCELLED => { |
| 8646 | 8748 | try syscall.checkCancel(); |
| 8647 | 8749 | continue; |
| 8648 | 8750 | }, |
| 8649 | | .INVALID_DEVICE_REQUEST => return syscall.fail(error.IsDir), |
| 8650 | | .LOCK_NOT_GRANTED => return syscall.fail(error.LockViolation), |
| 8651 | | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), |
| 8652 | | .INVALID_PARAMETER => |err| return syscall.ntstatusBug(err), // streaming read of async mode file |
| 8653 | | else => |status| return syscall.unexpectedNtstatus(status), |
| 8654 | | } |
| 8655 | | } |
| 8656 | | { |
| 8657 | | // Once we get here we received PENDING so we must not return from the |
| 8658 | | // function until the operation completes. |
| 8659 | | defer while (@atomicLoad(windows.NTSTATUS, &io_status_block.u.Status, .acquire) == .PENDING) { |
| 8660 | | waitForApcOrAlert(); |
| 8661 | | }; |
| 8662 | | |
| 8663 | | const alertable_syscall = syscall.toAlertable() catch |err| switch (err) { |
| 8664 | | error.Canceled => |e| { |
| 8665 | | _ = windows.ntdll.NtCancelIoFile(file.handle, &io_status_block); |
| 8666 | | return e; |
| 8751 | else => |status| { |
| 8752 | syscall.finish(); |
| 8753 | iosb.u.Status = status; |
| 8754 | return .status; |
| 8667 | 8755 | }, |
| 8668 | | }; |
| 8669 | | defer alertable_syscall.finish(); |
| 8670 | | waitForApcOrAlert(); |
| 8671 | | while (@atomicLoad(windows.NTSTATUS, &io_status_block.u.Status, .acquire) == .PENDING) { |
| 8672 | | alertable_syscall.checkCancel() catch |err| switch (err) { |
| 8673 | | error.Canceled => |e| { |
| 8674 | | _ = windows.ntdll.NtCancelIoFile(file.handle, &io_status_block); |
| 8675 | | return e; |
| 8676 | | }, |
| 8677 | | }; |
| 8678 | | waitForApcOrAlert(); |
| 8679 | 8756 | } |
| 8680 | 8757 | } |
| 8681 | | switch (io_status_block.u.Status) { |
| 8682 | | .SUCCESS, .END_OF_FILE, .PIPE_BROKEN => return io_status_block.Information, |
| 8683 | | .PENDING => unreachable, // cannot return until the operation completes |
| 8684 | | .INVALID_DEVICE_REQUEST => return error.IsDir, |
| 8685 | | .LOCK_NOT_GRANTED => return error.LockViolation, |
| 8686 | | .ACCESS_DENIED => return error.AccessDenied, |
| 8687 | | else => |status| return windows.unexpectedStatus(status), |
| 8688 | | } |
| 8689 | 8758 | } |
| 8690 | 8759 | |
| 8691 | 8760 | fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize { |
| ... | ... | @@ -9318,7 +9387,7 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut |
| 9318 | 9387 | }; |
| 9319 | 9388 | defer w.CloseHandle(h_file); |
| 9320 | 9389 | |
| 9321 | | // TODO move GetFinalPathNameByHandle logic into std.Io.Threaded and add cancel checks |
| 9390 | // TODO move GetFinalPathNameByHandle logic into Io.Threaded and add cancel checks |
| 9322 | 9391 | try Thread.checkCancel(); |
| 9323 | 9392 | const wide_slice = try w.GetFinalPathNameByHandle(h_file, .{}, &path_name_w_buf.data); |
| 9324 | 9393 | |
| ... | ... | @@ -12989,7 +13058,7 @@ fn processSetCurrentDir(userdata: ?*anyopaque, dir: Dir) process.SetCurrentDirEr |
| 12989 | 13058 | |
| 12990 | 13059 | if (is_windows) { |
| 12991 | 13060 | var dir_path_buffer: [windows.PATH_MAX_WIDE]u16 = undefined; |
| 12992 | | // TODO move GetFinalPathNameByHandle logic into std.Io.Threaded and add cancel checks |
| 13061 | // TODO move GetFinalPathNameByHandle logic into Io.Threaded and add cancel checks |
| 12993 | 13062 | try Thread.checkCancel(); |
| 12994 | 13063 | const dir_path = try windows.GetFinalPathNameByHandle(dir.handle, .{}, &dir_path_buffer); |
| 12995 | 13064 | const path_len_bytes = std.math.cast(u16, dir_path.len * 2) orelse return error.NameTooLong; |
| ... | ... | @@ -16657,7 +16726,7 @@ const parking_sleep = struct { |
| 16657 | 16726 | /// Spurious wakeups are possible. |
| 16658 | 16727 | /// |
| 16659 | 16728 | /// `addr_hint` has no semantic effect, but may allow the OS to optimize this operation. |
| 16660 | | fn park(opt_deadline: ?std.Io.Clock.Timestamp, addr_hint: ?*const anyopaque) error{Timeout}!void { |
| 16729 | fn park(opt_deadline: ?Io.Clock.Timestamp, addr_hint: ?*const anyopaque) error{Timeout}!void { |
| 16661 | 16730 | comptime assert(use_parking_futex or use_parking_sleep); |
| 16662 | 16731 | switch (native_os) { |
| 16663 | 16732 | .windows => { |
| ... | ... | @@ -16713,6 +16782,23 @@ fn park(opt_deadline: ?std.Io.Clock.Timestamp, addr_hint: ?*const anyopaque) err |
| 16713 | 16782 | } |
| 16714 | 16783 | } |
| 16715 | 16784 | |
| 16785 | fn timeoutToWindowsInterval(timeout: Io.Timeout) windows.LARGE_INTEGER { |
| 16786 | switch (timeout) { |
| 16787 | .none => { |
| 16788 | return std.math.minInt(windows.LARGE_INTEGER); // infinite timeout |
| 16789 | }, |
| 16790 | .deadline => |deadline| { |
| 16791 | const nanoseconds = deadline.raw.nanoseconds; |
| 16792 | return @intCast(@divTrunc(nanoseconds, 100)); |
| 16793 | }, |
| 16794 | .duration => |duration| { |
| 16795 | const now_timestamp = nowWindows(duration.clock) catch unreachable; |
| 16796 | const deadline_ns = now_timestamp.nanoseconds + duration.raw.nanoseconds; |
| 16797 | return @intCast(@divTrunc(deadline_ns, 100)); |
| 16798 | }, |
| 16799 | } |
| 16800 | } |
| 16801 | |
| 16716 | 16802 | const UnparkTid = switch (native_os) { |
| 16717 | 16803 | // `NtAlertMultipleThreadByThreadId` is weird and wants 64-bit thread handles? |
| 16718 | 16804 | .windows => usize, |