Segmentation fault on PortAudio callback

566 views
Skip to first unread message

Gustavo Goretkin

unread,
Jul 20, 2013, 4:58:19 AM7/20/13
to juli...@googlegroups.com
I'm trying to interface with PortAudio on Ubuntu 12.04. I have the latest of Julia from the repo. Mostly it segfaults, but sometimes it works (exciting!). This is most likely due to some issue with callbacks.

I have run gc_disable(). I've also tried maintaining a reference to the Julia callback function so that it doesn't get garbage collected.

Here is a minimum example: https://gist.github.com/anonymous/6044344

Sometimes I get very noisy segfaults: https://gist.github.com/anonymous/6044357 (see the top of that file for how I'm running the code)

I can often get this thing to work if I do the following in a session (but here's another example of it segfaulting, the ALSA stuff is noise from PortAudio. It happens on my system no matter which application uses PortAudio.)

julia> reload("gg/port_audio2.jl")
ALSA lib pcm_asym.c:106:(_snd_pcm_asym_open) capture slave is not defined
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib audio/pcm_bluetooth.c:1614:(audioservice_expect) BT_GET_CAPABILITIES failed : Input/output error(5)
ALSA lib audio/pcm_bluetooth.c:1614:(audioservice_expect) BT_GET_CAPABILITIES failed : Input/output error(5)
ALSA lib audio/pcm_bluetooth.c:1614:(audioservice_expect) BT_GET_CAPABILITIES failed : Input/output error(5)
ALSA lib audio/pcm_bluetooth.c:1614:(audioservice_expect) BT_GET_CAPABILITIES failed : Input/output error(5)
ALSA lib pcm_dmix.c:957:(snd_pcm_dmix_open) The dmix plugin supports only playback stream
ALSA lib pcm_dmix.c:1018:(snd_pcm_dmix_open) unable to open slave
Success
Success

julia> PortAudio.start_stream(PortAudio.stream_obj[1])
Success

julia> Segmentation fault (core dumped)

the only difference here, I can imagine, is the greater amount of time between opening the stream and starting the stream.

When it does work, it produces some periodic noise (two bursts a second), which is just unzero'd arrays being read out.

If I try/pray enough, it does end up not segfaulting, and then I can play around with the soundcard and played some simple tones and did an input-output passthrough (fun stuff!)




Gustavo Goretkin

unread,
Jul 25, 2013, 6:20:29 PM7/25/13
to juli...@googlegroups.com
I realize now I didn't actually ask a question.

How can I debug this? The code should run (by which I mean segfault) on any machine that has PortAudio installed (sudo apt-get install portaudio19-dev), though I've only tried it on Ubuntu 12.04


Elliot Saba

unread,
Jul 25, 2013, 6:51:38 PM7/25/13
to juli...@googlegroups.com
You could try building a debug version of Julia, (`make debug`) and running that inside of gdb (`gdb --args ./julia [julia arguments]`).  Once it crashes, you can get a backtrace by typing `bt` into gdb, and that should give you some idea where things are going wrong.
-E

Gustavo Goretkin

unread,
Jul 25, 2013, 7:11:02 PM7/25/13
to juli...@googlegroups.com
Thank you. It crashes at different places each time. Here are three different backtraces: https://gist.github.com/anonymous/6084617

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?

Tim Holy

unread,
Jul 26, 2013, 3:15:19 AM7/26/13
to juli...@googlegroups.com
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

Reply all
Reply to author
Forward
0 new messages