www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Call thread_attachThis() from your D shared library

reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
We had an issue today calling a D shared library from our Java code 
where we were getting segfaults during GC collection cycles.

Of course we were being careful and calling Runtime.initialize() inside 
our initialization function, which is called from the Java side:

extern (C) auto mylib_init() {
     const rtInit = Runtime.initialize();
     if (!rtInit) {
         logf("Failed to initialize D runtime");
         abort();
     }
     // ...
}

but we were forgetting about the fact that our API functions might be 
called from threads other than the one that called Runtime.initialize().

extern (C) auto mylib_do_good_work() {
     // Oops! A GC collection cycle may cause segmentation fault here
     // ...
}

A simple solution is to call thread_attachThis() from each API function:

extern (C) auto mylib_do_good_work() {
     import core.thread : thread_attachThis;
     thread_attachThis();

     // Now this thread is attached to D runtime and all is good
     // ...
}

Although thread_attachThis() can be called multiple times from the same 
thread, it may be possible to call it only once per thread if potential 
calling threads are known; such threads can call a per-thread 
initialization function on the D side. (We don't think our Java program 
gives us that option because "our Java code" is a callback registered 
with the framework of a Java program, which has total control of its 
threads.)

Ali
Nov 17
parent reply Guillaume Piolat <first.last gmail.com> writes:
On Saturday, 18 November 2017 at 00:23:31 UTC, Ali Çehreli wrote:
 We had an issue today calling a D shared library from our Java 
 code where we were getting segfaults during GC collection 
 cycles.

 Of course we were being careful and calling 
 Runtime.initialize() inside our initialization function, which 
 is called from the Java side:

 extern (C) auto mylib_init() {
     const rtInit = Runtime.initialize();
     if (!rtInit) {
         logf("Failed to initialize D runtime");
         abort();
     }
     // ...
 }

 but we were forgetting about the fact that our API functions 
 might be called from threads other than the one that called 
 Runtime.initialize().

 extern (C) auto mylib_do_good_work() {
     // Oops! A GC collection cycle may cause segmentation fault 
 here
     // ...
 }

 A simple solution is to call thread_attachThis() from each API 
 function:

 extern (C) auto mylib_do_good_work() {
     import core.thread : thread_attachThis;
     thread_attachThis();

     // Now this thread is attached to D runtime and all is good
     // ...
 }

 Although thread_attachThis() can be called multiple times from 
 the same thread, it may be possible to call it only once per 
 thread if potential calling threads are known; such threads can 
 call a per-thread initialization function on the D side. (We 
 don't think our Java program gives us that option because "our 
 Java code" is a callback registered with the framework of a 
 Java program, which has total control of its threads.)

 Ali
I highly advise to attach incoming threads _and detach them when they exit the callback_. Indeed when they have exited the callback no need to scan their stack. If you don't do this and the thread dies outside your library, then your runtime still register it and will try to pause it at the first collection.
Nov 18
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/18/2017 03:45 AM, Guillaume Piolat wrote:

 I highly advise to attach incoming threads _and detach them when they
 exit the callback_. Indeed when they have exited the callback no need to
 scan their stack.

 If you don't do this and the thread dies outside your library, then your
 runtime still register it and will try to pause it at the first 
collection. Ooh! That makes sense. :) Ali
Nov 18