Revert previous checkins as they introduced a bug when running zsh.

This commit is contained in:
Christopher Faylor 2011-05-28 20:41:51 +00:00
parent 17a5c8c36e
commit 07f89f85db
4 changed files with 15 additions and 225 deletions

View File

@ -1,41 +1,5 @@
2011-05-28 Christopher Faylor <me.cygwin2011@cgf.cx> 2011-05-28 Christopher Faylor <me.cygwin2011@cgf.cx>
Ryan Johnson <ryan.johnson@cs.utoronto.ca>
* dll_init.cc (reserve_upto): Remove.
(release_upto): Ditto.
(dll_list::reserve_space): New function to reserve space needed by
DLL_LOAD dlls early in the fork process.
(dll_list::load_after_fork): Rewrite to use recursion for tracking
reservations made while trying to make dlls land where they belong.
(dll_list::load_after_fork_impl): Ditto.
(dll_list::alloc): Initialize image base field.
* dll_init.h (struct dll_list): declare new functions.
(dll::image_size): New member.
2011-05-28 Ryan Johnson <ryan.johnson@cs.utoronto.ca>
* dll_init.cc (dll_list::find_by_modname): New function to search the
dll list for a module name only (no path).
(dll_list::alloc): Initialize newly-added members of struct dll.
(dll_list::append): New function to factor out the append operation
(used by dll_list::topsort).
(dll_list::populate_deps): New function to identify dll dependencies.
(dll_list::topsort): New function to sort the dll list topologically by
dependencies.
(dll_list::topsort_visit): New helper function for the above.
* dll_init.h (dll::ndeps): New class member.
(dll::deps): Ditto.
(dll::modname): Ditto.
(dll_list::find_by_modname): New function related to topsort.
(dll_list::populate_all_deps): Ditto.
(dll_list::populate_deps): Ditto.
(dll_list::topsort): Ditto.
(dll_list::topsort_visit): Ditto.
(dll_list::append): Ditto.
(pefile): New struct allowing simple introspection of dll images.
* fork.cc (fork): Topologically sort the dll list before forking.
2011-05-28 Christopher Faylor <me.cygwin2011@cgf.cx>
* dll_init.c (dll_list::load_after_fork): Don't clear in_forkee here. * dll_init.c (dll_list::load_after_fork): Don't clear in_forkee here.
* fork.cc (frok::errmsg): Rename from 'error'. * fork.cc (frok::errmsg): Rename from 'error'.

View File

@ -116,18 +116,6 @@ dll_list::operator[] (const PWCHAR name)
return NULL; return NULL;
} }
/* Look for a dll based on is short name only (no path) */
dll *
dll_list::find_by_modname (const PWCHAR name)
{
dll *d = &start;
while ((d = d->next) != NULL)
if (!wcscasecmp (name, d->modname))
return d;
return NULL;
}
#define RETRIES 1000 #define RETRIES 1000
/* Allocate space for a dll struct. */ /* Allocate space for a dll struct. */
@ -173,25 +161,7 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
d->handle = h; d->handle = h;
d->has_dtors = true; d->has_dtors = true;
d->p = p; d->p = p;
d->image_size = ((pefile*)h)->optional_hdr ()->SizeOfImage;
d->ndeps = 0;
d->deps = NULL;
d->modname = wcsrchr (d->name, L'\\');
if (d->modname)
d->modname++;
d->type = type; d->type = type;
append (d);
if (type == DLL_LOAD)
loaded_dlls++;
}
guard (false);
assert (p->envptr != NULL);
return d;
}
void
dll_list::append (dll* d)
{
if (end == NULL) if (end == NULL)
end = &start; /* Point to "end" of dll chain. */ end = &start; /* Point to "end" of dll chain. */
end->next = d; /* Standard linked list stuff. */ end->next = d; /* Standard linked list stuff. */
@ -199,108 +169,13 @@ dll_list::append (dll* d)
d->prev = end; d->prev = end;
end = d; end = d;
tot++; tot++;
if (type == DLL_LOAD)
loaded_dlls++;
} }
guard (false);
void dll_list::populate_deps (dll* d) assert (p->envptr != NULL);
{ return d;
WCHAR wmodname[NT_MAX_PATH];
pefile* pef = (pefile*) d->handle;
PIMAGE_DATA_DIRECTORY dd = pef->idata_dir (IMAGE_DIRECTORY_ENTRY_IMPORT);
/* Annoyance: calling crealloc with a NULL pointer will use the
wrong heap and crash, so we have to replicate some code */
long maxdeps = 4;
d->deps = (dll**) cmalloc (HEAP_2_DLL, maxdeps*sizeof (dll*));
d->ndeps = 0;
for (PIMAGE_IMPORT_DESCRIPTOR id=
(PIMAGE_IMPORT_DESCRIPTOR) pef->rva (dd->VirtualAddress);
dd->Size && id->Name;
id++)
{
char* modname = pef->rva (id->Name);
sys_mbstowcs (wmodname, NT_MAX_PATH, modname);
if (dll* dep = find_by_modname (wmodname))
{
if (d->ndeps >= maxdeps)
{
maxdeps = 2*(1+maxdeps);
d->deps = (dll**) crealloc (d->deps, maxdeps*sizeof (dll*));
} }
d->deps[d->ndeps++] = dep;
}
}
/* add one to differentiate no deps from unknown */
d->ndeps++;
}
void
dll_list::topsort ()
{
/* Anything to do? */
if (!end)
return;
/* make sure we have all the deps available */
dll* d = &start;
while ((d = d->next))
if (!d->ndeps)
populate_deps (d);
/* unlink head and tail pointers so the sort can rebuild the list */
d = start.next;
start.next = end = NULL;
topsort_visit (d, true);
/* clear node markings made by the sort */
d = &start;
while ((d = d->next))
{
debug_printf ("%W", d->modname);
for (int i=1; i < -d->ndeps; i++)
debug_printf ("-> %W", d->deps[i-1]->modname);
/* It would be really nice to be able to keep this information
around for next time, but we don't have an easy way to
invalidate cached dependencies when a module unloads. */
d->ndeps = 0;
cfree (d->deps);
d->deps = NULL;
}
}
/* A recursive in-place topological sort. The result is ordered so that
dependencies of a dll appear before it in the list.
NOTE: this algorithm is guaranteed to terminate with a "partial
order" of dlls but does not do anything smart about cycles: an
arbitrary dependent dll will necessarily appear first. Perhaps not
surprisingly, Windows ships several dlls containing dependency
cycles, including SspiCli/RPCRT4.dll and a lovely tangle involving
USP10/LPK/GDI32/USER32.dll). Fortunately, we don't care about
Windows DLLs here, and cygwin dlls should behave better */
void
dll_list::topsort_visit (dll* d, bool seek_tail)
{
/* Recurse to the end of the dll chain, then visit nodes as we
unwind. We do this because once we start visiting nodes we can no
longer trust any _next_ pointers.
We "mark" visited nodes (to avoid revisiting them) by negating
ndeps (undone once the sort completes). */
if (seek_tail && d->next)
topsort_visit (d->next, true);
if (d->ndeps > 0)
{
d->ndeps = -d->ndeps;
for (long i=1; i < -d->ndeps; i++)
topsort_visit (d->deps[i-1], false);
append (d);
}
}
dll * dll *
dll_list::find (void *retaddr) dll_list::find (void *retaddr)
@ -417,33 +292,21 @@ release_upto (const PWCHAR name, DWORD here)
} }
} }
/* Reserve the chunk of free address space starting _here_ and (usually) /* Mark one page at "here" as reserved. This may force
covering at least _dll_size_ bytes. However, we must take care not Windows NT to load a DLL elsewhere. */
to clobber the dll's target address range because it often overlaps.
*/
static DWORD static DWORD
reserve_at (const PWCHAR name, DWORD here, DWORD dll_base, DWORD dll_size) reserve_at (const PWCHAR name, DWORD here)
{ {
DWORD size; DWORD size;
MEMORY_BASIC_INFORMATION mb; MEMORY_BASIC_INFORMATION mb;
if (!VirtualQuery ((void *) here, &mb, sizeof (mb))) if (!VirtualQuery ((void *) here, &mb, sizeof (mb)))
api_fatal ("couldn't examine memory at %08lx while mapping %W, %E", size = 64 * 1024;
here, name);
if (mb.State != MEM_FREE) if (mb.State != MEM_FREE)
return 0; return 0;
size = mb.RegionSize; size = mb.RegionSize;
// don't clobber the space where we want the dll to land
DWORD end = here + size;
DWORD dll_end = dll_base + dll_size;
if (dll_base < here && dll_end > here)
here = dll_end; // the dll straddles our left edge
else if (dll_base >= here && dll_base < end)
end = dll_base; // the dll overlaps partly or fully to our right
size = end - here;
if (!VirtualAlloc ((void *) here, size, MEM_RESERVE, PAGE_NOACCESS)) if (!VirtualAlloc ((void *) here, size, MEM_RESERVE, PAGE_NOACCESS))
api_fatal ("couldn't allocate memory %p(%d) for '%W' alignment, %E\n", api_fatal ("couldn't allocate memory %p(%d) for '%W' alignment, %E\n",
here, size, name); here, size, name);
@ -521,8 +384,7 @@ dll_list::load_after_fork (HANDLE parent)
can in the child, due to differences in the load ordering. can in the child, due to differences in the load ordering.
Block memory at it's preferred address and try again. */ Block memory at it's preferred address and try again. */
if ((DWORD) h > (DWORD) d->handle) if ((DWORD) h > (DWORD) d->handle)
preferred_block = reserve_at (d->name, (DWORD) h, preferred_block = reserve_at (d->name, (DWORD) h);
(DWORD) d->handle, d->image_size);
} }
} }

View File

@ -52,10 +52,6 @@ struct dll
int count; int count;
bool has_dtors; bool has_dtors;
dll_type type; dll_type type;
DWORD image_size;
long ndeps;
dll** deps;
PWCHAR modname;
WCHAR name[1]; WCHAR name[1];
void detach (); void detach ();
int init (); int init ();
@ -88,13 +84,6 @@ public:
void detach (void *); void detach (void *);
void init (); void init ();
void load_after_fork (HANDLE); void load_after_fork (HANDLE);
dll *find_by_modname (const PWCHAR name);
void populate_all_deps ();
void populate_deps (dll* d);
void topsort ();
void topsort_visit (dll* d, bool goto_tail);
void append (dll* d);
dll *inext () dll *inext ()
{ {
while ((hold = hold->next)) while ((hold = hold->next))
@ -120,25 +109,6 @@ public:
dll_list () { protect.init ("dll_list"); } dll_list () { protect.init ("dll_list"); }
}; };
/* References:
http://msdn.microsoft.com/en-us/windows/hardware/gg463125
http://msdn.microsoft.com/en-us/library/ms809762.aspx
*/
/* FIXME: Integrate with other similar uses in source. */
struct pefile
{
IMAGE_DOS_HEADER dos_hdr;
char* rva (long offset) { return (char*) this + offset; }
PIMAGE_NT_HEADERS32 pe_hdr () { return (PIMAGE_NT_HEADERS32) rva (dos_hdr.e_lfanew); }
PIMAGE_OPTIONAL_HEADER32 optional_hdr () { return &pe_hdr ()->OptionalHeader; }
PIMAGE_DATA_DIRECTORY idata_dir (DWORD which)
{
PIMAGE_OPTIONAL_HEADER32 oh = optional_hdr ();
return (which < oh->NumberOfRvaAndSizes)? oh->DataDirectory + which : 0;
}
};
extern dll_list dlls; extern dll_list dlls;
void dll_global_dtors (); void dll_global_dtors ();

View File

@ -634,12 +634,6 @@ fork ()
return -1; return -1;
} }
/* Put the dll list in topological dependency ordering, in
hopes that the child will have a better shot at loading dlls
properly if it only has to deal with one at a time.
*/
dlls.topsort ();
ischild = !!setjmp (grouped.ch.jmp); ischild = !!setjmp (grouped.ch.jmp);
volatile char * volatile esp; volatile char * volatile esp;