How to make child of failed fork exit cleanly?

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


On 04/05/2011 5:25 AM, Corinna Vinschen wrote:
> On May  3 19:03, Ryan Johnson wrote:
>> On 03/05/2011 2:41 PM, Corinna Vinschen wrote:
>>> I'm not sure I understand the question.  How do you know which
>>> DLL is already initialized and which isn't?
>> I'm talking about a call to dll_list::alloc, due to a DLL_LINK which
>> did not map to its parent's address. At this point we know the fork
>> has failed and there's no point continuing to try.
>> [...]
>> For the moment I've just disabled all finalizers if in_forkee=1, on
>> the premise that it's better to risk not runing a valid finalizer
>> than to risk running an invalid one. That made the access violations
>> go away, [...]
> Can't we mark the DLLs in the list for which the constructors ran
> successfully and only call them on termination?
I could try that. For some reason before I missed the fact that DLL_LINK 
state doesn't get copied over until just before the call to 
load_after_fork, and DLL_LOAD state until after that, so my earlier 
attempts to selectively disable destructors was broken.

So, two questions come up:

First, when (and where in the code) does the parent's dll list get 
copied over to the child? My understanding is that Windows makes no 
promises about what order it runs dll entry points during process 
startup, so we could conceivably have early-loading dlls start building 
a dll list from scratch, only to have it clobbered when cygwin1.dll 
brings the parent's copy across. If so, I cannot trust dll:has_dtors 
until after all DLL_LINK entry points have been called (in case 
cygwin1.dll is the last to arrive). I tried poking around in init.cc and 
dcrt0.cc, but can't find any obvious sign that cygwin dlls which init 
before cygwin1 would

Actually, if the above happens then it would be very hard to reliably 
detect dlls whose base address changed...

Meanwhile, I can reverse the sense of has_dtors to destructor calls 
conditional on (has_dtors != in_forkee). This way it wouldn't matter 
which version of the list I get and I don't have to complicate code 
outside dll_init.cc. The downside is the code becomes somewhat more 
confusing.

Then again, in_forkee never gets cleared if there are no DLL_LOAD 
around. It's cleared by load_after_fork, which is only called if 
dll_list::loaded_dlls is non-zero. A quick test with my static-only toy 
program confirms this (so my current code prevents a 
statically-linked-only child's finalizers from running even if the fork 
succeeded... oops).

I can move the in_forkee=false assignment from dll_list::load_after_fork 
to frok::child, but then the question arises whether to do it before or 
after the call to ld_preload? Is it possible/legal/meaningful for 
ld_preload to load a new dll in a forked child?

Ryan


Thoughts?
Ryan



More information about the Cygwin-developers mailing list