| ... | ... | @@ -2649,7 +2649,7 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper |
| 2649 | 2649 | fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void { |
| 2650 | 2650 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2651 | 2651 | if (is_windows) { |
| 2652 | | batchDrainSubmittedWindows(b, false) catch |err| switch (err) { |
| 2652 | batchDrainSubmittedWindows(t, b, false) catch |err| switch (err) { |
| 2653 | 2653 | error.ConcurrencyUnavailable => unreachable, // passed concurrency=false |
| 2654 | 2654 | else => |e| return e, |
| 2655 | 2655 | }; |
| ... | ... | @@ -2789,7 +2789,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout |
| 2789 | 2789 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2790 | 2790 | if (is_windows) { |
| 2791 | 2791 | const deadline: ?Io.Clock.Timestamp = timeout.toTimestamp(ioBasic(t)); |
| 2792 | | try batchDrainSubmittedWindows(b, true); |
| 2792 | try batchDrainSubmittedWindows(t, b, true); |
| 2793 | 2793 | while (b.pending.head != .none and b.completed.head == .none) { |
| 2794 | 2794 | var delay_interval: windows.LARGE_INTEGER = interval: { |
| 2795 | 2795 | const d = deadline orelse break :interval std.math.minInt(windows.LARGE_INTEGER); |
| ... | ... | @@ -3005,6 +3005,31 @@ fn batchCancel(userdata: ?*anyopaque, b: *Io.Batch) void { |
| 3005 | 3005 | } |
| 3006 | 3006 | } |
| 3007 | 3007 | |
| 3008 | fn batchCompleteBlockingWindows( |
| 3009 | b: *Io.Batch, |
| 3010 | operation_userdata: *WindowsBatchOperationUserdata, |
| 3011 | result: Io.Operation.Result, |
| 3012 | ) void { |
| 3013 | const erased_userdata = operation_userdata.toErased(); |
| 3014 | const pending: *Io.Operation.Storage.Pending = @fieldParentPtr("userdata", erased_userdata); |
| 3015 | switch (pending.node.prev) { |
| 3016 | .none => b.pending.head = pending.node.next, |
| 3017 | else => |prev_index| b.storage[prev_index.toIndex()].pending.node.next = pending.node.next, |
| 3018 | } |
| 3019 | switch (pending.node.next) { |
| 3020 | .none => b.pending.tail = pending.node.prev, |
| 3021 | else => |next_index| b.storage[next_index.toIndex()].pending.node.prev = pending.node.prev, |
| 3022 | } |
| 3023 | const storage: *Io.Operation.Storage = @fieldParentPtr("pending", pending); |
| 3024 | const index: Io.Operation.OptionalIndex = .fromIndex(storage - b.storage.ptr); |
| 3025 | switch (b.completed.tail) { |
| 3026 | .none => b.completed.head = index, |
| 3027 | else => |tail_index| b.storage[tail_index.toIndex()].completion.node.next = index, |
| 3028 | } |
| 3029 | b.completed.tail = index; |
| 3030 | storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } }; |
| 3031 | } |
| 3032 | |
| 3008 | 3033 | fn batchApc( |
| 3009 | 3034 | apc_context: ?*anyopaque, |
| 3010 | 3035 | iosb: *windows.IO_STATUS_BLOCK, |
| ... | ... | @@ -3044,7 +3069,7 @@ fn batchApc( |
| 3044 | 3069 | .file_read_streaming => .{ .file_read_streaming = ntReadFileResult(iosb) }, |
| 3045 | 3070 | .file_write_streaming => .{ .file_write_streaming = ntWriteFileResult(iosb) }, |
| 3046 | 3071 | .device_io_control => .{ .device_io_control = iosb.* }, |
| 3047 | | .net_receive => unreachable, // TODO |
| 3072 | .net_receive => unreachable, |
| 3048 | 3073 | }; |
| 3049 | 3074 | storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } }; |
| 3050 | 3075 | }, |
| ... | ... | @@ -3052,7 +3077,7 @@ fn batchApc( |
| 3052 | 3077 | } |
| 3053 | 3078 | |
| 3054 | 3079 | /// If `concurrency` is false, `error.ConcurrencyUnavailable` is unreachable. |
| 3055 | | fn batchDrainSubmittedWindows(b: *Io.Batch, concurrency: bool) (Io.ConcurrentError || Io.Cancelable)!void { |
| 3080 | fn batchDrainSubmittedWindows(t: *Threaded, b: *Io.Batch, concurrency: bool) (Io.ConcurrentError || Io.Cancelable)!void { |
| 3056 | 3081 | var index = b.submitted.head; |
| 3057 | 3082 | errdefer b.submitted.head = index; |
| 3058 | 3083 | while (index != .none) { |
| ... | ... | @@ -3246,10 +3271,12 @@ fn batchDrainSubmittedWindows(b: *Io.Batch, concurrency: bool) (Io.ConcurrentErr |
| 3246 | 3271 | }; |
| 3247 | 3272 | } |
| 3248 | 3273 | }, |
| 3249 | | .net_receive => |o| { |
| 3274 | .net_receive => |*o| { |
| 3275 | // TODO integrate with overlapped I/O or equivalent to avoid this error |
| 3250 | 3276 | if (concurrency) return error.ConcurrencyUnavailable; |
| 3251 | | _ = o; |
| 3252 | | @panic("TODO implement Batch NetReceive on Windows"); |
| 3277 | batchCompleteBlockingWindows(b, operation_userdata, .{ |
| 3278 | .net_receive = netReceiveWindows(t, o.socket_handle, o.message_buffer, o.data_buffer, o.flags), |
| 3279 | }); |
| 3253 | 3280 | }, |
| 3254 | 3281 | } |
| 3255 | 3282 | index = submission.node.next; |
| ... | ... | @@ -13323,13 +13350,89 @@ fn netReceiveWindows( |
| 13323 | 13350 | data_buffer: []u8, |
| 13324 | 13351 | flags: net.ReceiveFlags, |
| 13325 | 13352 | ) struct { ?net.Socket.ReceiveError, usize } { |
| 13326 | | if (!have_networking) return .{ error.NetworkDown, 0 }; |
| 13327 | | _ = t; |
| 13328 | | _ = socket_handle; |
| 13329 | | _ = message_buffer; |
| 13330 | | _ = data_buffer; |
| 13331 | | _ = flags; |
| 13332 | | @panic("TODO implement netReceiveWindows"); |
| 13353 | netReceiveWindowsOne(t, socket_handle, &message_buffer[0], data_buffer, flags) catch |err| return .{ err, 0 }; |
| 13354 | return .{ null, 1 }; |
| 13355 | } |
| 13356 | |
| 13357 | fn netReceiveWindowsOne( |
| 13358 | t: *Threaded, |
| 13359 | socket_handle: net.Socket.Handle, |
| 13360 | message: *net.IncomingMessage, |
| 13361 | data_buffer: []u8, |
| 13362 | flags: net.ReceiveFlags, |
| 13363 | ) net.Socket.ReceiveError!void { |
| 13364 | comptime assert(have_networking); |
| 13365 | |
| 13366 | var windows_flags: u32 = |
| 13367 | @as(u32, if (flags.oob) ws2_32.MSG.OOB else 0) | |
| 13368 | @as(u32, if (flags.peek) ws2_32.MSG.PEEK else 0) | |
| 13369 | @as(u32, if (flags.trunc) ws2_32.MSG.TRUNC else 0); |
| 13370 | |
| 13371 | var buf: ws2_32.WSABUF = .{ |
| 13372 | .buf = data_buffer.ptr, |
| 13373 | .len = std.math.cast(u32, data_buffer.len) orelse return error.MessageOversize, |
| 13374 | }; |
| 13375 | var n: u32 = undefined; |
| 13376 | var syscall: Syscall = try .start(); |
| 13377 | var from_storage: WsaAddress = undefined; |
| 13378 | var from_storage_len: i32 = @sizeOf(WsaAddress); |
| 13379 | |
| 13380 | while (true) { |
| 13381 | const rc = ws2_32.WSARecvFrom( |
| 13382 | socket_handle, |
| 13383 | (&buf)[0..1], |
| 13384 | 1, |
| 13385 | &n, |
| 13386 | &windows_flags, |
| 13387 | &from_storage.any, |
| 13388 | &from_storage_len, |
| 13389 | null, |
| 13390 | null, |
| 13391 | ); |
| 13392 | if (rc != ws2_32.SOCKET_ERROR) { |
| 13393 | syscall.finish(); |
| 13394 | message.* = .{ |
| 13395 | .from = addressFromWsa(&from_storage), |
| 13396 | .data = data_buffer[0..n], |
| 13397 | .control = &.{}, |
| 13398 | .flags = .{ |
| 13399 | .eor = false, |
| 13400 | .trunc = (windows_flags & ws2_32.MSG.TRUNC) != 0, |
| 13401 | .ctrunc = (windows_flags & ws2_32.MSG.CTRUNC) != 0, |
| 13402 | .oob = false, |
| 13403 | .errqueue = false, |
| 13404 | }, |
| 13405 | }; |
| 13406 | return; |
| 13407 | } |
| 13408 | switch (ws2_32.WSAGetLastError()) { |
| 13409 | .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { |
| 13410 | try syscall.checkCancel(); |
| 13411 | continue; |
| 13412 | }, |
| 13413 | .NOTINITIALISED => { |
| 13414 | syscall.finish(); |
| 13415 | try initializeWsa(t); |
| 13416 | syscall = try .start(); |
| 13417 | continue; |
| 13418 | }, |
| 13419 | |
| 13420 | .ECONNRESET => return syscall.fail(error.ConnectionResetByPeer), |
| 13421 | .ENETDOWN => return syscall.fail(error.NetworkDown), |
| 13422 | .ENETRESET => return syscall.fail(error.ConnectionResetByPeer), |
| 13423 | .ENOTCONN => return syscall.fail(error.SocketUnconnected), |
| 13424 | .EFAULT => unreachable, // a pointer is not completely contained in user address space. |
| 13425 | |
| 13426 | else => |err| { |
| 13427 | syscall.finish(); |
| 13428 | switch (err) { |
| 13429 | .EINVAL => return wsaErrorBug(err), |
| 13430 | .EMSGSIZE => return wsaErrorBug(err), |
| 13431 | else => return windows.unexpectedWSAError(err), |
| 13432 | } |
| 13433 | }, |
| 13434 | } |
| 13435 | } |
| 13333 | 13436 | } |
| 13334 | 13437 | |
| 13335 | 13438 | fn netReceiveUnavailable( |