authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-10-21 16:54:38+02:00
committergravatar for johnnymarler@gmail.comJonathan Marler <johnnymarler@gmail.com> 2021-06-17 17:39:32-06:00
logb590195222ba560b8201f2344d7fcb398a43a504
treebe2a085b494c332bc39fed18414f229120661bb9
parent34c00ecf57a50e19b31fce420044311c4f2e9c7a

std: Uniform polling logic for Windows and Unix

Keep polling until there are enough open handles, if the child process terminates closing the handles or explicitly closes them we just quit polling and wait for the process handle to signal the termination condition.

1 files changed, 21 insertions(+), 28 deletions(-)

lib/std/child_process.zig+21-28
...@@ -258,11 +258,11 @@ pub const ChildProcess = struct {...@@ -258,11 +258,11 @@ pub const ChildProcess = struct {
258 }258 }
259259
260 fn collectOutputWindows(child: *const ChildProcess, stdout: *std.ArrayList(u8), stderr: *std.ArrayList(u8), max_output_bytes: usize) !void {260 fn collectOutputWindows(child: *const ChildProcess, stdout: *std.ArrayList(u8), stderr: *std.ArrayList(u8), max_output_bytes: usize) !void {
261 // The order of the objects here is important, WaitForMultipleObjects
262 // uses the same order when scanning the events.
263 var wait_objects = [_]windows.kernel32.HANDLE{261 var wait_objects = [_]windows.kernel32.HANDLE{
264 child.handle, child.stdout.?.handle, child.stderr.?.handle,262 child.stdout.?.handle, child.stderr.?.handle,
265 };263 };
264 var waiting_objects: u32 = wait_objects.len;
265
266 // XXX: Calling zeroes([2]windows.OVERLAPPED) causes the stage1 compiler266 // XXX: Calling zeroes([2]windows.OVERLAPPED) causes the stage1 compiler
267 // to crash and burn.267 // to crash and burn.
268 var overlapped = [_]windows.OVERLAPPED{268 var overlapped = [_]windows.OVERLAPPED{
...@@ -274,38 +274,31 @@ pub const ChildProcess = struct {...@@ -274,38 +274,31 @@ pub const ChildProcess = struct {
274 // Kickstart the loop by issuing two async reads.274 // Kickstart the loop by issuing two async reads.
275 // ReadFile returns false and GetLastError returns ERROR_IO_PENDING if275 // ReadFile returns false and GetLastError returns ERROR_IO_PENDING if
276 // everything is ok.276 // everything is ok.
277 _ = windows.kernel32.ReadFile(wait_objects[1], &temp_buf[0], temp_buf[0].len, null, &overlapped[0]);277 _ = windows.kernel32.ReadFile(wait_objects[0], &temp_buf[0], temp_buf[0].len, null, &overlapped[0]);
278 _ = windows.kernel32.ReadFile(wait_objects[2], &temp_buf[1], temp_buf[1].len, null, &overlapped[1]);278 _ = windows.kernel32.ReadFile(wait_objects[1], &temp_buf[1], temp_buf[1].len, null, &overlapped[1]);
279279
280 while (true) {280 poll: while (waiting_objects > 0) {
281 const status = windows.kernel32.WaitForMultipleObjects(wait_objects.len, &wait_objects, 0, windows.INFINITE);281 const status = windows.kernel32.WaitForMultipleObjects(waiting_objects, &wait_objects, 0, windows.INFINITE);
282 std.debug.print("status {x}\n", .{status});
283 switch (status) {282 switch (status) {
284 windows.WAIT_OBJECT_0 + 0 => {283 windows.WAIT_OBJECT_0 + 0...windows.WAIT_OBJECT_0 + 1 => {
285 // The child process was terminated.284 // stdout (or stderr) is ready.
286 break;285 const object = status - windows.WAIT_OBJECT_0;
287 },286
288 windows.WAIT_OBJECT_0 + 1 => {
289 // stdout is ready.
290 var read_bytes: u32 = undefined;
291 if (windows.kernel32.GetOverlappedResult(wait_objects[1], &overlapped[0], &read_bytes, 0) == 0) {
292 switch (windows.kernel32.GetLastError()) {
293 else => |err| return windows.unexpectedError(err),
294 }
295 }
296 try stdout.appendSlice(temp_buf[0][0..read_bytes]);
297 _ = windows.kernel32.ReadFile(wait_objects[1], &temp_buf[0], temp_buf[0].len, null, &overlapped[0]);
298 },
299 windows.WAIT_OBJECT_0 + 2 => {
300 // stderr is ready.
301 var read_bytes: u32 = undefined;287 var read_bytes: u32 = undefined;
302 if (windows.kernel32.GetOverlappedResult(wait_objects[2], &overlapped[1], &read_bytes, 0) == 0) {288 if (windows.kernel32.GetOverlappedResult(wait_objects[object], &overlapped[object], &read_bytes, 0) == 0) {
303 switch (windows.kernel32.GetLastError()) {289 switch (windows.kernel32.GetLastError()) {
290 .BROKEN_PIPE => {
291 // Move it to the end to remove it.
292 if (object != waiting_objects - 1)
293 mem.swap(windows.kernel32.HANDLE, &wait_objects[object], &wait_objects[waiting_objects - 1]);
294 waiting_objects -= 1;
295 continue :poll;
296 },
304 else => |err| return windows.unexpectedError(err),297 else => |err| return windows.unexpectedError(err),
305 }298 }
306 }299 }
307 try stdout.appendSlice(temp_buf[1][0..read_bytes]);300 try stdout.appendSlice(temp_buf[object][0..read_bytes]);
308 _ = windows.kernel32.ReadFile(wait_objects[2], &temp_buf[1], temp_buf[1].len, null, &overlapped[1]);301 _ = windows.kernel32.ReadFile(wait_objects[object], &temp_buf[object], temp_buf[object].len, null, &overlapped[object]);
309 },302 },
310 windows.WAIT_FAILED => {303 windows.WAIT_FAILED => {
311 switch (windows.kernel32.GetLastError()) {304 switch (windows.kernel32.GetLastError()) {