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