How to avoid GC of Julia structs within C/C++/Rust data structures?

Here’s an example.

First the julia code to create a foreign DataType:

function maketype(marker, mod::Module=@__MODULE__)

    dtp = ccall(:jl_new_foreign_type,
               Any,
               (Symbol,Module,Any,Ptr{Cvoid}, Ptr{Cvoid}, Cint, Cint),
               :QueueRef, mod, Any, marker, C_NULL, 1, 0)
    mod.eval(
        quote
            const QueueRef = $dtp
            # a constructor:
            function QueueRef(h::Ptr)
                # make a new QueueRef object 
                ptls = Core.getptls()
                newobj = ccall(:jl_gc_alloc_typed, Any, 
                               (Ptr{Cvoid}, Csize_t, Any,),
                               ptls, sizeof(Ptr{Cvoid}), QueueRef)::QueueRef
                # store the pointer in it
                unsafe_store!(Ptr{UInt}(pointer_from_objref(newobj)), UInt(h), 1)
                # return the object
                newobj
            end
            Base.getindex(qr::QueueRef) = unsafe_load(Ptr{Any}(pointer_from_objref(qr)))
        end
    )
end

Then some C-code which I compile to a shared library in the file libmarker.so. This is where you loop through the C-queue and mark each entry.

#include <stdio.h>
#include "julia.h"
#include "julia_gcext.h"

int marker(jl_ptls_t ptls, jl_value_t *obj[]) {
  jl_value_t *p = obj[0];
  int marks = jl_gc_mark_queue_obj(ptls, p);
  if(marks > 0) printf("marked %p %d\n",p,marks);
  return marks;
}

Then a julia script using this stuff, which shows that I can lose all refs to the vector v. A pointer is hidden inside the QueueRef object, and the marker C-function takes care of marking it as still in use:

using Libdl
flib = dlopen("./libmarker.so")
cfun = dlsym(flib,:marker)
maketype(cfun)

v = [42, 42, 42]
finalizer(v) do o
    @ccall printf("finalize %p\n"::Cstring; pointer_from_objref(o)::Ptr{Nothing})::Cint
end

a = QueueRef(pointer_from_objref(v));
julia> a
QueueRef()

julia> v = nothing

julia> GC.gc(true)
marked 0x77e04e73f030 1
marked 0x77e04e73f030 1

julia> GC.gc(true)
marked 0x77e04e73f030 1

julia> a = nothing

julia> GC.gc(true)
finalize 0x77e04e73f030
1 Like