-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fails to capture long output from C stdio #16
Comments
Okay, interesting. Probably not too surprising that directly calling into C would not work properly (IOCapture just uses I also see an issue with a short string, where we don't actually return the capture. With function test_puts(str)
IOCapture.capture() do
@ccall puts(str::Cstring)::Cint
end
end I get
I can also replicate the issue with the long string. I guess the Would be great to get this working if possible, but I don't have the bandwidth currently to go down the IO rabbit hole. |
Here is a bit more systematic testing script and output, I think I can confirm your results: Test scriptusing IOCapture, Test
nbytes = [10^0, 10^1, 10^2, 10^3, 10^4, 10^5, 10^6]
function test_print(str)
cap = IOCapture.capture() do
print(str)
end
# save in a bool to avoid printing long strings when test fails
cap_output_equals_str = cap.output == str
@test cap_output_equals_str
end
function test_puts(str)
cap = IOCapture.capture() do
@ccall puts(str::Cstring)::Cint
end
@test cap.value == length(str) + 1
# save in a bool to avoid printing long strings when test fails
cap_output_equals_str = cap.output == str * "\n"
@test cap_output_equals_str
end
function test_puts_flush(str)
cap = IOCapture.capture() do
ret = @ccall puts(str::Cstring)::Cint
Libc.flush_cstdio()
return ret
end
@test cap.value == length(str) + 1
# save in a bool to avoid printing long strings when test fails
cap_output_equals_str = cap.output == str * "\n"
@test cap_output_equals_str
end
function run_testset(fn::Function)
@testset verbose=true "$fn" begin
for (i, n) in enumerate(nbytes)
# print different letters for each test
c = collect('A':'Z')[i]
@testset "$n" begin
fn(c^n)
end
end
end
end
@testset "IOCapture cstdio" verbose=true begin
run_testset(test_print)
run_testset(test_puts)
run_testset(test_puts_flush)
end Test script output
For the the smaller sizes (10k bytes and below), So I guess a first step would be to:
Second step:
Third step maybe (I'm not sure if this is correct):
What do you think? Edit: looks like the code to copy from the pipe to the IOBuffer is already running on another thread Line 108 in a23f2a4
so there must be something else going on. |
Regarding the async stuff -- those should be tasks, not threads. So it's still all single-threaded. But regardless, those tasks should be taking care of keeping the buffer empty.
Yeah, happy to take a PR for this. The edge cases should definitely be documented.
This also sounds good to me, and would happily accept a PR here too. I wouldn't worry too much about performance here -- I generally assume that the IOCapture calls are not very performance critical, and we can add the option to disable it later once it becomes a problem for someone. |
This currently fails:
For Julia-only code using e.g.
print
this works fine.Using
Libc.flush_cstdio()
doesn't seem to help:Related: JuliaIO/Suppressor.jl#46 and JuliaIO/Suppressor.jl#47
The text was updated successfully, but these errors were encountered: