Druntime and non-D threads

Joakim dlang at joakim.fea.st
Tue Dec 12 03:18:37 UTC 2017


On Friday, 8 December 2017 at 09:33:03 UTC, Ali Çehreli wrote:
> I'm trying to use D as a library to be called from a non-D 
> environment e.g. Java runtime. If I'm not mistaken, it's quite 
> difficult and perhaps impossible to use GC in such a scenario. 
> It works as long as attached threads don't go away either by 
> themselves or by thread_detachThis.

I've been doing this for some time, by running all the D stdlib 
tests in a shared library that's called from Android's Java 
runtime, no problem with the GC or threads, if I set it up right 
and with a tweak or two:

https://wiki.dlang.org/Build_D_for_Android#Changes_for_Android

However, I go the other way and call Java methods from D, so it 
does depend on whether the process running the D shared library 
is long-running or not, as I've had issues when a D function or 
two are called periodically from a Java app instead.

> My setup is Linux (Ubuntu-based), dmd 2.077.1, 64-bit build. D 
> is used in a shared library that is called by non-D threads. 
> (Tested with C and Java.)
>
> 1) The following newsgroup topic is about calling 
> thread_attachThis() for threads created outside of D:
>
>   http://forum.dlang.org/post/ounui4$171a$1@digitalmars.com
>
> As suggested in that thread, I think I have to call 
> thread_detachThis but I'm not sure when that can be safely 
> done. One idea was to attach and detach in every api function 
> something to the effect of
>
> extern(C) my_api_func() {
>     thread_attachThis();
>     scope(exit) thread_detachThis();
>
>     // Do work, potentially producing garbage...
> }
>
> Does that make sense? Wouldn't garbage produced by that thread 
> leaked after detaching? However, failing to detach would be bad 
> as well as the calling thread can terminate without our 
> knowledge. (More on that below.)
>
> 2) Obviously, Runtime.initialize() must be called for Druntime 
> to work at all. Question: Is the thread that calls 
> Runtime.initialize() special compared to the other threads? Can 
> this thread disappear and the Druntime still work?
>
> 3) An attached non-D thread can exit without any notice 
> (gracefully or otherwise) while it's still attached to D's GC, 
> causing segmentation faults or deadlock.
>
> I failed to find a way for Druntime to be resilient when such 
> threads disappear. For example, the registered cleanup handler 
> in thread.d is called only for cancelled threads, not the ones 
> that exit simply by returning from their thread functions. 
> (This is according to cleanup handler spec.)

I haven't had to try all these thread registration methods, 
perhaps because the apps I'm testing are much simpler or because 
I'm going the other way from D to Java most of the time.

> 4) Druntime uses pthread_kill to signal threads to suspend (and 
> resume) threads. However, successful return of this function 
> does not mean that the thread will respond to that signal. So, 
> we have a couple of bugs in Druntime as the number of 
> sem_wait() calls we make depends on the unreliable return value 
> of pthread_kill. Perhaps that's the reason for bugs like the 
> following:
>
>   https://issues.dlang.org/show_bug.cgi?id=15939
>
> I don't see a way out of this POSIX limitation. 
> (pthread_key_create may help as a "thread destructor" but I 
> haven't played with it yet. thread.d beat me up pretty bad for 
> more than two days; I'm too tired to do anything else right 
> now. :) )
>
> 5) We depend on SIGUSR1 (and SIGUSR2, which may not be 
> necessary but it's a different topic) to suspend non-D threads. 
> Does that work with all threads? What if the calling framework 
> has other uses for those signals? Would we be interfering with 
> them?

Those signals are used for D threads, should work fine unless 
they're being intercepted somewhere, as they are by the Android 
runtime.  However, you can always change the signals used, as I 
did by swapping them on Android, and as others are trying to for 
other reasons:

https://github.com/dlang/druntime/pull/1851#discussion_r123886260
https://github.com/dlang/druntime/pull/1565

> So, what are the rules of using D as a library for a non-D 
> framework? I have the following so far but I'm not sure on all 
> points:
>
> - SURE: One thread must make a call to Runtime.initialize()
>
> - SURE: Every D api call must call thread_attachThis
>
> - SURE: Attached threads must *not* terminate gracefully, due 
> to error, or by cancellation. (As there is no way of 
> guaranteeing this in POSIX, I think using D as a library in a 
> framework is best-effort at best.)
>
> - NOT SURE: thread_detachThis must *not* be called as the 
> thread may have uncollected garbage.
>
> - NOT SURE: SIGUSR1 and SIGUSR2 should be available.

I have tried to avoid all these problems by having the D shared 
library be the starting point of the app and calling Java 
functions occasionally instead, so haven't delved into all this.


More information about the Digitalmars-d mailing list