more words
This commit is contained in:
parent
d353d5d6f8
commit
64a2f70b43
|
@ -1,4 +1,5 @@
|
||||||
[Not yet complete]
|
Copyright 2001 Christopher Faylor
|
||||||
|
|
||||||
Cygwin has recently adopted something called the "cygwin heap". This is
|
Cygwin has recently adopted something called the "cygwin heap". This is
|
||||||
an internal heap that is inherited by forked/execed children. It
|
an internal heap that is inherited by forked/execed children. It
|
||||||
consists of process specific information that should be inherited. So
|
consists of process specific information that should be inherited. So
|
||||||
|
@ -20,3 +21,84 @@ The cygheap memory allocation functions are adapted from memory
|
||||||
allocators developed by DJ Delorie. They are similar to early BSD
|
allocators developed by DJ Delorie. They are similar to early BSD
|
||||||
malloc and are intended to be relatively lightweight and relatively
|
malloc and are intended to be relatively lightweight and relatively
|
||||||
fast.
|
fast.
|
||||||
|
|
||||||
|
How is the cygheap propagated to the child?
|
||||||
|
|
||||||
|
Well, it depends if you are running on Windows 9x or Windows NT.
|
||||||
|
|
||||||
|
On NT and 9x, just before CreateProcess is about to be called in
|
||||||
|
fork or exec, a shared memory region is prepared for copying of the
|
||||||
|
cygwin heap. This is in cygheap_setup_for_child. The handle to this
|
||||||
|
shared memory region is passed to the new process in the 'child_info'
|
||||||
|
structure.
|
||||||
|
|
||||||
|
If there are no handles that need "fixing up" prior to starting another
|
||||||
|
process, cygheap_setup_for_child will also copy the contents of the
|
||||||
|
cygwin heap to the shared memory region.
|
||||||
|
|
||||||
|
If there are any handles that need "fixing up" prior to invoking
|
||||||
|
another process (i.e., sockets) then the creation of the shared
|
||||||
|
memory region and copying of the current cygwin heap is a two
|
||||||
|
step process.
|
||||||
|
|
||||||
|
First the shared memory region is created and the process is started
|
||||||
|
in a "CREATE_SUSPENDED" state, inheriting the handle. After the
|
||||||
|
process is created, the fixup_before_*() functions are called. These
|
||||||
|
set information in the heap and duplicate handles in the child, essentially
|
||||||
|
ensuring that the child's fd table is correct.
|
||||||
|
|
||||||
|
(Note that it is vital that the cygwin heap should not grow during this
|
||||||
|
process. Currently, there is no guard against this happening so this
|
||||||
|
operation is not thread safe.)
|
||||||
|
|
||||||
|
Meanwhile, back in fork_parent, the function
|
||||||
|
cygheap_setup_for_child_cleanup is called. In the simple "one step"
|
||||||
|
case above, all that happens is that the shared memory is ummapped and
|
||||||
|
the handle referring to it is closed.
|
||||||
|
|
||||||
|
In the two step process, the cygheap is now copied to the shared memory
|
||||||
|
region, complete with new fdtab info (the child process will see the
|
||||||
|
updated information as soon as it starts). Then the memory is unmapped,
|
||||||
|
the handle is closed, and upon return the child process is started.
|
||||||
|
|
||||||
|
It is in the child process that the difference between Windows 9x and
|
||||||
|
Windows NT becomes evident.
|
||||||
|
|
||||||
|
Under Windows NT, the operation is simple. The shared memory handle is
|
||||||
|
used to map the information that the parent has set up into the cygheap
|
||||||
|
location in the child. This means that the child has a copy of the
|
||||||
|
cygwin heap existing in "shared memory" but the only process with a view
|
||||||
|
to this "shared memory" is the child.
|
||||||
|
|
||||||
|
Under Windows 9x, due to address limitations, we can't just map the
|
||||||
|
shared memory region into the cygheap position. So, instead, the memory
|
||||||
|
is mapped whereever Windows wants to put it, a new heap region is
|
||||||
|
allocated at the same place as in the parent, the contents of the shared
|
||||||
|
memory is *copied* to the new heap, and the shared memory is unmapped.
|
||||||
|
Simple, huh?
|
||||||
|
|
||||||
|
Why do we go to these contortions? Previous versions (<1.3.3) of cygwin
|
||||||
|
used to block when creating a child so that the child could copy the
|
||||||
|
parent's cygheap. The problem with this was that when a cygwin process
|
||||||
|
invoked a non-cygwin child, it would block forever waiting for the child
|
||||||
|
to let it know that it was done copying the heap. That caused
|
||||||
|
understandable complaints from people who wanted to run non-cygwin
|
||||||
|
applications "in the background".
|
||||||
|
|
||||||
|
In Cygwin 1.3.3 (and presumably beyond) the location of the cygwin heap
|
||||||
|
has been fixed to be at the end of the cygwin1.dll address space.
|
||||||
|
Previously, we let the "OS" choose where to allocate the cygwin heap in
|
||||||
|
the initial cygwin process and attempted to use this same location in
|
||||||
|
subsequent cygwin processes started from this parent.
|
||||||
|
|
||||||
|
This was basically done to accomodate Windows XP, although there were
|
||||||
|
sporadic complaints of cygwin heap failures in other pathological
|
||||||
|
situations with both NT and 9x. In Windows XP, Microsoft made the
|
||||||
|
allocation of memory less deterministic. This is certainly their right.
|
||||||
|
Cygwin was previously relying on undocumented and "iffy" behavior before.
|
||||||
|
|
||||||
|
We're not exactly on completely firm ground now, though. We are assuming
|
||||||
|
that there is sufficient space after the cygwin DLL for the allocation
|
||||||
|
of the cygwin heap. So far this assumption has proved workable but there
|
||||||
|
is no guarantee that newer versions of Windows won't break this assumption
|
||||||
|
too.
|
||||||
|
|
Loading…
Reference in New Issue