Thread overview
D DLL crashes if not run on the main thread
Sep 05, 2023
raven09
Sep 06, 2023
raven09
Sep 05, 2023
Hipreme
Sep 05, 2023
Guillaume Piolat
September 05, 2023

Hi,
I've compiled a DLL using D and intended to use it with a C# winforms app using P/Invoke. Everything works wonderfully as long as it is called from the main thread (at least I assume that it not being on the main thread is causing the issues). If I start a new thread and try using any function imported from the DLL the program will instantly crash. Debugging the winforms app with VS shows that it does indeed crash on that function call, but does not provide any more information. Further testing I did was writing a test DLL that basically just contained extern(C) export int TestMe() { return 5; } and calling it in a new C# program: it worked fine until I put it in a separate thread.

I assume that this has something to do with D's GC? But I tried calling GC.disable() and nothing changed. Any help or insight would be appreciated.
Thanks in advance

September 06, 2023
Whatever is going on, that function you showed would not call into druntime. So I don't think it's related.

As of right now I have no tips as I'm tired, but I suspect its on the .net end.
September 05, 2023

On Tuesday, 5 September 2023 at 22:45:28 UTC, raven09 wrote:

>

Hi,
I've compiled a DLL using D and intended to use it with a C# winforms app using P/Invoke. Everything works wonderfully as long as it is called from the main thread (at least I assume that it not being on the main thread is causing the issues). If I start a new thread and try using any function imported from the DLL the program will instantly crash. Debugging the winforms app with VS shows that it does indeed crash on that function call, but does not provide any more information. Further testing I did was writing a test DLL that basically just contained extern(C) export int TestMe() { return 5; } and calling it in a new C# program: it worked fine until I put it in a separate thread.

[...]

Hi, maybe you could try putting your DLL load function inside the thread which you're calling your function? Maybe there could be something related to that.

September 05, 2023

On Tuesday, 5 September 2023 at 22:45:28 UTC, raven09 wrote:

>

I assume that this has something to do with D's GC? But I tried calling GC.disable() and nothing changed. Any help or insight would be appreciated.
Thanks in advance

If you want to have a D DLL called from elsewhere, and don't control which threads call your dynlib:

  • first thread that comes (or the DLL load itself) should initialize the runtime. You can use pragma(crt_destructor) to deinitialize the D runtime.
  • threads that come through a callback should in general register to the D runtime, and unregister on exit. They will not hold roots while they are back in C land, and you must unregister them on exit else the GC will try to pause possibly dead threads when it collects.
    You can leave some threads unregistered, but then I'm not sure for TLS and they certainly cannot hold GC roots.

You can also leave the whole D runtime disabled, but that is annoying (no GC, amongst other things).

September 06, 2023
On Tuesday, 5 September 2023 at 22:53:35 UTC, Richard (Rikki) Andrew Cattermole wrote:
> Whatever is going on, that function you showed would not call into druntime. So I don't think it's related.
>
> As of right now I have no tips as I'm tired, but I suspect its on the .net end.

Sorry for the confusion, that function actually runs fine and it was something completely unrelated that caused the crash. However, swapping that out for a function that does interact with the druntime does cause a crash (it calls a function template inside of a class and returns the value)
September 06, 2023
Assuming it works outside of a DLL, you're probably missing the runtime initialization calls.

Mix SimpleDllMain in (or do your own). https://github.com/dlang/dmd/blob/9639d72ea0883808feff7aba71d87c5a78fb7f92/druntime/src/core/sys/windows/dll.d#L577