Thread overview
[Issue 4104] New: No way to get notified about D runtime termination.
Apr 19, 2010
Max Samukha
Jul 20, 2010
Sean Kelly
Jul 22, 2010
Max Samukha
April 19, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=4104

           Summary: No way to get notified about D runtime termination.
           Product: D
           Version: unspecified
          Platform: Other
        OS/Version: Linux
            Status: NEW
          Severity: critical
          Priority: P2
         Component: druntime
        AssignedTo: sean@invisibleduck.org
        ReportedBy: samukha@voliacable.com


--- Comment #0 from Max Samukha <samukha@voliacable.com> 2010-04-19 06:07:29 PDT ---
Qt classes have corresponding D wrappers in QtD. For many Qt classes we can avoid creating duplicate wrappers (or searching a wrapper cache) and store the D wrapper pointers directly in the C++ objects.

When Qt takes ownership of such an object, QtD disables garbage collection for the D wrapper by adding its reference to the GC roots. When later Qt deletes the object, a callback to D is emitted, during which the wrapper is destroyed.

Everything works well unless the C++ object is statically allocated or is owned by a statically allocated object. If it is, the C++ destructor is called *after* the D runtime has been terminated, meaning GC pools has been freed and there is no wrapper to delete.

One solution is to have a flag that would be set after the D runtime has been terminated. Then we could avoid deleting already freed wrappers by checking the flag in the callback.

Patch for druntime/src/rt/dmain2.d:

@@ -165,12 +165,18 @@
 }

 shared bool _d_isHalting = false;
+shared bool _d_isTerminated = false;

 extern (C) bool rt_isHalting()
 {
     return _d_isHalting;
 }

+extern (C) bool rt_isTerminated()
+{
+    return _d_isTerminated;
+}
+
 // This variable is only ever set by a debugger on initialization so it should
 // be fine to leave it as __gshared.
 extern (C) __gshared bool rt_trapExceptions = true;
@@ -244,6 +250,7 @@
     finally
     {
         _d_criticalTerm();
+        _d_isTerminated = true;
     }
     return false;
 }
@@ -404,5 +411,7 @@
         _STD_critical_term();
         _STD_monitor_staticdtor();
     }
+
+    _d_isTerminated = true;
     return result;
 }

Another solution would be a notification. Tests show that 'atexit' doesn't work for us because the handlers registered with 'atexit' are invoked after the destructors has been run. So we need a separate notification.

Even better solution: don't free the GC memory on exit and give the rooted objects a chance to be finalized properly.

This is critical.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 20, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=4104


Sean Kelly <sean@invisibleduck.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |ASSIGNED


--- Comment #1 from Sean Kelly <sean@invisibleduck.org> 2010-07-20 15:09:44 PDT ---
Is this something that can be addressed via a shared module dtor, or is that too early/late in the termination process?  isHalting seems of limited utility so I tentatively deprecated it, but perhaps it should be replaced by a status field instead?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 22, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=4104



--- Comment #2 from Max Samukha <samukha@voliacable.com> 2010-07-22 01:21:54 PDT ---
I am afraid it is too early.

The problem is that during the final GC cycle wrappers owned by D (subject to garbage collection) will be destroyed. As part of their destruction process, they will destroy their corresponding C++ objects, which may destroy other C++ objects, which will destroy their D wrappers (those added to roots).

Though I am not entirely sure whether the last-mentioned wrappers need to be destroyed at program exit, I tend to think they do, just like the wrapper that owns them (that is the one that indirectly causes their destruction).

From the above follows that we need to know when the final GC cycle has been finished, so that QtD doesn't try to destroy wrappers for the C++ objects that survived that cycle.

Obviously isHalting does not help here because it is set before the GC cycle is initiated.

A field of an enum type indicating the current runtime state would be great.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------