authorgravatar for johnnymarler@gmail.comJonathan Marler <johnnymarler@gmail.com> 2022-02-06 15:20:15-07:00
committergravatar for johnnymarler@gmail.comJonathan Marler <johnnymarler@gmail.com> 2022-02-06 18:05:21-07:00
log4fddb591e2377186ef942084cae2e93d5de448b3
tree003a07c864bd2e64a5dbdccd0bc60ff878194422
parent8f830207c47987de9767130d54abff79c8ec257d

rework to allow ReadFile to complete synchronously


1 files changed, 36 insertions(+), 19 deletions(-)

lib/std/child_process.zig+36-19
......@@ -252,6 +252,33 @@ pub const ChildProcess = struct {
252252 }
253253 }
254254
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
255282 fn collectOutputWindows(child: *const ChildProcess, outs: [2]*std.ArrayList(u8), max_output_bytes: usize) !void {
256283 const bump_amt = 512;
257284 const handles = [_]windows.HANDLE{
......@@ -274,18 +301,13 @@ pub const ChildProcess = struct {
274301
275302 // Windows Async IO requires an initial call to ReadFile before waiting on the handle
276303 for ([_]u1{ 0, 1 }) |i| {
277 const new_capacity = std.math.min(outs[i].items.len + bump_amt, max_output_bytes);
278 try outs[i].ensureTotalCapacity(new_capacity);
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 => {
304 switch (try windowsAsyncRead(handles[i], &overlapped[i], outs[i], bump_amt, max_output_bytes)) {
305 .pending => {
284306 wait_objects[wait_object_count] = handles[i];
285307 wait_object_count += 1;
286308 },
287 .BROKEN_PIPE => {}, // don't add to the wait_objects list
288 else => |err| return windows.unexpectedError(err),
309 .closed => {}, // don't add to the wait_objects list
310 .full => return if (i == 0) error.StdoutStreamTooLong else error.StderrStreamTooLong,
289311 }
290312 }
291313
......@@ -319,19 +341,14 @@ pub const ChildProcess = struct {
319341 }
320342
321343 outs[i].items.len += read_bytes;
322 const new_capacity = std.math.min(outs[i].items.len + bump_amt, max_output_bytes);
323 try outs[i].ensureTotalCapacity(new_capacity);
324 const buf = outs[i].unusedCapacitySlice();
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 => {
344
345 switch (try windowsAsyncRead(handles[i], &overlapped[i], outs[i], bump_amt, max_output_bytes)) {
346 .pending => {
330347 wait_objects[wait_object_count] = handles[i];
331348 wait_object_count += 1;
332349 },
333 .BROKEN_PIPE => {}, // don't add to the wait_objects list
334 else => |err| return windows.unexpectedError(err),
350 .closed => {}, // don't add to the wait_objects list
351 .full => return if (i == 0) error.StdoutStreamTooLong else error.StderrStreamTooLong,
335352 }
336353 }
337354 }