diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 82851aa4a..1670f7f8f 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,41 +1,5 @@ 2011-05-28 Christopher Faylor - - * 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 - - * 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 - + Ryan Johnson * dll_init.c (dll_list::load_after_fork): Don't clear in_forkee here. * fork.cc (frok::errmsg): Rename from 'error'. diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc index 7882ed65f..68a974b7b 100644 --- a/winsup/cygwin/dll_init.cc +++ b/winsup/cygwin/dll_init.cc @@ -116,18 +116,6 @@ dll_list::operator[] (const PWCHAR name) 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 /* Allocate space for a dll struct. */ @@ -173,14 +161,14 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type) d->handle = h; d->has_dtors = true; 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; - append (d); + if (end == NULL) + end = &start; /* Point to "end" of dll chain. */ + end->next = d; /* Standard linked list stuff. */ + d->next = NULL; + d->prev = end; + end = d; + tot++; if (type == DLL_LOAD) loaded_dlls++; } @@ -189,119 +177,6 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type) return d; } -void -dll_list::append (dll* d) -{ - if (end == NULL) - end = &start; /* Point to "end" of dll chain. */ - end->next = d; /* Standard linked list stuff. */ - d->next = NULL; - d->prev = end; - end = d; - tot++; -} - -void dll_list::populate_deps (dll* 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_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) - covering at least _dll_size_ bytes. However, we must take care not - to clobber the dll's target address range because it often overlaps. - */ +/* Mark one page at "here" as reserved. This may force + Windows NT to load a DLL elsewhere. */ static DWORD -reserve_at (const PWCHAR name, DWORD here, DWORD dll_base, DWORD dll_size) +reserve_at (const PWCHAR name, DWORD here) { DWORD size; MEMORY_BASIC_INFORMATION mb; if (!VirtualQuery ((void *) here, &mb, sizeof (mb))) - api_fatal ("couldn't examine memory at %08lx while mapping %W, %E", - here, name); + size = 64 * 1024; + if (mb.State != MEM_FREE) return 0; 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)) api_fatal ("couldn't allocate memory %p(%d) for '%W' alignment, %E\n", 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. Block memory at it's preferred address and try again. */ if ((DWORD) h > (DWORD) d->handle) - preferred_block = reserve_at (d->name, (DWORD) h, - (DWORD) d->handle, d->image_size); + preferred_block = reserve_at (d->name, (DWORD) h); } } diff --git a/winsup/cygwin/dll_init.h b/winsup/cygwin/dll_init.h index 3fbe8760f..d14cc6cb9 100644 --- a/winsup/cygwin/dll_init.h +++ b/winsup/cygwin/dll_init.h @@ -52,10 +52,6 @@ struct dll int count; bool has_dtors; dll_type type; - DWORD image_size; - long ndeps; - dll** deps; - PWCHAR modname; WCHAR name[1]; void detach (); int init (); @@ -88,13 +84,6 @@ public: void detach (void *); void init (); 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 () { while ((hold = hold->next)) @@ -120,25 +109,6 @@ public: 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; void dll_global_dtors (); diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index 1ac2b8a45..3ec7fa8c5 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -625,7 +625,7 @@ fork () the thread-local storage. A process forking too deeply will run into the problem to be out of temporary TLS path buffers. */ tmp_pathbuf tp; - + if (!held_everything) { if (exit_state) @@ -634,12 +634,6 @@ fork () 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); volatile char * volatile esp;