digitalmars.D - rt_init, rt_term and _initCount
- Benjamin Thaut (60/60) Oct 20 2016 This is a topic really specific to druntime, I don't know a
- Ethan Watson (4/6) Oct 20 2016 Would this also be a bigger problem if people use LoadLibrary and
- Benjamin Thaut (3/9) Oct 20 2016 No. This case actually works correctly. No worries I have your
- Patrick Schluter (7/69) Oct 20 2016 I don't know anything about the druntime code but the solution
- Rainer Schuetze (8/22) Oct 21 2016 I don't think the current rt_init/rt_exit function are suitable for DLLs...
- Benjamin Thaut (6/11) Oct 21 2016 Yes, I also considered that option. The problem with that is,
- Rainer Schuetze (9/21) Oct 22 2016 The main executable wrapper could add this join-all if it is considered
- Benjamin Thaut (6/9) Oct 22 2016 The case where the main executable is not D is working fine. The
This is a topic really specific to druntime, I don't know a better place to put it though. rt_init increases the _initCount and rt_term decreases it and only terminates the runtime in case the _initCount reaches zero (see dmain2.d) The problem now is as follows. Each dynamic library that is loaded (in this case a .dll on windows) must ensure that druntime is intialized. This must be done to ensure that d dynamic libraries work with C processes that load them. So lets assume we have a exe and two dlls: DllA and DllB. The exe uses the two dlls and druntime. What will happen is the following 1) Exe starts up 2) The windows loader will load DllA. This will call rt_init _initCount will be 1. Druntime will be initialized. Module ctors of druntime will be called. Module Ctors of DllA will be called. 3) The windows loader will load DllB. _initCount will be 2. Module Ctors of DllB will be called. 4) The dmain function will be execued. It will call rt_init. _initCount is 3. Module ctors of exe will be called. 5) Dmain finishes and calls rt_term. _initCount is 2. Nothing happens 6) The windows loader will unload DllB. rt_term is called. _initCount is 1. DllB is forced to call its module dtors. 7) The windows loader will unload DllA. r_term is called. _initCount is 0. Module Dtors of exe will be called. Module Dotrs of DllA will be called. Module Dtors of druntime will be called. As might observed the issue is the order in which the module dtors are called. The order is Druntime Ctor DllA Ctor DllB Ctor ExE Ctor DllB Dtor Exe Dtor DllA Dtor Druntime Dtor Whereas it should be: Druntime Ctor DllA Ctor DllB Ctor ExE Ctor Exe Dtor DllB Dtor DllA Dtor Druntime Dtor The problem is step 5) in the above list. When the main executable leaves dmain the runtime should be deinitialized no matter if any dll is still loaded or not. If this would be the case the module Dtors would be calle din the correct order. I can't remove the rt_init calls from the dll loading code however because that would mean when loading a d-dll into a C process druntime would never be initialized. So I'm thinking of adding a force parameter to rt_term which will always deinitialize druntime disregarding the _initCount. This feels like a hack though. Any suggestions how to solve this problem? Who are other platforms doing it? Kind Regards Benjamin Thaut
Oct 20 2016
On Thursday, 20 October 2016 at 07:17:49 UTC, Benjamin Thaut wrote:Any suggestions how to solve this problem? Who are other platforms doing it?Would this also be a bigger problem if people use LoadLibrary and don't FreeLibrary after?
Oct 20 2016
On Thursday, 20 October 2016 at 08:44:09 UTC, Ethan Watson wrote:On Thursday, 20 October 2016 at 07:17:49 UTC, Benjamin Thaut wrote:No. This case actually works correctly. No worries I have your use case covered ;-)Any suggestions how to solve this problem? Who are other platforms doing it?Would this also be a bigger problem if people use LoadLibrary and don't FreeLibrary after?
Oct 20 2016
On Thursday, 20 October 2016 at 07:17:49 UTC, Benjamin Thaut wrote:This is a topic really specific to druntime, I don't know a better place to put it though. rt_init increases the _initCount and rt_term decreases it and only terminates the runtime in case the _initCount reaches zero (see dmain2.d) The problem now is as follows. Each dynamic library that is loaded (in this case a .dll on windows) must ensure that druntime is intialized. This must be done to ensure that d dynamic libraries work with C processes that load them. So lets assume we have a exe and two dlls: DllA and DllB. The exe uses the two dlls and druntime. What will happen is the following 1) Exe starts up 2) The windows loader will load DllA. This will call rt_init _initCount will be 1. Druntime will be initialized. Module ctors of druntime will be called. Module Ctors of DllA will be called. 3) The windows loader will load DllB. _initCount will be 2. Module Ctors of DllB will be called. 4) The dmain function will be execued. It will call rt_init. _initCount is 3. Module ctors of exe will be called. 5) Dmain finishes and calls rt_term. _initCount is 2. Nothing happens 6) The windows loader will unload DllB. rt_term is called. _initCount is 1. DllB is forced to call its module dtors. 7) The windows loader will unload DllA. r_term is called. _initCount is 0. Module Dtors of exe will be called. Module Dotrs of DllA will be called. Module Dtors of druntime will be called. As might observed the issue is the order in which the module dtors are called. The order is Druntime Ctor DllA Ctor DllB Ctor ExE Ctor DllB Dtor Exe Dtor DllA Dtor Druntime Dtor Whereas it should be: Druntime Ctor DllA Ctor DllB Ctor ExE Ctor Exe Dtor DllB Dtor DllA Dtor Druntime Dtor The problem is step 5) in the above list. When the main executable leaves dmain the runtime should be deinitialized no matter if any dll is still loaded or not. If this would be the case the module Dtors would be calle din the correct order. I can't remove the rt_init calls from the dll loading code however because that would mean when loading a d-dll into a C process druntime would never be initialized. So I'm thinking of adding a force parameter to rt_term which will always deinitialize druntime disregarding the _initCount. This feels like a hack though. Any suggestions how to solve this problem? Who are other platforms doing it? Kind Regards Benjamin ThautI don't know anything about the druntime code but the solution seems to look like rt_term() should kick the call to the destructor when the initcound matches with the initcount it had when it called rt_init(). But as I already said, I'm talking out of my ass here as I never even looked in the code.
Oct 20 2016
On 20.10.2016 09:17, Benjamin Thaut wrote:This is a topic really specific to druntime, I don't know a better place to put it though. rt_init increases the _initCount and rt_term decreases it and only terminates the runtime in case the _initCount reaches zero (see dmain2.d)[...]The problem is step 5) in the above list. When the main executable leaves dmain the runtime should be deinitialized no matter if any dll is still loaded or not. If this would be the case the module Dtors would be calle din the correct order. I can't remove the rt_init calls from the dll loading code however because that would mean when loading a d-dll into a C process druntime would never be initialized. So I'm thinking of adding a force parameter to rt_term which will always deinitialize druntime disregarding the _initCount. This feels like a hack though. Any suggestions how to solve this problem? Who are other platforms doing it?I don't think the current rt_init/rt_exit function are suitable for DLLs or executables that are using a shared druntime library. The wrapper around main in the executable should work just as any DLLs' DllMain, i.e. it should register/unregister its own data segments with the GC and run its shared and TLS module constructors/decoontructors. Everything else should be handled by the druntime DLL.
Oct 21 2016
On Friday, 21 October 2016 at 19:40:52 UTC, Rainer Schuetze wrote:The wrapper around main in the executable should work just as any DLLs' DllMain, i.e. it should register/unregister its own data segments with the GC and run its shared and TLS module constructors/decoontructors. Everything else should be handled by the druntime DLL.Yes, I also considered that option. The problem with that is, that druntime deinit joins alls threads before running the shared module dtors. If the main executable behaves exactly like the dlls do this joining of threads would be lost and different from the behavior of a fully statical linked executable.
Oct 21 2016
On 22.10.2016 01:21, Benjamin Thaut wrote:On Friday, 21 October 2016 at 19:40:52 UTC, Rainer Schuetze wrote:The main executable wrapper could add this join-all if it is considered useful. I'm not really convinced: If there are actually threads still running on program termination, it's likely they need some signal to stop. In C++ that is usually fired in the shared destructor of some global. This is currently not possible in D as these are run after joinAll. Please also consider that the main executable might not know about DLLs being written in D. In that case all termination must be triggered by the druntime DLL.The wrapper around main in the executable should work just as any DLLs' DllMain, i.e. it should register/unregister its own data segments with the GC and run its shared and TLS module constructors/decoontructors. Everything else should be handled by the druntime DLL.Yes, I also considered that option. The problem with that is, that druntime deinit joins alls threads before running the shared module dtors. If the main executable behaves exactly like the dlls do this joining of threads would be lost and different from the behavior of a fully statical linked executable.
Oct 22 2016
On Saturday, 22 October 2016 at 07:12:48 UTC, Rainer Schuetze wrote:Please also consider that the main executable might not know about DLLs being written in D. In that case all termination must be triggered by the druntime DLL.The case where the main executable is not D is working fine. The problem at the moment is the case where the main executable is D. So I will be going for the dll registration approach then. As you said we can add in the thread join in case it becomes a problem.
Oct 22 2016