How to make child of failed fork exit cleanly?

Ryan Johnson ryan.johnson@cs.utoronto.ca
Wed May 4 18:49:00 GMT 2011


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



More information about the Cygwin-developers mailing list