A pass-through option for IOCapture

Yeah, unsafe_write is probably too unsafe, especially while I don’t understand every detail of asynchronous I/O. Also copyuntil doesn’t seem to work with Pipe/PipeEndpoint objects.

It would be nice if there was an atomic bytes_read = read!(pip, buffer, bufsize) , but I don’t think there is.

Actually, looking at the internals, with @edit read(pipe, bufsize), I think there is, and it’s readbytes!.

So this is my latest iteration, which seems to work and shouldn’t allocate anything inside the loop:

bufsize = 128
buffer = Vector{UInt8}(undef, bufsize)
buffer_redirect_task = @async begin
    while true
        nbytes = readbytes!(pipe, buffer, bufsize)
        data = view(buffer, 1:nbytes)
        write(output, data)
        write(default_stdout, data)
        isopen(pipe) || break
    end
end

Now, one more question about the exit condition from the loop (since I’m still pretty unsure about some of the details of asynchronous I/O): Is there any possibility that I might be missing data because the main task puts data into the pipe between the time I call readbytes!(pipe, buffer, bufsize) and the time I call isopen(pipe)? What about if I move the isopen check to the beginning of the loop (while isopen(pipe))?

The other possibility I was considering was (nbytes == 0) && break, which also seems to work in my tests. But again: is there any possibility that the main task doesn’t write data to the pipe fast enough, so that there (temporarily) might not be anything for readbytes! to read, making me believe erroneously that the main task is done? Update: Let’s split this off to Race condition reading from Pipe. The MWE there demonstrated that (nbytes == 0) does not work in general.

I saw iolock_begin() and iolock_end() in the internals of Pipe. Is that something I might need here to avoid race conditions?