Leave GC collection to the user of the D library?

Vladimir Panteleev thecybershadow.lists at gmail.com
Sun May 9 13:51:26 UTC 2021


On Sunday, 9 May 2021 at 03:25:06 UTC, Ali Çehreli wrote:
> That workaround seemed to be sufficient to load the library 
> successfully. Unfortunately, that was not enough to weed out 
> all issues related to libraries because this library itself 
> loads other D libraries. All of this caused sporadic issues. 
> (My brain is too fried to even remember what was a cause, what 
> was a usable workaround, etc. Sometimes I wasted days chasing a 
> solution while using a test, which had nothing to do with the 
> solution. I would change the code, test, no go; repeat, no go. 
> It turns out, my test was unrelated. Argh!)

In my experience, calling D from C/C++ works fine as long as 1) 
the D runtime is allowed to initialize, and 2) all threads which 
execute D code are registered with the D runtime.

If C/C++ code is allowed to hold the only reference to an object 
in the D GC heap, then the second rule needs to be extended to 
all threads which may hold a reference to said objects, but it 
may be practical to copy D objects at the C/D barrier either to 
caller-owned memory, or malloc-allocated memory that the caller 
can free by calling the standard C `free` function.

> So, we came up with a drastic solution: Since all this code 
> works just fine in a pure D environment, make the library as 
> thin as possible; the library starts a daemon that is written 
> in D with all the functionality. The library merely dispatches 
> the requests to that daemon.
>
> The library starts the daemon with pipeProcess(); pipes are 
> used for dispatching requests and shared memory is used for 
> large data. This idea "worked like a charm." Phew!
>
> However, dispatching of the requests to the daemon is performed 
> by a single library thread in a blocked manner: When a request 
> is written to the pipe, the response is read back (blocked) and 
> the result is returned to the user of the library function.

If the threads don't need to share state, you could just as well 
spawn one subprocess per thread, and let it do its own data 
processing.

Another approach would be to listen on a UNIX socket instead of 
using a pipe, which allows using `accept` to open new 
communication channels on-demand.

> I feel so hopeless that in the past, I even thought about and 
> experimented with banning the user from starting threads on 
> their own. Rather, they would call my library on a posix 
> compatible thread API and create their threads through me, 
> which happens to be a D thread, so no thread would be a 
> "foreign thread" and everything would work just fine. I haven't 
> deployed this crazy idea (yet).

Perhaps it would be simpler to just write the library part in C / 
C++ / -betterC D. std.mmfile has many lines, but the work it has 
to do is actually quite simple. The same is true about 
std.socket. This will completely avoid your headache with getting 
the D runtime / GC to play well with the host process's threading 
model.



More information about the Digitalmars-d mailing list