I'm trying to figure out why the gc (refc) is crashing. I have a dll with nim code, that's being called from C++. The nim function is calling NimMain() once and then doing some stuff with paths (allocating strings) and eventually crashes from repeated calls. If I move the NimMain() call outside of the once macro so it's called repeatedly, there's no crash. I don't know if that's a bad thing to repeatedly call NimMain, but I'd like to initialize the dll once. I've tried calling setupForeignThreadGC after NimMain or alone at the top of the function, but that doesn't make a difference.
If I compile with orc, I don't have any crashes which is great, but currently, I'm having issues with compiling with orc and clang on osx.
Any idea how I can stop refc from crashing without calling NimMain in my function?
proc NimMain() {.importc.} # needed to initialize the gc
var libPath:string
{.pragma: ex, exportc, cdecl, dynlib.}
proc initializeHost() {.ex.} =
NimMain()
libPath = getNimForUEConfig(pluginDir).nimForUELibPath
# call in an Actor while game is running
proc checkReload*() {.ex.} =
# NimMain() # no crash
#crashes on repeated calls
once:
initializeHost()
dostuff()
On the cpp side, Initialize is called first, then Tick is called repeatedly.
void UNimForUEEngineSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
initializeHost();
checkReload();
elapsedSeconds = 0.0;
}
void UNimForUEEngineSubsystem::Tick(float DeltaTime)
{
elapsedSeconds += DeltaTime;
if (elapsedSeconds > 0.1) // trigger crash faster
{
checkReload();
elapsedSeconds = 0.0;
}
}
That doesn't seem to be any different from calling NimMain through initializeHost above. Does NimMain need to be called per thread where the nim function is called? If that's the case somehow the Initialize and Tick functions on the C++ side could be on different threads because having the initialize check for NimMain done on the C++ side works.
void UNimForUEEngineSubsystem::Tick(float DeltaTime)
{
if (!initialized)
{
NimMain();
initialized = true;
}
elapsedSeconds += DeltaTime;
if (elapsedSeconds > 0.1)
{
checkReload();
elapsedSeconds = 0.0;
}
}
It seems like the C++ / Unreal subsystem code is creating multiple instances. A Default and "0" version of UNimForUEEngineSubsystem, and the Default is calling Tick without Initialize. The "0" version is calling Initialize(), then Default calls Tick(), then "0" calls Tick(). Why wouldn't calling NimMain in the "0"'s Initialize() work?
Oh well, I have a workaround...