| ... | @@ -252,6 +252,33 @@ pub const ChildProcess = struct { | ... | @@ -252,6 +252,33 @@ pub const ChildProcess = struct { |
| 252 | } | 252 | } |
| 253 | } | 253 | } |
| 254 | | 254 | |
| | 255 | const WindowsAsyncReadResult = enum { |
| | 256 | pending, |
| | 257 | closed, |
| | 258 | full, |
| | 259 | }; |
| | 260 | |
| | 261 | fn windowsAsyncRead( |
| | 262 | handle: windows.HANDLE, |
| | 263 | overlapped: *windows.OVERLAPPED, |
| | 264 | buf: *std.ArrayList(u8), |
| | 265 | bump_amt: usize, |
| | 266 | max_output_bytes: usize, |
| | 267 | ) !WindowsAsyncReadResult { |
| | 268 | while (true) { |
| | 269 | const new_capacity = std.math.min(buf.items.len + bump_amt, max_output_bytes); |
| | 270 | try buf.ensureTotalCapacity(new_capacity); |
| | 271 | const next_buf = buf.unusedCapacitySlice(); |
| | 272 | if (next_buf.len == 0) return .full; |
| | 273 | const read_result = windows.kernel32.ReadFile(handle, next_buf.ptr, math.cast(u32, next_buf.len) catch maxInt(u32), null, overlapped); |
| | 274 | if (read_result == 0) return switch (windows.kernel32.GetLastError()) { |
| | 275 | .IO_PENDING => .pending, |
| | 276 | .BROKEN_PIPE => .closed, |
| | 277 | else => |err| windows.unexpectedError(err), |
| | 278 | }; |
| | 279 | } |
| | 280 | } |
| | 281 | |
| 255 | fn collectOutputWindows(child: *const ChildProcess, outs: [2]*std.ArrayList(u8), max_output_bytes: usize) !void { | 282 | fn collectOutputWindows(child: *const ChildProcess, outs: [2]*std.ArrayList(u8), max_output_bytes: usize) !void { |
| 256 | const bump_amt = 512; | 283 | const bump_amt = 512; |
| 257 | const handles = [_]windows.HANDLE{ | 284 | const handles = [_]windows.HANDLE{ |
| ... | @@ -274,18 +301,13 @@ pub const ChildProcess = struct { | ... | @@ -274,18 +301,13 @@ pub const ChildProcess = struct { |
| 274 | | 301 | |
| 275 | // Windows Async IO requires an initial call to ReadFile before waiting on the handle | 302 | // Windows Async IO requires an initial call to ReadFile before waiting on the handle |
| 276 | for ([_]u1{ 0, 1 }) |i| { | 303 | for ([_]u1{ 0, 1 }) |i| { |
| 277 | const new_capacity = std.math.min(outs[i].items.len + bump_amt, max_output_bytes); | 304 | switch (try windowsAsyncRead(handles[i], &overlapped[i], outs[i], bump_amt, max_output_bytes)) { |
| 278 | try outs[i].ensureTotalCapacity(new_capacity); | 305 | .pending => { |
| 279 | const buf = outs[i].unusedCapacitySlice(); | | |
| 280 | const read_result = windows.kernel32.ReadFile(handles[i], buf.ptr, math.cast(u32, buf.len) catch maxInt(u32), null, &overlapped[i]); | | |
| 281 | std.debug.assert(read_result == 0); | | |
| 282 | switch (windows.kernel32.GetLastError()) { | | |
| 283 | .IO_PENDING => { | | |
| 284 | wait_objects[wait_object_count] = handles[i]; | 306 | wait_objects[wait_object_count] = handles[i]; |
| 285 | wait_object_count += 1; | 307 | wait_object_count += 1; |
| 286 | }, | 308 | }, |
| 287 | .BROKEN_PIPE => {}, // don't add to the wait_objects list | 309 | .closed => {}, // don't add to the wait_objects list |
| 288 | else => |err| return windows.unexpectedError(err), | 310 | .full => return if (i == 0) error.StdoutStreamTooLong else error.StderrStreamTooLong, |
| 289 | } | 311 | } |
| 290 | } | 312 | } |
| 291 | | 313 | |
| ... | @@ -319,19 +341,14 @@ pub const ChildProcess = struct { | ... | @@ -319,19 +341,14 @@ pub const ChildProcess = struct { |
| 319 | } | 341 | } |
| 320 | | 342 | |
| 321 | outs[i].items.len += read_bytes; | 343 | outs[i].items.len += read_bytes; |
| 322 | const new_capacity = std.math.min(outs[i].items.len + bump_amt, max_output_bytes); | 344 | |
| 323 | try outs[i].ensureTotalCapacity(new_capacity); | 345 | switch (try windowsAsyncRead(handles[i], &overlapped[i], outs[i], bump_amt, max_output_bytes)) { |
| 324 | const buf = outs[i].unusedCapacitySlice(); | 346 | .pending => { |
| 325 | if (buf.len == 0) return if (i == 0) error.StdoutStreamTooLong else error.StderrStreamTooLong; | | |
| 326 | const read_result = windows.kernel32.ReadFile(handles[i], buf.ptr, math.cast(u32, buf.len) catch maxInt(u32), null, &overlapped[i]); | | |
| 327 | std.debug.assert(read_result == 0); | | |
| 328 | switch (windows.kernel32.GetLastError()) { | | |
| 329 | .IO_PENDING => { | | |
| 330 | wait_objects[wait_object_count] = handles[i]; | 347 | wait_objects[wait_object_count] = handles[i]; |
| 331 | wait_object_count += 1; | 348 | wait_object_count += 1; |
| 332 | }, | 349 | }, |
| 333 | .BROKEN_PIPE => {}, // don't add to the wait_objects list | 350 | .closed => {}, // don't add to the wait_objects list |
| 334 | else => |err| return windows.unexpectedError(err), | 351 | .full => return if (i == 0) error.StdoutStreamTooLong else error.StderrStreamTooLong, |
| 335 | } | 352 | } |
| 336 | } | 353 | } |
| 337 | } | 354 | } |