| ... | ... | @@ -256,6 +256,35 @@ pub const ChildProcess = struct { |
| 256 | 256 | } |
| 257 | 257 | } |
| 258 | 258 | |
| 259 | const WindowsAsyncReadResult = enum { |
| 260 | pending, |
| 261 | closed, |
| 262 | full, |
| 263 | }; |
| 264 | |
| 265 | fn windowsAsyncRead( |
| 266 | handle: windows.HANDLE, |
| 267 | overlapped: *windows.OVERLAPPED, |
| 268 | buf: *std.ArrayList(u8), |
| 269 | bump_amt: usize, |
| 270 | max_output_bytes: usize, |
| 271 | ) !WindowsAsyncReadResult { |
| 272 | while (true) { |
| 273 | const new_capacity = std.math.min(buf.items.len + bump_amt, max_output_bytes); |
| 274 | try buf.ensureTotalCapacity(new_capacity); |
| 275 | const next_buf = buf.unusedCapacitySlice(); |
| 276 | if (next_buf.len == 0) return .full; |
| 277 | var read_bytes: u32 = undefined; |
| 278 | const read_result = windows.kernel32.ReadFile(handle, next_buf.ptr, math.cast(u32, next_buf.len) catch maxInt(u32), &read_bytes, overlapped); |
| 279 | if (read_result == 0) return switch (windows.kernel32.GetLastError()) { |
| 280 | .IO_PENDING => .pending, |
| 281 | .BROKEN_PIPE => .closed, |
| 282 | else => |err| windows.unexpectedError(err), |
| 283 | }; |
| 284 | buf.items.len += read_bytes; |
| 285 | } |
| 286 | } |
| 287 | |
| 259 | 288 | fn collectOutputWindows(child: *const ChildProcess, outs: [2]*std.ArrayList(u8), max_output_bytes: usize) !void { |
| 260 | 289 | const bump_amt = 512; |
| 261 | 290 | const handles = [_]windows.HANDLE{ |
| ... | ... | @@ -278,15 +307,17 @@ pub const ChildProcess = struct { |
| 278 | 307 | |
| 279 | 308 | // Windows Async IO requires an initial call to ReadFile before waiting on the handle |
| 280 | 309 | for ([_]u1{ 0, 1 }) |i| { |
| 281 | | const new_capacity = std.math.min(outs[i].items.len + bump_amt, max_output_bytes); |
| 282 | | try outs[i].ensureTotalCapacity(new_capacity); |
| 283 | | const buf = outs[i].unusedCapacitySlice(); |
| 284 | | _ = windows.kernel32.ReadFile(handles[i], buf.ptr, math.cast(u32, buf.len) catch maxInt(u32), null, &overlapped[i]); |
| 285 | | wait_objects[wait_object_count] = handles[i]; |
| 286 | | wait_object_count += 1; |
| 310 | switch (try windowsAsyncRead(handles[i], &overlapped[i], outs[i], bump_amt, max_output_bytes)) { |
| 311 | .pending => { |
| 312 | wait_objects[wait_object_count] = handles[i]; |
| 313 | wait_object_count += 1; |
| 314 | }, |
| 315 | .closed => {}, // don't add to the wait_objects list |
| 316 | .full => return if (i == 0) error.StdoutStreamTooLong else error.StderrStreamTooLong, |
| 317 | } |
| 287 | 318 | } |
| 288 | 319 | |
| 289 | | while (true) { |
| 320 | while (wait_object_count > 0) { |
| 290 | 321 | const status = windows.kernel32.WaitForMultipleObjects(wait_object_count, &wait_objects, 0, windows.INFINITE); |
| 291 | 322 | if (status == windows.WAIT_FAILED) { |
| 292 | 323 | switch (windows.kernel32.GetLastError()) { |
| ... | ... | @@ -310,23 +341,21 @@ pub const ChildProcess = struct { |
| 310 | 341 | var read_bytes: u32 = undefined; |
| 311 | 342 | if (windows.kernel32.GetOverlappedResult(handles[i], &overlapped[i], &read_bytes, 0) == 0) { |
| 312 | 343 | switch (windows.kernel32.GetLastError()) { |
| 313 | | .BROKEN_PIPE => { |
| 314 | | if (wait_object_count == 0) |
| 315 | | break; |
| 316 | | continue; |
| 317 | | }, |
| 344 | .BROKEN_PIPE => continue, |
| 318 | 345 | else => |err| return windows.unexpectedError(err), |
| 319 | 346 | } |
| 320 | 347 | } |
| 321 | 348 | |
| 322 | 349 | outs[i].items.len += read_bytes; |
| 323 | | const new_capacity = std.math.min(outs[i].items.len + bump_amt, max_output_bytes); |
| 324 | | try outs[i].ensureTotalCapacity(new_capacity); |
| 325 | | const buf = outs[i].unusedCapacitySlice(); |
| 326 | | if (buf.len == 0) return if (i == 0) error.StdoutStreamTooLong else error.StderrStreamTooLong; |
| 327 | | _ = windows.kernel32.ReadFile(handles[i], buf.ptr, math.cast(u32, buf.len) catch maxInt(u32), null, &overlapped[i]); |
| 328 | | wait_objects[wait_object_count] = handles[i]; |
| 329 | | wait_object_count += 1; |
| 350 | |
| 351 | switch (try windowsAsyncRead(handles[i], &overlapped[i], outs[i], bump_amt, max_output_bytes)) { |
| 352 | .pending => { |
| 353 | wait_objects[wait_object_count] = handles[i]; |
| 354 | wait_object_count += 1; |
| 355 | }, |
| 356 | .closed => {}, // don't add to the wait_objects list |
| 357 | .full => return if (i == 0) error.StdoutStreamTooLong else error.StderrStreamTooLong, |
| 358 | } |
| 330 | 359 | } |
| 331 | 360 | } |
| 332 | 361 | |