Segfault when invoking Julia callback function from C

Thanks to Valentin for meeting with me offline. We arrived at a final solution to this problem:

Declare a callback this way:

struct Message
	error_code::Cint
	return_code::Cint
	session_present::Cuchar
end

callback = ForeignCallbacks.ForeignCallback{Message}() do msg
	# actual callback impl in here
	return nothing
end

function on_connection_complete(connection::Ptr{aws_mqtt_client_connection}, error_code::Cint, return_code::Cint, session_present::Cuchar, userdata::Ptr{Cvoid})
	# convert and then load the pointer because this function must be type-stable
	token = Base.unsafe_load(Base.unsafe_convert(Ptr{ForeignCallbacks.ForeignToken}, userdata))
	ForeignCallbacks.notify!(token, Message(error_code, return_code, session_present))
	return nothing
end

Store the user_data this way:

token = Ref(ForeignCallbacks.ForeignToken(callback))
Base.unsafe_convert(Ptr{Cvoid}, token) # this is the user_data

Then you can create the callback C function:

on_connection_complete_cb = @cfunction(on_connection_complete, Cvoid, (Ptr{aws_mqtt_client_connection},Cint,Cint,Cuchar,Ptr{Cvoid}))

Relevant variables like token and on_connection_complete_cb must be GC.@preserve-ed while in use.

4 Likes