From fc6a0dc849d07c3aace5e06fa6eee01b45e83d68 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Tue, 2 Feb 2010 02:00:01 +0000 Subject: [PATCH] * dcrt0.cc (atexit_lock): Delete. (cygwin_exit): Remove atexit lock. (cygwin_atexit): Ditto. Rename parameter to match newlib. Call __cxa_atexit when invoked by a registered DLL. * dll_init.cc (remove_dll_atexit): Delete. (dll_list::find): New function. (dll_list::detach): Use dll_list::find to find dll associated with return address. Use __cxa_finalize to run atexit functions associated with the dll. (cygwin_detach_dll): Don't assume that HANDLE == void *. * dll_init.h (dll_list::find): Declare. (__cxa_atexit): Ditto. (__cxa_finalize): Ditto. * init.cc (dll_entry): Clarify comment. --- winsup/cygwin/ChangeLog | 18 +++++++++ winsup/cygwin/dcrt0.cc | 12 ++---- winsup/cygwin/dll_init.cc | 80 +++++++++++++++------------------------ winsup/cygwin/dll_init.h | 6 +++ winsup/cygwin/init.cc | 2 +- 5 files changed, 58 insertions(+), 60 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index f49a31c8e..5246135e1 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,21 @@ +2010-02-01 Christopher Faylor + + * dcrt0.cc (atexit_lock): Delete. + (cygwin_exit): Remove atexit lock. + (cygwin_atexit): Ditto. Rename parameter to match newlib. Call + __cxa_atexit when invoked by a registered DLL. + * dll_init.cc (remove_dll_atexit): Delete. + (dll_list::find): New function. + (dll_list::detach): Use dll_list::find to find dll associated with + return address. Use __cxa_finalize to run atexit functions associated + with the dll. + (cygwin_detach_dll): Don't assume that HANDLE == void *. + * dll_init.h (dll_list::find): Declare. + (__cxa_atexit): Ditto. + (__cxa_finalize): Ditto. + + * init.cc (dll_entry): Clarify comment. + 2010-02-02 Dave Korn * how-startup-shutdown-works.txt: Add new document. diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index f1f904ac7..7cd383bf7 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -1108,24 +1108,18 @@ do_exit (int status) myself.exit (n); } -static NO_COPY muto atexit_lock; - extern "C" int -cygwin_atexit (void (*function)(void)) +cygwin_atexit (void (*fn) (void)) { int res; - atexit_lock.init ("atexit_lock"); - atexit_lock.acquire (); - res = atexit (function); - atexit_lock.release (); + dll *d = dlls.find ((void *) _my_tls.retaddr ()); + res = d ? __cxa_atexit ((void (*) (void *)) fn, NULL, d) : atexit (fn); return res; } extern "C" void cygwin_exit (int n) { - if (atexit_lock) - atexit_lock.acquire (); exit (n); } diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc index 763964bac..e449f7777 100644 --- a/winsup/cygwin/dll_init.cc +++ b/winsup/cygwin/dll_init.cc @@ -143,63 +143,43 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type) return d; } -/* This function looks for every atexit function registered in the - about-to-be-unloaded DLL and runs it. - - newlib does not provide any method for selectively running elements - from the atexit() queue so we have to roll our own. - - Note that this is not foolproof since a function in the DLL could - register an atexit function outside of the DLL and that should be - run when the DLL detachs. */ -static void -remove_dll_atexit (MEMORY_BASIC_INFORMATION& m) +dll * +dll_list::find (void *retaddr) { - unsigned char *dll_beg = (unsigned char *) m.AllocationBase; - unsigned char *dll_end = (unsigned char *) m.AllocationBase + m.RegionSize; - struct _atexit *p = _GLOBAL_REENT->_atexit; - for (int n = p->_ind - 1; n >= 0; n--) - { - void (*fn) (void) = p->_fns[n]; - if ((unsigned char *) fn >= dll_beg && (unsigned char *) fn < dll_end) - { - fn (); - p->_fns[n] = NULL; - } - } + MEMORY_BASIC_INFORMATION m; + if (!VirtualQuery (retaddr, &m, sizeof m)) + return NULL; + HMODULE h = (HMODULE) m.AllocationBase; + + dll *d = &start; + while ((d = d->next)) + if (d->handle == h) + break; + return d; } /* Detach a DLL from the chain. */ void dll_list::detach (void *retaddr) { - if (!myself || exit_state) + dll *d; + if (!myself || exit_state || !(d = find (retaddr))) return; - MEMORY_BASIC_INFORMATION m; - if (!VirtualQuery (retaddr, &m, sizeof m)) - return; - HMODULE h = (HMODULE) m.AllocationBase; - - dll *d = &start; - while ((d = d->next)) - if (d->handle != h) - continue; - else if (d->count <= 0) - system_printf ("WARNING: trying to detach an already detached dll ..."); - else if (--d->count == 0) - { - remove_dll_atexit (m); - d->run_dtors (); - d->prev->next = d->next; - if (d->next) - d->next->prev = d->prev; - if (d->type == DLL_LOAD) - loaded_dlls--; - if (end == d) - end = d->prev; - cfree (d); - break; - } + if (d->count <= 0) + system_printf ("WARNING: trying to detach an already detached dll ..."); + if (--d->count == 0) + { + __cxa_finalize (d); + d->run_dtors (); + d->prev->next = d->next; + if (d->next) + d->next->prev = d->prev; + if (d->type == DLL_LOAD) + loaded_dlls--; + if (end == d) + end = d->prev; + cfree (d); + } } /* Initialization for all linked DLLs, called by dll_crt0_1. */ @@ -427,7 +407,7 @@ cygwin_detach_dll (dll *) { HANDLE retaddr; if (_my_tls.isinitialized ()) - retaddr = (HANDLE) _my_tls.retaddr (); + retaddr = (void *) _my_tls.retaddr (); else retaddr = __builtin_return_address (0); dlls.detach (retaddr); diff --git a/winsup/cygwin/dll_init.h b/winsup/cygwin/dll_init.h index 90cfa03e2..b37406e82 100644 --- a/winsup/cygwin/dll_init.h +++ b/winsup/cygwin/dll_init.h @@ -79,6 +79,7 @@ public: int reload_on_fork; dll *operator [] (const PWCHAR name); dll *alloc (HINSTANCE, per_process *, dll_type); + dll *find (void *); void detach (void *); void init (); void load_after_fork (HANDLE); @@ -100,3 +101,8 @@ public: extern dll_list dlls; void dll_global_dtors (); + +/* These probably belong in a newlib header but we can keep them here + for now. */ +extern "C" int __cxa_atexit(void (*)(void*), void*, void*); +extern "C" int __cxa_finalize(void*); diff --git a/winsup/cygwin/init.cc b/winsup/cygwin/init.cc index efdd775c4..9bf49f2a3 100644 --- a/winsup/cygwin/init.cc +++ b/winsup/cygwin/init.cc @@ -126,7 +126,7 @@ dll_entry (HANDLE h, DWORD reason, void *static_load) cygwin_hmodule = (HMODULE) h; dynamically_loaded = (static_load == NULL); - /* Is the stack at an unusual address? This is, an address which + /* Is the stack at an unusual address? That is, an address which is in the usual space occupied by the process image, but below the auto load address of DLLs? Check if we're running in WOW64 on a 64 bit machine *and* are