# Julia to C function to Julia function call

**URL:** <https://discourse.julialang.org/t/julia-to-c-function-to-julia-function-call/115997>\
**Category:** New to Julia\
**Tags:** embedding, multithreading\
**Created:** [June 21, 2024, 10:08pm UTC](https://discourse.julialang.org/t/julia-to-c-function-to-julia-function-call/115997 "2024-06-21T22:08:31Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![miniskar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/miniskar/32/210144_2.png) [@miniskar](https://discourse.julialang.org/u/miniskar)\
**Post date:** [June 21, 2024, 10:08pm UTC](https://discourse.julialang.org/t/julia-to-c-function-to-julia-function-call/115997/1 "2024-06-21T22:08:31Z")

</div>

I am trying having a runtime framework implemented in C++ launguage. Julia application calls this framework and this framework will call some other Julia function. I am facing some issue when the framework calls Julia function. I read from Embedding Julia documentation that it is not fully thread safe. Please help us to resolve this issue.  
I have created a simple test case to demonstrate the behavior.

Here is the Julia application code, which will call c\_function. c\_function creates a pthread and calls back Julia function julia\_add.  
main.jl

```julia
module MyLib
#enable(on::Bool) = ccall(:jl_gc_enable, Int32, (Int32,), on) != 0
#enable(off)
export julia_add, call_c_function, call_c_function_direct, initialize_c_function, cleanup_c_function

# Define a Julia function
#function julia_add(a::Int, b::Int)::Int
# return a + b
#end
function julia_add(a::Cint, b::Cint)::Cint
    println("Received a:", a, "b:", b)
    return a + b
end

# Initialize the C environment by passing the function pointer
function initialize_c_function()
    println("Inside initialize_c_function\n")
    #GC.enable(false)
    func_ptr = @cfunction(julia_add, Cint, (Cint, Cint))
    global stored_func_ptr = func_ptr
    ccall((:initialize_function, "libcfunction"), Cvoid, (Ptr{Cvoid},), func_ptr)
end

# Prototype for the C function
function call_c_function(a::Int, b::Int)::Int
    #ccall((:c_function, "libcfunction"), Cint, (Cint, Cint), Int32(a), Int32(b))
    return ccall((:c_function, "libcfunction"), Cint, (Cint, Cint), Cint(a), Cint(b))
end

# Prototype for the C function
function call_c_function_direct(a::Int, b::Int)::Int
    #ccall((:c_function, "libcfunction"), Cint, (Cint, Cint), Int32(a), Int32(b))
    return ccall((:c_function_direct, "libcfunction"), Cint, (Cint, Cint), Cint(a), Cint(b))
end

# Prototype for the C cleanup function
function cleanup_c_function()
    ccall((:cleanup, "libcfunction"), Cvoid, ())
    return 1
end

end # module

using .MyLib

# Initialize the C environment
initialize_c_function()

# Call the C function
#result = call_c_function_direct(3, 5)
#println("Result of calling C function: $result")
result = call_c_function(3, 5)
println("Result of calling C function: $result")
#result = call_c_function(3, 5)
#println("Result of calling C function: $result")
#result = call_c_function(3, 5)
#println("Result of calling C function: $result")

# Call the cleanup function
cleanup_c_function()
println("Exited\n")

```

c\_function.c

```julia
#include <julia.h>
#include <stdio.h>
#include <stdint.h>
#include <pthread.h>

// Define a type for the function pointer
typedef jl_value_t* (*julia_add_t)(jl_value_t*, jl_value_t*);

// Global variable to hold the function pointer
julia_add_t julia_add_func = NULL;

// Function to initialize the Julia runtime and get the function pointer
void initialize_function() {
    // Initialize the Julia runtime
    if (!jl_is_initialized()) {
        jl_init();
    }

    // Load the Julia module
    // Get the function from the module
    jl_function_t *julia_add = jl_get_function(jl_main_module, "julia_add");

    if (julia_add == NULL) {
        fprintf(stderr, "Error: Function julia_add not found\n");
        jl_atexit_hook(0);
        return;
    }

    // Store the function pointer
    julia_add_func = (julia_add_t)julia_add;
    printf(" Julia add:%p\n", julia_add);
}

// Function to be executed by pthreads
void* thread_function(void *args) {
    int32_t *arguments = (int32_t *)args;
    int32_t a = arguments[0];
    int32_t b = arguments[1];

    // Initialize the Julia runtime in this thread
    if (!jl_is_initialized()) {
        jl_init();
    }

    // Check if the function pointer is initialized
    if (julia_add_func == NULL) {
        fprintf(stderr, "Julia function pointer is not initialized\n");
        jl_atexit_hook(0);
        return NULL;
    }

    // Prepare the arguments
    jl_value_t *arg1 = jl_box_int32(a);
    jl_value_t *arg2 = jl_box_int32(b);

    // Call the Julia function
    jl_value_t *result = julia_add_func(arg1, arg2);

    // Check for exceptions
    if (jl_exception_occurred()) {
        fprintf(stderr, "Exception occurred while calling julia_add: %s\n", jl_typeof_str(jl_exception_occurred()));
        jl_atexit_hook(0);
        return NULL;
    }

    // Unbox the result
    int32_t c_result = jl_unbox_int32(result);
    printf("Result from thread: %d\n", c_result);

    // Cleanup Julia runtime for this thread
    jl_atexit_hook(0);

    return NULL;
}

// Define the C function to create a thread and call the Julia function
int32_t c_function(int32_t a, int32_t b) {
    pthread_t thread;
    int32_t args[2] = {a, b};

    if (pthread_create(&thread, NULL, thread_function, args)) {
        fprintf(stderr, "Error creating thread\n");
        return -1;
    }

    if (pthread_join(thread, NULL)) {
        fprintf(stderr, "Error joining thread\n");
        return -1;
    }

    return 0;
}

// Cleanup function to properly shutdown Julia
void cleanup() {
    if (jl_is_initialized()) {
        jl_atexit_hook(0);
    }
}

```

Build and run:

```julia
$ gcc -g -O0 -fPIC -shared -o libcfunction.so c_function.c -I$JULIA/include/julia -L$JULIA/lib -ljulia -lpthread
$ julia main.jl

```

---

<div class="post-metadata">

**Author:** ![vchuravy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vchuravy/32/8_2.png) [@vchuravy](https://discourse.julialang.org/u/vchuravy)\
**Post date:** [June 22, 2024, 1:12am UTC](https://discourse.julialang.org/t/julia-to-c-function-to-julia-function-call/115997/2 "2024-06-22T01:12:23Z")

</div>

You are getting the ABI wrong.

```julia
func_ptr = @cfunction(julia_add, Cint, (Cint, Cint))

```

does not correspond to:

```julia
// Define a type for the function pointer
typedef jl_value_t* (*julia_add_t)(jl_value_t*, jl_value_t*);

```

Instead this should have been:

```julia
typedef int (*julia_add_t)(int, int);

```

Your code-snippets are trying to do many things at once.  
Simplify your problem first so that you can find the source of your issues.

I would also recommend reading [Calling C and Fortran Code · The Julia Language](https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/#Creating-C-Compatible-Julia-Function-Pointers)

---

<div class="post-metadata">

**Author:** ![miniskar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/miniskar/32/210144_2.png) [@miniskar](https://discourse.julialang.org/u/miniskar)\
**Post date:** [June 30, 2024, 3:38pm UTC](https://discourse.julialang.org/t/julia-to-c-function-to-julia-function-call/115997/3 "2024-06-30T15:38:26Z")

</div>

> [@vchuravy](#):
>
> ```julia
> typedef int (*julia_add_t)(int, int);
> 
> ```

Thank you for your response.  
I have followed your solution and there is still an issue.  
I found the core reason for this issue.  
The issue is with println statement in “julia\_add” julia function. I found in documentation that println is not thread safe. When I replaced it with another C function, it worked.

---

<div class="post-metadata">

**Author:** ![vchuravy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vchuravy/32/8_2.png) [@vchuravy](https://discourse.julialang.org/u/vchuravy)\
**Post date:** [June 30, 2024, 3:59pm UTC](https://discourse.julialang.org/t/julia-to-c-function-to-julia-function-call/115997/4 "2024-06-30T15:59:57Z")

</div>

Yeah that’s why I recommended isolating issues first.  
Get your code your code working without threads in the mix and then tackle issue around thread safety.

When you say `println` isn’t threadsafe. How did that issue materialize? Is the issue that the printing was interleaved or that there was a crash?

Kinda curious where you found the note in the docs since it isn’t here [I/O and Network · The Julia Language](https://docs.julialang.org/en/v1/base/io-network/#Base.println)

---

<div class="post-metadata">

**Author:** ![miniskar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/miniskar/32/210144_2.png) [@miniskar](https://discourse.julialang.org/u/miniskar)\
**Post date:** [July 1, 2024, 4:38am UTC](https://discourse.julialang.org/t/julia-to-c-function-to-julia-function-call/115997/5 "2024-07-01T04:38:22Z")

</div>

I do not think the println is interleaved. I have created a single thread in C and called Julia function which was having println. If I replace that with ccall based printf it worked without an issue. Most times it is not crashing. It is stalled there.

---

<div class="post-metadata">

**Author:** ![vchuravy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vchuravy/32/8_2.png) [@vchuravy](https://discourse.julialang.org/u/vchuravy)\
**Post date:** [July 1, 2024, 11:32am UTC](https://discourse.julialang.org/t/julia-to-c-function-to-julia-function-call/115997/6 "2024-07-01T11:32:08Z")

</div>

So `println` is threadsafe, but you might have held onto the io lock somehow.

In cases like this it’s often helpful to attach GDB and print a stack trace on all threads.
