<p dir="auto">I want to use the main processing loop of a C-library, which implements specific functionality in callbacks.<br>
The callbacks shall be implemented in Julia. The following MWE demonstrates the difficulties, when the callback functions are invoked from POSIX-threads, which have been launched in C.</p>
<p dir="auto">callmtcb.jl</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="module Testcb
    f1() = println(&quot;called f1()&quot;)
    f2() = exit(99)
    cf1 = @cfunction f1 Cvoid ()
    cf2 = @cfunction f2 Cvoid ()

    push!(Base.DL_LOAD_PATH, pwd())
    dl = Base.Libc.dlopen(&quot;libmtcb&quot;)
    dls = Base.Libc.Libdl.dlsym(dl, :cb_setup)
    ccall(dls, Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}), cf1, cf2)
end"><pre class="notranslate"><span class="pl-k">module</span> Testcb
    <span class="pl-en">f1</span>() <span class="pl-k">=</span> <span class="pl-c1">println</span>(<span class="pl-s"><span class="pl-pds">"</span>called f1()<span class="pl-pds">"</span></span>)
    <span class="pl-en">f2</span>() <span class="pl-k">=</span> <span class="pl-c1">exit</span>(<span class="pl-c1">99</span>)
    cf1 <span class="pl-k">=</span> <span class="pl-c1">@cfunction</span> f1 Cvoid ()
    cf2 <span class="pl-k">=</span> <span class="pl-c1">@cfunction</span> f2 Cvoid ()

    <span class="pl-c1">push!</span>(Base<span class="pl-k">.</span>DL_LOAD_PATH, <span class="pl-c1">pwd</span>())
    dl <span class="pl-k">=</span> Base<span class="pl-k">.</span>Libc<span class="pl-k">.</span><span class="pl-c1">dlopen</span>(<span class="pl-s"><span class="pl-pds">"</span>libmtcb<span class="pl-pds">"</span></span>)
    dls <span class="pl-k">=</span> Base<span class="pl-k">.</span>Libc<span class="pl-k">.</span>Libdl<span class="pl-k">.</span><span class="pl-c1">dlsym</span>(dl, <span class="pl-c1">:cb_setup</span>)
    <span class="pl-c1">ccall</span>(dls, Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}), cf1, cf2)
<span class="pl-k">end</span></pre></div>
<p dir="auto">libmtcb.c</p>
<div class="highlight highlight-source-c notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="#include &lt;pthread.h&gt;

pthread_t threadid;
void(*savedf2)(void);

void* cb_thread(void* arg);

void cb_setup(void(*f1)(void), void(*f2)(void)) {

    (*f1)();
    savedf2 = f2;

    pthread_create(&amp;threadid, NULL, cb_thread, (void*)NULL);

    pthread_join(threadid, NULL);
    pthread_exit((void*)0);
}

void* cb_thread(void* arg) {
    (*savedf2)();
    return (void*)0;
}"><pre class="notranslate"><span class="pl-k">#include</span> <span class="pl-s">&lt;pthread.h&gt;</span>

<span class="pl-smi">pthread_t</span> <span class="pl-s1">threadid</span>;
<span class="pl-smi">void</span>(<span class="pl-c1">*</span><span class="pl-s1">savedf2</span>)(<span class="pl-smi">void</span>);

<span class="pl-smi">void</span><span class="pl-c1">*</span> <span class="pl-en">cb_thread</span>(<span class="pl-smi">void</span><span class="pl-c1">*</span> <span class="pl-s1">arg</span>);

<span class="pl-smi">void</span> <span class="pl-en">cb_setup</span>(<span class="pl-smi">void</span>(<span class="pl-c1">*</span><span class="pl-s1">f1</span>)(<span class="pl-smi">void</span>), <span class="pl-smi">void</span>(<span class="pl-c1">*</span><span class="pl-s1">f2</span>)(<span class="pl-smi">void</span>)) {

    (<span class="pl-c1">*</span><span class="pl-s1">f1</span>)();
    <span class="pl-s1">savedf2</span> <span class="pl-c1">=</span> <span class="pl-s1">f2</span>;

    <span class="pl-en">pthread_create</span>(<span class="pl-c1">&amp;</span><span class="pl-s1">threadid</span>, <span class="pl-c1">NULL</span>, <span class="pl-s1">cb_thread</span>, (<span class="pl-smi">void</span><span class="pl-c1">*</span>)<span class="pl-c1">NULL</span>);

    <span class="pl-en">pthread_join</span>(<span class="pl-s1">threadid</span>, <span class="pl-c1">NULL</span>);
    <span class="pl-en">pthread_exit</span>((<span class="pl-smi">void</span><span class="pl-c1">*</span>)<span class="pl-c1">0</span>);
}

<span class="pl-smi">void</span><span class="pl-c1">*</span> <span class="pl-en">cb_thread</span>(<span class="pl-smi">void</span><span class="pl-c1">*</span> <span class="pl-s1">arg</span>) {
    (<span class="pl-c1">*</span><span class="pl-s1">savedf2</span>)();
    <span class="pl-k">return</span> (<span class="pl-smi">void</span><span class="pl-c1">*</span>)<span class="pl-c1">0</span>;
}</pre></div>
<p dir="auto">Result of execution:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content=" make run
/home/crusius/julia/julia --startup-file=no callmtcb.jl
called f1()

signal (11): Segmentation fault
in expression starting at /home/crusius/dev/FuseApi/test/embed/callmtcb.jl:11
Allocations: 2749 (Pool: 2739; Big: 10); GC: 0
make: *** [Makefile:18: run] Segmentation fault (core dumped)"><pre class="notranslate"><code class="notranslate"> make run
/home/crusius/julia/julia --startup-file=no callmtcb.jl
called f1()

signal (11): Segmentation fault
in expression starting at /home/crusius/dev/FuseApi/test/embed/callmtcb.jl:11
Allocations: 2749 (Pool: 2739; Big: 10); GC: 0
make: *** [Makefile:18: run] Segmentation fault (core dumped)
</code></pre></div>
<p dir="auto">A <code class="notranslate">gdb</code> session revealed, that the callback to <code class="notranslate">f2</code> propagates into the call to <code class="notranslate">exit(99)</code> and then fails.<br>
Actually the threads local variable <code class="notranslate">jl_pgcstack</code> is not initialized, so the Julia runtime has no chance to succeed.</p>
<p dir="auto">The test files and the setup for a debug session are found here: <a href="https://github.com/KlausC/FuseApi.jl/blob/main/test/embed/">https://github.com/KlausC/FuseApi.jl/blob/main/test/embed/</a><br>
There is a <code class="notranslate">Makefile</code> with <code class="notranslate">run</code> and <code class="notranslate">debug</code> targets to explore the example under Linux and Gnome.</p>
<p dir="auto">As discussed on julia-users, I would like for it to be possible to call a Julia function from a non-Julia thread:<br>
<a href="https://groups.google.com/forum/#!topic/julia-users/TqC79eYTYx8" rel="nofollow">https://groups.google.com/forum/#!topic/julia-users/TqC79eYTYx8</a></p>
<p dir="auto">My use case is calling a Julia OpenGL rendering function from within the QML rendering thread. The current workaround is to force Qt to use the non-threaded rendering engine.</p>