From 8d011ec425db8ea29f72a41109e5064f244b96b6 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Tue, 3 Sep 2024 13:22:45 +0200 Subject: [PATCH] Simplify the juliac compatible fork-exec This patch simplifies the juliac compatible pipe-fork-exec implementation for running git on the formatted text. Instead of collecting all bytes and then writing to stderr we instead write directly from the intermediate buffer to stderr. The drawback is that if reading bytes fail we might have already written something to stderr, but this should rarely, if ever, happen under normal circumstances. --- src/juliac.jl | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/juliac.jl b/src/juliac.jl index 3c7c178..e02ab3c 100644 --- a/src/juliac.jl +++ b/src/juliac.jl @@ -130,9 +130,7 @@ function run_juliac(cmd::Base.CmdRedirect) argv = cmd′′.exec dir = cmd′′.dir # Run the command - bytes = pipe_fork_exec(argv, dir) - # Write output - write(Core.stderr, bytes) + pipe_fork_exec(argv, dir) return end @@ -145,6 +143,7 @@ end function pipe_fork_exec(argv::Vector{String}, dir::String) local pipe, fork, dup2, chdir, execv, waitpid # Silence of the Langs(erver) + STDOUT_FILENO, STDERR_FILENO = 1, 2 # Set up the pipe fds = Vector{Cint}(undef, 2) READ_END, WRITE_END = 1, 2 @@ -161,7 +160,6 @@ function pipe_fork_exec(argv::Vector{String}, dir::String) err = @ccall close(fds[READ_END]::Cint)::Cint err == -1 && systemerror("close") # Duplicate write end of the pipe to stdout and stderr - STDOUT_FILENO, STDERR_FILENO = 1, 2 err = @ccall dup2(fds[WRITE_END]::Cint, STDOUT_FILENO::Cint)::Cint err == -1 && systemerror("dup2") err = @ccall dup2(fds[WRITE_END]::Cint, STDERR_FILENO::Cint)::Cint @@ -180,18 +178,24 @@ function pipe_fork_exec(argv::Vector{String}, dir::String) # Close write end of the pipe err = @ccall close(fds[WRITE_END]::Cint)::Cint err == -1 && systemerror("close") - bytes = UInt8[] - buf = Vector{UInt8}(undef, 1024) + # Shuffle bytes from the pipe to stderr + bufsize = 1024 + buf = Vector{UInt8}(undef, bufsize) while true - nread = @ccall read(fds[READ_END]::Cint, buf::Ptr{Cvoid}, 1024::Csize_t)::Cssize_t + # Read bytes from the pipe + nread = @ccall read(fds[READ_END]::Cint, buf::Ptr{Cvoid}, bufsize::Csize_t)::Cssize_t nread == -1 && systemerror("read") nread == 0 && break # eof - append!(bytes, @view(buf[1:nread])) + # Write bytes to stderr + nwrite = @ccall write(STDERR_FILENO::Cint, buf::Ptr{Cvoid}, nread::Csize_t)::Cssize_t + nread == -1 && systemerror("write") + @assert nwrite == nread end - err = @ccall close(fds[READ_END]::Cint)::Cint # Close the read end of the pipe + # Close the read end of the pipe + err = @ccall close(fds[READ_END]::Cint)::Cint err == -1 && systemerror("close") - # Check exit status of the child + # Wait for, and check exit status of, the child status = Ref{Cint}() wpid = @ccall waitpid(cpid::Cint, status::Ref{Cint}, 0::Cint)::Cint wpid == -1 && systemerror("waitpid") @@ -199,5 +203,5 @@ function pipe_fork_exec(argv::Vector{String}, dir::String) error("child process did not exit normally") end # crc = WEXITSTATUS(status) # ignore this like `ignorestatus(cmd)` - return bytes + return end