diff --git a/cmake/targets/BuildLibuv.cmake b/cmake/targets/BuildLibuv.cmake index af49601f33..76814059fa 100644 --- a/cmake/targets/BuildLibuv.cmake +++ b/cmake/targets/BuildLibuv.cmake @@ -4,7 +4,7 @@ register_repository( REPOSITORY oven-sh/libuv COMMIT - 537d74411e9a5587bc5c6dd9ca04a77976ecb120 + 271d173b6ebd4dfeb692862df2b03af48dcfb16b ) if(WIN32) diff --git a/repro-hell/beancounter.ts b/repro-hell/beancounter.ts new file mode 100644 index 0000000000..cb917e504c --- /dev/null +++ b/repro-hell/beancounter.ts @@ -0,0 +1,7 @@ +let count = 0; +process.stdin.on("data", chunk => { + count += chunk.length; +}); +process.stdin.on("end", () => { + console.log(count); +}); diff --git a/repro-hell/reader.ts b/repro-hell/reader.ts new file mode 100644 index 0000000000..bd57a04987 --- /dev/null +++ b/repro-hell/reader.ts @@ -0,0 +1 @@ +process.stdin.pipe(process.stdout); diff --git a/src/bun.js/api/bun/subprocess/StaticPipeWriter.zig b/src/bun.js/api/bun/subprocess/StaticPipeWriter.zig index 4679de7699..91c9213821 100644 --- a/src/bun.js/api/bun/subprocess/StaticPipeWriter.zig +++ b/src/bun.js/api/bun/subprocess/StaticPipeWriter.zig @@ -1,3 +1,5 @@ +const mlog = @import("../../../../mlog.zig").log; + pub fn NewStaticPipeWriter(comptime ProcessType: type) type { return struct { const This = @This(); @@ -35,6 +37,7 @@ pub fn NewStaticPipeWriter(comptime ProcessType: type) type { } pub fn close(this: *This) void { + mlog("StaticPipeWriter(0x{x}) close()\n", .{@intFromPtr(this)}); log("StaticPipeWriter(0x{x}) close()", .{@intFromPtr(this)}); this.writer.close(); } @@ -60,6 +63,7 @@ pub fn NewStaticPipeWriter(comptime ProcessType: type) type { } pub fn start(this: *This) bun.sys.Maybe(void) { + mlog("StaticPipeWriter(0x{x}) start()\n", .{@intFromPtr(this)}); log("StaticPipeWriter(0x{x}) start()", .{@intFromPtr(this)}); this.ref(); this.buffer = this.source.slice(); diff --git a/src/fd.zig b/src/fd.zig index f92459eba9..85213862d8 100644 --- a/src/fd.zig +++ b/src/fd.zig @@ -595,7 +595,10 @@ pub const FD = packed struct(backing_int) { pub const truncate = bun.sys.ftruncate; pub const unlinkat = bun.sys.unlinkat; pub const updateNonblocking = bun.sys.updateNonblocking; - pub const write = bun.sys.write; + const Error = @import("./sys/Error.zig"); + pub fn write(fd: bun.FileDescriptor, bytes: []const u8) bun.api.node.Maybe(usize, Error) { + return bun.sys.write(fd, bytes); + } pub const writeNonblocking = bun.sys.writeNonblocking; pub const writev = bun.sys.writev; diff --git a/src/io/PipeReader.zig b/src/io/PipeReader.zig index 628adf34e0..7a5ac5a289 100644 --- a/src/io/PipeReader.zig +++ b/src/io/PipeReader.zig @@ -1,3 +1,5 @@ +const mlog = @import("../mlog.zig").log; + // This is a runtime type instead of comptime due to bugs in Zig. // https://github.com/ziglang/zig/issues/18664 const BufferedReaderVTable = struct { @@ -923,6 +925,7 @@ pub const WindowsBufferedReader = struct { const nread_int = nread.int(); bun.sys.syslog("onStreamRead(0x{d}) = {d}", .{ @intFromPtr(this), nread_int }); + mlog("onStreamRead(0x{d}) = {d}\n", .{ @intFromPtr(this), nread_int }); // NOTE: pipes/tty need to call stopReading on errors (yeah) switch (nread_int) { diff --git a/src/mlog.zig b/src/mlog.zig new file mode 100644 index 0000000000..e29c8e2540 --- /dev/null +++ b/src/mlog.zig @@ -0,0 +1,70 @@ +const std = @import("std"); +const c = @cImport({ + @cInclude("stdlib.h"); +}); + +const Logger = struct { + var log_file: ?std.fs.File = null; + var proc_id: std.os.windows.DWORD = 0; + var name_buf: [64]u8 = undefined; + var name: []u8 = undefined; + + export fn cleanup() void { + if (Logger.log_file) |*file| { + file.sync() catch { + @panic("Failed to flush mlog.txt: {any}\n"); + }; + + file.close(); + Logger.log_file = null; + } + } + + fn getAndOpenFile() *std.fs.File { + if (Logger.log_file) |*file| { + return file; + } + + Logger.proc_id = std.os.windows.GetCurrentProcessId(); + + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + + var cwd = std.fs.cwd(); + + Logger.name = std.fmt.bufPrint(&name_buf, "mlog_{}.txt", .{Logger.proc_id}) catch { + @panic("Failed to format mlog filename: {any}\n"); + }; + + Logger.log_file = cwd.openFile(Logger.name, .{ + .mode = .read_write, + }) catch + cwd.createFile( + Logger.name, + .{ + .read = true, + .truncate = true, + }, + ) catch + @panic("Failed to create mlog.txt: {any}\n"); + + _ = c.atexit(cleanup); + + return &(Logger.log_file orelse unreachable); + } + + pub fn log(comptime fmt: []const u8, args: anytype) void { + const file = Logger.getAndOpenFile(); + + const writer = file.writer(); + + const nanos = std.time.nanoTimestamp(); + std.fmt.format(writer, "[{}] (pid {}) " ++ fmt, .{ nanos, Logger.proc_id } ++ args) catch { + @panic("Failed to write to mlog.txt: {any}\n"); + }; + + std.debug.print("Saved output to {s}.\n", .{name_buf}); + } +}; + +pub const log = Logger.log; diff --git a/src/shell/subproc.zig b/src/shell/subproc.zig index dd308b13e7..5f94dfc163 100644 --- a/src/shell/subproc.zig +++ b/src/shell/subproc.zig @@ -1,3 +1,4 @@ +const mlog = @import("../mlog.zig").log; // const IPC = @import("../bun.js/ipc.zig"); pub const Stdio = util.Stdio; @@ -1135,6 +1136,7 @@ pub const PipeReader = struct { this.process = process; this.event_loop = event_loop; if (Environment.isWindows) { + mlog("Starting with current pipe...\n", .{}); return this.reader.startWithCurrentPipe(); } @@ -1158,6 +1160,7 @@ pub const PipeReader = struct { pub const toJS = toReadableStream; pub fn onReadChunk(ptr: *anyopaque, chunk: []const u8, has_more: bun.io.ReadState) bool { + mlog("Reading a chunk...\n", .{}); var this: *PipeReader = @ptrCast(@alignCast(ptr)); this.buffered_output.append(chunk); log("PipeReader(0x{x}, {s}) onReadChunk(chunk_len={d}, has_more={s})", .{ @intFromPtr(this), @tagName(this.out_type), chunk.len, @tagName(has_more) }); @@ -1179,6 +1182,7 @@ pub const PipeReader = struct { } pub fn onReaderDone(this: *PipeReader) void { + mlog("The reader is done...\n", .{}); log("onReaderDone(0x{x}, {s})", .{ @intFromPtr(this), @tagName(this.out_type) }); const owned = this.toOwnedSlice(); this.state = .{ .done = owned }; diff --git a/src/sys.zig b/src/sys.zig index a800b68d42..93ea016825 100644 --- a/src/sys.zig +++ b/src/sys.zig @@ -4,6 +4,7 @@ //! //! Sometimes this namespace is referred to as "Syscall", prefer "bun.sys"/"sys" +const mlog = @import("./mlog.zig").log; const This = @This(); // @@ -1550,6 +1551,7 @@ pub fn write(fd: bun.FileDescriptor, bytes: []const u8) Maybe(usize) { // "WriteFile sets this value to zero before doing any work or error checking." var bytes_written: u32 = undefined; bun.assert(bytes.len > 0); + mlog("We're about to WriteFile({}, {})\n", .{ fd, adjusted_len }); const rc = kernel32.WriteFile( fd.cast(), bytes.ptr,