| ... | @@ -28,6 +28,7 @@ fn logImpl( | ... | @@ -28,6 +28,7 @@ fn logImpl( |
| 28 | } | 28 | } |
| 29 | | 29 | |
| 30 | pub fn main(init: std.process.Init) !void { | 30 | pub fn main(init: std.process.Init) !void { |
| | 31 | const gpa = init.gpa; |
| 31 | const fatal = std.process.fatal; | 32 | const fatal = std.process.fatal; |
| 32 | const arena = init.arena.allocator(); | 33 | const arena = init.arena.allocator(); |
| 33 | const io = init.io; | 34 | const io = init.io; |
| ... | @@ -224,11 +225,10 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -224,11 +225,10 @@ pub fn main(init: std.process.Init) !void { |
| 224 | .enable_darling = enable_darling, | 225 | .enable_darling = enable_darling, |
| 225 | }; | 226 | }; |
| 226 | | 227 | |
| 227 | var poller = Io.poll(arena, Eval.StreamEnum, .{ | 228 | var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined; |
| 228 | .stdout = child.stdout.?, | 229 | var multi_reader: Io.File.MultiReader = undefined; |
| 229 | .stderr = child.stderr.?, | 230 | multi_reader.init(gpa, io, multi_reader_buffer.toStreams(), &.{ child.stdout.?, child.stderr.? }); |
| 230 | }); | 231 | defer multi_reader.deinit(); |
| 231 | defer poller.deinit(); | | |
| 232 | | 232 | |
| 233 | for (case.updates) |update| { | 233 | for (case.updates) |update| { |
| 234 | var update_node = target_prog_node.start(update.name, 0); | 234 | var update_node = target_prog_node.start(update.name, 0); |
| ... | @@ -243,10 +243,10 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -243,10 +243,10 @@ pub fn main(init: std.process.Init) !void { |
| 243 | | 243 | |
| 244 | eval.write(update); | 244 | eval.write(update); |
| 245 | try eval.requestUpdate(); | 245 | try eval.requestUpdate(); |
| 246 | try eval.check(&poller, update, update_node); | 246 | try eval.check(&multi_reader, update, update_node); |
| 247 | } | 247 | } |
| 248 | | 248 | |
| 249 | try eval.end(&poller); | 249 | try eval.end(&multi_reader); |
| 250 | | 250 | |
| 251 | waitChild(&child, &eval); | 251 | waitChild(&child, &eval); |
| 252 | } | 252 | } |
| ... | @@ -272,9 +272,6 @@ const Eval = struct { | ... | @@ -272,9 +272,6 @@ const Eval = struct { |
| 272 | enable_wasmtime: bool, | 272 | enable_wasmtime: bool, |
| 273 | enable_darling: bool, | 273 | enable_darling: bool, |
| 274 | | 274 | |
| 275 | const StreamEnum = enum { stdout, stderr }; | | |
| 276 | const Poller = Io.Poller(StreamEnum); | | |
| 277 | | | |
| 278 | /// Currently this function assumes the previous updates have already been written. | 275 | /// Currently this function assumes the previous updates have already been written. |
| 279 | fn write(eval: *Eval, update: Case.Update) void { | 276 | fn write(eval: *Eval, update: Case.Update) void { |
| 280 | const io = eval.io; | 277 | const io = eval.io; |
| ... | @@ -293,23 +290,29 @@ const Eval = struct { | ... | @@ -293,23 +290,29 @@ const Eval = struct { |
| 293 | } | 290 | } |
| 294 | } | 291 | } |
| 295 | | 292 | |
| 296 | fn check(eval: *Eval, poller: *Poller, update: Case.Update, prog_node: std.Progress.Node) !void { | 293 | fn check(eval: *Eval, mr: *Io.File.MultiReader, update: Case.Update, prog_node: std.Progress.Node) !void { |
| 297 | const arena = eval.arena; | 294 | const arena = eval.arena; |
| 298 | const stdout = poller.reader(.stdout); | 295 | const stdout = mr.fileReader(0); |
| 299 | const stderr = poller.reader(.stderr); | 296 | const stderr = &mr.fileReader(1).interface; |
| 300 | | 297 | const Header = std.zig.Server.Message.Header; |
| 301 | poll: while (true) { | 298 | |
| 302 | const Header = std.zig.Server.Message.Header; | 299 | while (true) { |
| 303 | while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll; | 300 | const header = stdout.interface.takeStruct(Header, .little) catch |err| switch (err) { |
| 304 | const header = stdout.takeStruct(Header, .little) catch unreachable; | 301 | error.EndOfStream => break, |
| 305 | while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll; | 302 | error.ReadFailed => return stdout.err.?, |
| 306 | const body = stdout.take(header.bytes_len) catch unreachable; | 303 | }; |
| | 304 | const body = stdout.interface.take(header.bytes_len) catch |err| switch (err) { |
| | 305 | // If this panic triggers it might be helpful to rework this |
| | 306 | // code to print the stderr from the abnormally terminated child. |
| | 307 | error.EndOfStream => @panic("unexpected mid-message end of stream"), |
| | 308 | error.ReadFailed => return stdout.err.?, |
| | 309 | }; |
| 307 | | 310 | |
| 308 | switch (header.tag) { | 311 | switch (header.tag) { |
| 309 | .error_bundle => { | 312 | .error_bundle => { |
| 310 | const result_error_bundle = try std.zig.Server.allocErrorBundle(arena, body); | 313 | const result_error_bundle = try std.zig.Server.allocErrorBundle(arena, body); |
| 311 | if (stderr.bufferedLen() > 0) { | 314 | if (stderr.bufferedLen() > 0) { |
| 312 | const stderr_data = try poller.toOwnedSlice(.stderr); | 315 | const stderr_data = try mr.toOwnedSlice(1); |
| 313 | if (eval.allow_stderr) { | 316 | if (eval.allow_stderr) { |
| 314 | std.log.info("error_bundle stderr:\n{s}", .{stderr_data}); | 317 | std.log.info("error_bundle stderr:\n{s}", .{stderr_data}); |
| 315 | } else { | 318 | } else { |
| ... | @@ -326,7 +329,7 @@ const Eval = struct { | ... | @@ -326,7 +329,7 @@ const Eval = struct { |
| 326 | var r: std.Io.Reader = .fixed(body); | 329 | var r: std.Io.Reader = .fixed(body); |
| 327 | _ = r.takeStruct(std.zig.Server.Message.EmitDigest, .little) catch unreachable; | 330 | _ = r.takeStruct(std.zig.Server.Message.EmitDigest, .little) catch unreachable; |
| 328 | if (stderr.bufferedLen() > 0) { | 331 | if (stderr.bufferedLen() > 0) { |
| 329 | const stderr_data = try poller.toOwnedSlice(.stderr); | 332 | const stderr_data = try mr.toOwnedSlice(1); |
| 330 | if (eval.allow_stderr) { | 333 | if (eval.allow_stderr) { |
| 331 | std.log.info("emit_digest stderr:\n{s}", .{stderr_data}); | 334 | std.log.info("emit_digest stderr:\n{s}", .{stderr_data}); |
| 332 | } else { | 335 | } else { |
| ... | @@ -358,11 +361,12 @@ const Eval = struct { | ... | @@ -358,11 +361,12 @@ const Eval = struct { |
| 358 | } | 361 | } |
| 359 | } | 362 | } |
| 360 | | 363 | |
| 361 | if (stderr.bufferedLen() > 0) { | 364 | const buffered_stderr = stderr.buffered(); |
| | 365 | if (buffered_stderr.len > 0) { |
| 362 | if (eval.allow_stderr) { | 366 | if (eval.allow_stderr) { |
| 363 | std.log.info("stderr:\n{s}", .{stderr.buffered()}); | 367 | std.log.info("stderr:\n{s}", .{buffered_stderr}); |
| 364 | } else { | 368 | } else { |
| 365 | eval.fatal("unexpected stderr:\n{s}", .{stderr.buffered()}); | 369 | eval.fatal("unexpected stderr:\n{s}", .{buffered_stderr}); |
| 366 | } | 370 | } |
| 367 | } | 371 | } |
| 368 | | 372 | |
| ... | @@ -588,23 +592,27 @@ const Eval = struct { | ... | @@ -588,23 +592,27 @@ const Eval = struct { |
| 588 | }; | 592 | }; |
| 589 | } | 593 | } |
| 590 | | 594 | |
| 591 | fn end(eval: *Eval, poller: *Poller) !void { | 595 | fn end(eval: *Eval, mr: *Io.File.MultiReader) !void { |
| 592 | requestExit(eval.child, eval); | 596 | requestExit(eval.child, eval); |
| 593 | | 597 | |
| 594 | const stdout = poller.reader(.stdout); | 598 | const stdout = mr.fileReader(0); |
| 595 | const stderr = poller.reader(.stderr); | 599 | const Header = std.zig.Server.Message.Header; |
| 596 | | 600 | |
| 597 | poll: while (true) { | 601 | while (true) { |
| 598 | const Header = std.zig.Server.Message.Header; | 602 | const header = stdout.interface.takeStruct(Header, .little) catch |err| switch (err) { |
| 599 | while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll; | 603 | error.EndOfStream => break, |
| 600 | const header = stdout.takeStruct(Header, .little) catch unreachable; | 604 | error.ReadFailed => return stdout.err.?, |
| 601 | while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll; | 605 | }; |
| 602 | stdout.toss(header.bytes_len); | 606 | stdout.interface.discardAll(header.bytes_len) catch |err| switch (err) { |
| | 607 | error.ReadFailed => return stdout.err.?, |
| | 608 | error.EndOfStream => |e| return e, |
| | 609 | }; |
| 603 | } | 610 | } |
| 604 | | 611 | |
| 605 | if (stderr.bufferedLen() > 0) { | 612 | try mr.fillRemaining(.none); |
| 606 | eval.fatal("unexpected stderr:\n{s}", .{stderr.buffered()}); | 613 | |
| 607 | } | 614 | const stderr = mr.reader(1).buffered(); |
| | 615 | if (stderr.len > 0) eval.fatal("unexpected stderr:\n{s}", .{stderr}); |
| 608 | } | 616 | } |
| 609 | | 617 | |
| 610 | fn buildCOutput(eval: *Eval, c_path: []const u8, out_path: []const u8, prog_node: std.Progress.Node) !void { | 618 | fn buildCOutput(eval: *Eval, c_path: []const u8, out_path: []const u8, prog_node: std.Progress.Node) !void { |