On Thursday, July 25, 2013 07:11:02 PM Gustavo Goretkin wrote:
> I should have considered this before, but PortAudio calls the julia
> callback on it's own thread. That's probably the reason why things are
> breaking. Can anyone confirm?
Certainly it's true that julia is not thread-safe, particularly in two areas:
code generation (JIT compilation) and memory allocation/cleanup. I know you
said you're running with gc_disable(), that might help with the latter problem
but I'm not certain it avoids it altogether.
You have at least two options:
1. Write your callbacks in C
2. If you want to try writing your callbacks in Julia, (a) make sure you run
them once or more first so they are already compiled, and (b) write them so
that they don't use any memory. @allocated was very recently added, with a
certain amount of discussion :-), as a way of testing whether the latter is
true.
Example based on your gist:
function output(status_flags::Culong, frame_count::Culong)
println("stfl:$status_flags \tframe_count:$frame_count")
zero(Cint) #continue stream
end
# Run once to get compilation out of the way:
julia> output(uint(0),uint(5))
stfl:0x0000000000000000 frame_count:0x0000000000000005
0
# Now pay attention to this run:
julia> @allocated output(uint(0),uint(5))
stfl:0x0000000000000000 frame_count:0x0000000000000005
864
That 864 at the end is bad news. You want to see 0. I think println and
friends won't work for you. Probably your best bet would be to append those
two values to the end of a preallocated buffer. If you like the idea of
representing "raw" memory there are some functions in base/pointer.jl that may
help, but I suspect the easiest approach will be something like this:
julia> mybuffer = Array(Culong, 0);
julia> sizehint(mybuffer, 10^6)
0-element Uint64 Array
julia> function output(status_flags::Culong, frame_count::Culong)
push!(mybuffer, status_flags)
push!(mybuffer, frame_count)
zero(Cint)
end
# methods for generic function output
output(status_flags::Uint64,frame_count::Uint64) at none:2
julia> @allocated output(uint(0),uint(5)) # it will compile here
67616
julia> @allocated output(uint(0),uint(5))
0
julia> @allocated output(uint(0),uint(5))
0
julia> mybuffer
6-element Uint64 Array:
0x0000000000000000
0x0000000000000005
0x0000000000000000
0x0000000000000005
0x0000000000000000
0x0000000000000005
Just make sure you don't fill the buffer up, because push! will allocate memory
when that happens. You could, e.g., use mybuffer1 to encode its reserved size,
and not generate output once you will overflow it.
--Tim