This is the mail archive of the cygwin-developers mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: How to make child of failed fork exit cleanly?


On 04/05/2011 11:58 AM, Christopher Faylor wrote:
On Wed, May 04, 2011 at 05:33:57PM +0200, Corinna Vinschen wrote:
That said, I've implemented what you suggested (reversing the sense
of dll::has_dtors until fork fixup completes), and it seems to
behave properly. I still wonder, though: can we expect all dlls to
behave properly if (from their perspective) some library they
communicate with has ceased to exist without detaching?
It's a good assumption for a start.  If it turns out to be incorrect,
we can take another look.
Wouldn't this do what's required pretty simply?

cgf

--- dll_init.cc 2 May 2011 15:28:34 -0000       1.81
+++ dll_init.cc 4 May 2011 15:57:26 -0000
@@ -37,6 +37,8 @@ static bool dll_global_dtors_recorded;
  void
  dll_global_dtors ()
  {
+  if (in_forkee)
+    return;
    int recorded = dll_global_dtors_recorded;
    dll_global_dtors_recorded = false;
    if (recorded&&  dlls.start.next)
Originally I had this (though your way is probably better):
-   if (recorded&&  dlls.start.next)
+   if (recorded&&  dlls.start.next&&  !in_forkee)

It also needs (in dll_list::detach):
       /* Ensure our exception handler is enabled for destructors */
       exception protect;
       /* Call finalize function if we are not already exiting */
       if (!exit_state)
         __cxa_finalize (d);
-      d->run_dtors ();
+      if (!in_forkee)
+        d->run_dtors ();
       d->prev->next = d->next;
       if (d->next)
         d->next->prev = d->prev;

I favor one change in dll_init.h instead:
   void run_dtors ()
   {
-    if (has_dtors)
+    if (has_dtors&&  !in_forkee)

       {
        has_dtors = 0;
        p.run_dtors ();
       }
   }


The two problems with the all-or-nothing approach are:
1. in_forkee is only cleared if the parent process had at least one dynamically loaded dll at fork time (easily resolved by moving it from dll_list::load_after_fork to just after the call to it from frok::child, as I mentioned in another email)


2. once frok::child's first call to sync_with_parent returns, the statically linked dlls are fully initialized and (in theory) need to be finalized if the process exits. At least, that's the impression I got from Corinna's response. It does make sense in a way (one might ask why the finalizers exist if they don't need to run?). However, it's equally easy to argue that the child doesn't really "exist" until the fork completes successfully, which I tend to favor given undefined behavior that would arise if dlls share state with each other. It's easy to implement either way, though (I've already tested Corinna's suggestion, it's just a few more lines of code than the above). We just need to decide which we like better.

Ryan


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]