# @cfunction help

**URL:** <https://discourse.julialang.org/t/cfunction-help/60263>\
**Category:** General Usage\
**Created:** [April 29, 2021, 5:04pm UTC](https://discourse.julialang.org/t/cfunction-help/60263 "2021-04-29T17:04:43Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [April 29, 2021, 5:04pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/1 "2021-04-29T17:04:43Z")

</div>

Hello,

I have a tricky question. Let me know if there’s anything I can do to help explain etc.

I’m trying to make a fork of PortAudio that uses callback functions. You can see my progress here:

> **[GitHub - bramtayl/PortAudio.jl: PortAudio wrapper for the Julia programming...](https://github.com/bramtayl/PortAudio.jl)**
>
> PortAudio wrapper for the Julia programming language, compatible with the JuliaAudio family of packages - GitHub - bramtayl/PortAudio.jl: PortAudio wrapper for the Julia programming language, compa...

When I run the following code in `test/runtests_local.jl`

```julia
using PortAudio

PortAudioStream(input(), output()) do input_buffer, output_buffer, framecount, time_info, callback_flags, userdata
    return paComplete
end

```

I get a segfault:

```julia
fish: “/home/brandon/julia-1.6.0/bin/j…” terminated by signal SIGSEGV (Address boundary error)

```

I think the problem is most likely confusion on my part about how `@cfunction` works; this is the first time I’ve used it.

My code to wrap a Julia function as a PortAudio call-back function is below. I do a bit of conversion to allow users to access data rather than the underlying pointers.

```julia
function wrap_callback(callback, ::Type{UserData}, ::Type{Sample}) where {UserData, Sample}
    @cfunction(
        function (
            input_buffer_pointer, 
            output_buffer_pointer, 
            framecount,
            time_info_pointer,
            status_flags,
            user_data_pointer
        )
            PaStreamCallbackResult(callback(
                unsafe_wrap(Array, input_buffer_pointer, 2),
                unsafe_wrap(Array, output_buffer_pointer, 2),
                framecount,
                unsafe_pointer_to_objref(time_info_pointer),
                StreamCallbackFlags(status_flags),
                if user_data_pointer === C_NULL
                    nothing
                else
                    unsafe_pointer_to_objref(user_data_pointer)
                end
            ))
        end,
        PaStreamCallbackResult, # returns
        (
            Ptr{Sample}, # input buffer pointer
            Ptr{Sample}, # output buffer pointer
            Culong, # framecount
            Ptr{PaStreamCallbackTimeInfo}, # time info pointer
            PaStreamCallbackFlags, # status flags
            Ptr{UserData}, # userdata pointer
        )
    )
end

```

The PortAudio docs on writing a callback function are here:

[http://portaudio.com/docs/v19-doxydocs/writing\_a\_callback.html](http://portaudio.com/docs/v19-doxydocs/writing_a_callback.html)

They state:

> Your callback function must return an int and accept the exact parameters specified in this typedef:

```julia
typedef int PaStreamCallback( const void *input,
                                      void *output,
                                      unsigned long frameCount,
                                      const PaStreamCallbackTimeInfo* timeInfo,
                                      PaStreamCallbackFlags statusFlags,
                                      void *userData ) ;

```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [April 29, 2021, 6:55pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/2 "2021-04-29T18:55:00Z")

</div>

Since it accepts a `void *userData` argument, you should use this to pass through the Julia function object, as explained [here](https://julialang.org/blog/2013/05/callback/#passing_closures_via_pass-through_pointers).

---

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [April 30, 2021, 12:13pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/3 "2021-04-30T12:13:26Z")

</div>

@stevengj nice, that’s so clever! I tried updating the code but am still getting the same error.

My updated code looks like:

```julia
function run_true_callback(
    input_buffer_pointer, 
    output_buffer_pointer, 
    framecount,
    time_info_pointer,
    status_flags,
    user_data_pointer
)
    PaStreamCallbackResult((unsafe_pointer_to_objref(user_data_pointer)::Function)(
        unsafe_wrap(Array, input_buffer_pointer, 2),
        unsafe_wrap(Array, output_buffer_pointer, 2),
        framecount,
        unsafe_pointer_to_objref(time_info_pointer),
        StreamCallbackFlags(status_flags),
    ))
end

function make_dummy_callback(::Type{Sample}) where {Sample}
    @cfunction(
        run_true_callback,
        PaStreamCallbackResult, # returns
        (
            Ptr{Sample}, # input buffer pointer
            Ptr{Sample}, # output buffer pointer
            Culong, # framecount
            Ptr{PaStreamCallbackTimeInfo}, # time info pointer
            PaStreamCallbackFlags, # status flags
            Ptr{Nothing}
        )
    )
end

stream_pointer = Pa_OpenStream(
        input_parameters,
        output_parameters,
        the_sample_rate,
        frames_per_buffer,
        flag,
        make_dummy_callback(Sample),
        Ref(callback),
    )

```

And now I run

```julia
using PortAudio

PortAudioStream(input(), output()) do input_buffer, output_buffer, framecount, time_info, callback_flags
    return paComplete
end

```

---

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [May 3, 2021, 1:21am UTC](https://discourse.julialang.org/t/cfunction-help/60263/4 "2021-05-03T01:21:49Z")

</div>

After further investigation, it seems to be that doing almost _anything_ inside the callback function results in a segfault.

```julia
function run_true_callback(
    input_buffer_pointer, 
    output_buffer_pointer, 
    framecount,
    time_info_pointer,
    status_flags,
    pass_through_pointer
)
    println("hi")
    return PaStreamCallbackResult(paComplete)
end
# “/home/brandon/julia-1.6.0/bin/j…” terminated by signal SIGSEGV (Address boundary error)

```

```julia
function run_true_callback(
    input_buffer_pointer, 
    output_buffer_pointer, 
    framecount,
    time_info_pointer,
    status_flags,
    pass_through_pointer
)
    @spawn println("hi")
    return PaStreamCallbackResult(paComplete)
end
# “/home/brandon/julia-1.6.0/bin/j…” terminated by signal SIGSEGV (Address boundary error)

```

So…, at a loss

---

<div class="post-metadata">

**Author:** ![Gnimuc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gnimuc/32/2194_2.png) [@Gnimuc](https://discourse.julialang.org/u/Gnimuc)\
**Post date:** [May 3, 2021, 2:42am UTC](https://discourse.julialang.org/t/cfunction-help/60263/5 "2021-05-03T02:42:54Z")

</div>

Does it segfault if you use global `cfunction`s instead of creating them via the `make_dummy_callback`?

Currently, there is something wrong with `closure-cfunction`s.

This issue might be related: [Segfault in ccall · Issue #40164 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/40164)

---

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [May 3, 2021, 5:35am UTC](https://discourse.julialang.org/t/cfunction-help/60263/6 "2021-05-03T05:35:23Z")

</div>

Something like this?

```julia
const CALLBACK_CFUNCTION = 
    @cfunction(
        run_true_callback,
        PaStreamCallbackResult, # returns
        (
            Ptr{Float32}, # input buffer pointer
            Ptr{Float32}, # output buffer pointer
            Culong, # framecount
            Ptr{PaStreamCallbackTimeInfo}, # time info pointer
            PaStreamCallbackFlags, # status flags
            Ptr{Nothing}, # pass-through
        )
    )

```

Yup, still get a segfault

---

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [May 3, 2021, 5:38am UTC](https://discourse.julialang.org/t/cfunction-help/60263/7 "2021-05-03T05:38:43Z")

</div>

Worth nothing that this simply returning a value does not throw a segfault, and runs as expected. Haven’t found anything else that works though.

```julia
function run_true_callback(
    input_buffer_pointer, 
    output_buffer_pointer, 
    framecount,
    time_info_pointer,
    status_flags,
    pass_through_pointer
)
    return PaStreamCallbackResult(paComplete)
end

```

---

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [May 3, 2021, 4:22pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/8 "2021-05-03T16:22:02Z")

</div>

I’ve discovered that repeatedly running and crashing gives a variety of error messages:

```julia
signal (11): Segmentation fault
in expression starting at REPL[1]:1
Assertion 'pthread_mutex_lock(&m->mutex) == 0' failed at ../src/pulsecore/mutex-posix.c:90, function pa_mutex_lock(). Aborting.

fatal: error thrown and no exception handler available.
DivideError()

signal (6): Aborted
in expression starting at REPL[1]:1

malloc(): smallbin double linked list corrupted

```

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 3, 2021, 4:24pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/9 "2021-05-03T16:24:14Z")

</div>

> [@bramtayl](#):
>
> ```julia
> Ptr{Float32}, # input buffer pointer
> Ptr{Float32}, # output buffer pointer
> 
> ```

Just curious, but why are these `Ptr{Float32}` and not `Ptr{Cvoid}`? From my understanding, you’d want Cvoid here and convert whatever you get internally with one of the `unsafe_` functions.

> [@bramtayl](#):
>
> I’ve discovered that repeatedly running and crashing gives a variety of error messages:

Those errors suggest some buffer overflow to me, which (I think) would be in line with what I said above.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 3, 2021, 4:29pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/10 "2021-05-03T16:29:43Z")

</div>

> [@bramtayl](#):
>
> ```julia
> unsafe_wrap(Array, input_buffer_pointer, 2),
> unsafe_wrap(Array, output_buffer_pointer, 2),
> 
> ```

Are you sure `2` for dims is correct here? This will lead to a 1-D Vector with 2 elements, not an array with 2 dimensions.

---

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [May 3, 2021, 4:35pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/11 "2021-05-03T16:35:23Z")

</div>

Hmm, well about the pointer type I’m honestly not sure. Could you explain a bit more when to use one and when to use the other? In any case, I tried changing to Cvoid and it didn’t seem to help.

I had figured out I was wrong about dims (dims is a confusing argument name), currently I’ve got:

```julia
unsafe_wrap(Array{Float32}, input_buffer_pointer, (2, framecount))

```

The two rows are for the left and right speaker I think. I’ll eventually have to figure out a way to pass the number of channels for other setups.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 3, 2021, 4:39pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/12 "2021-05-03T16:39:22Z")

</div>

PortAudio seems to expect a `*void`, so from my understanding you’d have to use `Ptr{Cvoid}` and you’d want to convert that to `Ptr{Float32}` before passing it to `unsafe_wrap(Array, ptr, ...)`.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 3, 2021, 4:43pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/13 "2021-05-03T16:43:45Z")

</div>

I’m also not sure if you can do any of that at all:

```nohighlight
/* This routine will be called by the PortAudio engine when audio is needed.
 * It may called at interrupt level on some machines so don't do anything
 * that could mess up the system like calling malloc() or free().
 */ 

```

So you’re not allowed to allocate at all.

---

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [May 3, 2021, 4:52pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/14 "2021-05-03T16:52:17Z")

</div>

Ok…, so, the kind of thing I might want to do is fill the output buffer with a generated sin wave. Is there a way to do that without allocating?

---

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [May 3, 2021, 5:04pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/15 "2021-05-03T17:04:56Z")

</div>

Also, at least as I’m reading the docs, being too greedy in the callback function shouldn’t cause crashes, just slowdowns:

> For most modern systems, you won’t be able to cause crashes by making disallowed calls in the callback, but if you want your code to produce glitch-free audio, you will have to make sure you avoid function calls that may take an unbounded amount of time to execute

---

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [May 4, 2021, 11:14am UTC](https://discourse.julialang.org/t/cfunction-help/60263/16 "2021-05-04T11:14:57Z")

</div>

Well, I’m not sure if its software limitations or bugs, but I’m pretty sure I won’t be able to make any progress here…

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 4, 2021, 12:28pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/17 "2021-05-04T12:28:32Z")

</div>

> [@bramtayl](#):
>
> Is there a way to do that without allocating?

That should be possible, having a loop calling `sin` again and again. That shouldn’t allocate.

> [@bramtayl](#):
>
> Well, I’m not sure if its software limitations or bugs, but I’m pretty sure I won’t be able to make any progress here…

I’m running out of ideas as well - maybe it’s because your enum isn’t using `Cint` as its basetype? what happens if you just return `Cint(0)` instead?

---

<div class="post-metadata">

**Author:** ![Gnimuc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gnimuc/32/2194_2.png) [@Gnimuc](https://discourse.julialang.org/u/Gnimuc)\
**Post date:** [May 4, 2021, 12:45pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/18 "2021-05-04T12:45:14Z")

</div>

> [@bramtayl](#):
>
> `paComplete`

what’s `paComplete`? could you provide a MWE? I can give it a look if I could get some time.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 4, 2021, 1:07pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/19 "2021-05-04T13:07:30Z")

</div>

> [@Gnimuc](#):
>
> what’s `paComplete` ?

> <https://github.com/bramtayl/PortAudio.jl/blob/12516aa74487d76356c797fd5786129c478e62be/src/libportaudio.jl#L73-L77>

---

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [May 4, 2021, 1:35pm UTC](https://discourse.julialang.org/t/cfunction-help/60263/20 "2021-05-04T13:35:27Z")

</div>

> Maybe it’s because your enum isn’t using `Cint` as its basetype?

At least in my current version, I call `PaStreamCallbackResult` to convert it back to a Cint.

> That should be possible, having a loop calling `sin` again and again. That shouldn’t allocate.

Right, but how can I modify the data in the buffer without making an array?

> could you provide a MWE? I can give it a look if I could get some time.

@Gnimuc that would be great! You can go to my fork for PortAudio ([GitHub - bramtayl/PortAudio.jl: PortAudio wrapper for the Julia programming language, compatible with the JuliaAudio family of packages](https://github.com/bramtayl/PortAudio.jl)), check out the “callback” branch (I’ve given up on the master branch), and then include test/runtest\_local.jl. It’s not exactly minimal, but you can experiment ways to make it more minimal (doing almost anything in the dummy callback function except returning causes a segfault on my end).

[Next page](https://discourse.julialang.org/t/cfunction-help/60263.md?page=2)
