Home | History | Annotate | Line # | Download | only in config
      1   1.1  mrg /* __cxa_atexit backwards-compatibility support for Darwin.
      2  1.10  mrg    Copyright (C) 2006-2022 Free Software Foundation, Inc.
      3   1.1  mrg 
      4   1.1  mrg This file is part of GCC.
      5   1.1  mrg 
      6   1.1  mrg GCC is free software; you can redistribute it and/or modify it under
      7   1.1  mrg the terms of the GNU General Public License as published by the Free
      8   1.1  mrg Software Foundation; either version 3, or (at your option) any later
      9   1.1  mrg version.
     10   1.1  mrg 
     11   1.1  mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     12   1.1  mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13   1.1  mrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14   1.1  mrg for more details.
     15   1.1  mrg 
     16   1.1  mrg Under Section 7 of GPL version 3, you are granted additional
     17   1.1  mrg permissions described in the GCC Runtime Library Exception, version
     18   1.1  mrg 3.1, as published by the Free Software Foundation.
     19   1.1  mrg 
     20   1.1  mrg You should have received a copy of the GNU General Public License and
     21   1.1  mrg a copy of the GCC Runtime Library Exception along with this program;
     22   1.1  mrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23   1.1  mrg <http://www.gnu.org/licenses/>.  */
     24   1.1  mrg 
     25   1.1  mrg /* Don't do anything if we are compiling for a kext multilib. */
     26   1.1  mrg #ifdef __PIC__
     27   1.1  mrg 
     28   1.1  mrg #include "tconfig.h"
     29   1.1  mrg #include "tsystem.h"
     30   1.1  mrg 
     31   1.1  mrg #include <dlfcn.h>
     32   1.1  mrg #include <stdbool.h>
     33   1.1  mrg #include <stdlib.h>
     34   1.1  mrg #include <string.h>
     35   1.1  mrg 
     36   1.1  mrg /* This file works around two different problems.
     37   1.1  mrg 
     38   1.1  mrg    The first problem is that there is no __cxa_atexit on Mac OS versions
     39   1.1  mrg    before 10.4.  It fixes this by providing a complete atexit and
     40   1.1  mrg    __cxa_atexit emulation called from the regular atexit.
     41   1.1  mrg 
     42   1.1  mrg    The second problem is that on all shipping versions of Mac OS,
     43   1.1  mrg    __cxa_finalize and exit() don't work right: they don't run routines
     44   1.1  mrg    that were registered while other atexit routines are running.  This
     45   1.1  mrg    is worked around by wrapping each atexit/__cxa_atexit routine with
     46   1.1  mrg    our own routine which ensures that any __cxa_atexit calls while it
     47   1.1  mrg    is running are honoured.
     48   1.1  mrg 
     49   1.1  mrg    There are still problems which this does not solve.  Before 10.4,
     50   1.1  mrg    shared objects linked with previous compilers won't have their
     51   1.1  mrg    atexit calls properly interleaved with code compiled with newer
     52   1.1  mrg    compilers.  Also, atexit routines registered from shared objects
     53   1.1  mrg    linked with previous compilers won't get the bug fix.  */
     54   1.1  mrg 
     55   1.1  mrg typedef int (*cxa_atexit_p)(void (*func) (void*), void* arg, const void* dso);
     56   1.1  mrg typedef void (*cxa_finalize_p)(const void *dso);
     57   1.1  mrg typedef int (*atexit_p)(void (*func)(void));
     58   1.1  mrg 
     59   1.1  mrg /* These are from "keymgr.h".  */
     60   1.1  mrg extern void *_keymgr_get_and_lock_processwide_ptr (unsigned key);
     61   1.1  mrg extern int _keymgr_get_and_lock_processwide_ptr_2 (unsigned, void **);
     62   1.1  mrg extern int _keymgr_set_and_unlock_processwide_ptr (unsigned key, void *ptr);
     63   1.1  mrg 
     64   1.1  mrg extern void *__keymgr_global[];
     65   1.1  mrg typedef struct _Sinfo_Node {
     66   1.1  mrg         unsigned int size ;             /*size of this node*/
     67   1.1  mrg         unsigned short major_version ;  /*API major version.*/
     68   1.1  mrg         unsigned short minor_version ;  /*API minor version.*/
     69   1.1  mrg         } _Tinfo_Node ;
     70   1.1  mrg 
     71   1.1  mrg #ifdef __ppc__
     72   1.1  mrg #define CHECK_KEYMGR_ERROR(e) \
     73   1.1  mrg   (((_Tinfo_Node *)__keymgr_global[2])->major_version >= 4 ? (e) : 0)
     74   1.1  mrg #else
     75   1.1  mrg #define CHECK_KEYMGR_ERROR(e) (e)
     76   1.1  mrg #endif
     77   1.1  mrg 
     78   1.1  mrg /* Our globals are stored under this keymgr index.  */
     79   1.1  mrg #define KEYMGR_ATEXIT_LIST	14
     80   1.1  mrg 
     81   1.1  mrg /* The different kinds of callback routines.  */
     82   1.1  mrg typedef void (*atexit_callback)(void);
     83   1.1  mrg typedef void (*cxa_atexit_callback)(void *);
     84   1.1  mrg 
     85   1.1  mrg /* This structure holds a routine to call.  There may be extra fields
     86   1.1  mrg    at the end of the structure that this code doesn't know about.  */
     87   1.1  mrg struct one_atexit_routine
     88   1.1  mrg {
     89   1.1  mrg   union {
     90   1.1  mrg     atexit_callback ac;
     91   1.1  mrg     cxa_atexit_callback cac;
     92   1.1  mrg   } callback;
     93   1.1  mrg   /* has_arg is 0/2/4 if 'ac' is live, 1/3/5 if 'cac' is live.
     94   1.1  mrg      Higher numbers indicate a later version of the structure that this
     95   1.1  mrg      code doesn't understand and will ignore.  */
     96   1.1  mrg   int has_arg;
     97   1.1  mrg   void * arg;
     98   1.1  mrg };
     99   1.1  mrg 
    100   1.1  mrg struct atexit_routine_list
    101   1.1  mrg {
    102   1.1  mrg   struct atexit_routine_list * next;
    103   1.1  mrg   struct one_atexit_routine r;
    104   1.1  mrg };
    105   1.1  mrg 
    106   1.1  mrg /* The various possibilities for status of atexit().  */
    107   1.1  mrg enum atexit_status {
    108   1.1  mrg   atexit_status_unknown = 0,
    109   1.1  mrg   atexit_status_missing = 1,
    110   1.1  mrg   atexit_status_broken = 2,
    111   1.1  mrg   atexit_status_working = 16
    112   1.1  mrg };
    113   1.1  mrg 
    114   1.1  mrg struct keymgr_atexit_list
    115   1.1  mrg {
    116   1.1  mrg   /* Version of this list.  This code knows only about version 0.
    117   1.1  mrg      If the version is higher than 0, this code may add new atexit routines
    118   1.1  mrg      but should not attempt to run the list.  */
    119   1.1  mrg   short version;
    120   1.1  mrg   /* 1 if an atexit routine is currently being run by this code, 0
    121   1.1  mrg      otherwise.  */
    122   1.1  mrg   char running_routines;
    123   1.1  mrg   /* Holds a value from 'enum atexit_status'.  */
    124   1.1  mrg   unsigned char atexit_status;
    125   1.1  mrg   /* The list of atexit and cxa_atexit routines registered.  If
    126   1.1  mrg    atexit_status_missing it contains all routines registered while
    127   1.1  mrg    linked with this code.  If atexit_status_broken it contains all
    128   1.1  mrg    routines registered during cxa_finalize while linked with this
    129   1.1  mrg    code.  */
    130   1.1  mrg   struct atexit_routine_list *l;
    131   1.1  mrg   /* &__cxa_atexit; set if atexit_status >= atexit_status_broken.  */
    132   1.1  mrg   cxa_atexit_p cxa_atexit_f;
    133   1.1  mrg   /* &__cxa_finalize; set if atexit_status >= atexit_status_broken.  */
    134   1.1  mrg   cxa_finalize_p cxa_finalize_f;
    135   1.1  mrg   /* &atexit; set if atexit_status >= atexit_status_working
    136   1.1  mrg      or atexit_status == atexit_status_missing.  */
    137   1.1  mrg   atexit_p atexit_f;
    138   1.1  mrg };
    139   1.1  mrg 
    140   1.1  mrg /* Return 0 if __cxa_atexit has the bug it has in Mac OS 10.4: it
    141   1.1  mrg    fails to call routines registered while an atexit routine is
    142   1.1  mrg    running.  Return 1 if it works properly, and -1 if an error occurred.  */
    143   1.1  mrg 
    144   1.1  mrg struct atexit_data
    145   1.1  mrg {
    146   1.1  mrg   int result;
    147   1.1  mrg   cxa_atexit_p cxa_atexit;
    148   1.1  mrg };
    149   1.1  mrg 
    150   1.1  mrg static void cxa_atexit_check_2 (void *arg)
    151   1.1  mrg {
    152   1.1  mrg   ((struct atexit_data *)arg)->result = 1;
    153   1.1  mrg }
    154   1.1  mrg 
    155   1.1  mrg static void cxa_atexit_check_1 (void *arg)
    156   1.1  mrg {
    157   1.1  mrg   struct atexit_data * aed = arg;
    158   1.1  mrg   if (aed->cxa_atexit (cxa_atexit_check_2, arg, arg) != 0)
    159   1.1  mrg     aed->result = -1;
    160   1.1  mrg }
    161   1.1  mrg 
    162   1.1  mrg static int
    163   1.1  mrg check_cxa_atexit (cxa_atexit_p cxa_atexit, cxa_finalize_p cxa_finalize)
    164   1.1  mrg {
    165   1.1  mrg   struct atexit_data aed = { 0, cxa_atexit };
    166   1.1  mrg 
    167   1.1  mrg   /* We re-use &aed as the 'dso' parameter, since it's a unique address.  */
    168   1.1  mrg   if (cxa_atexit (cxa_atexit_check_1, &aed, &aed) != 0)
    169   1.1  mrg     return -1;
    170   1.1  mrg   cxa_finalize (&aed);
    171   1.1  mrg   if (aed.result == 0)
    172   1.1  mrg     {
    173   1.1  mrg       /* Call __cxa_finalize again to make sure that cxa_atexit_check_2
    174   1.1  mrg 	 is removed from the list before AED goes out of scope.  */
    175   1.1  mrg       cxa_finalize (&aed);
    176   1.1  mrg       aed.result = 0;
    177   1.1  mrg     }
    178   1.1  mrg   return aed.result;
    179   1.1  mrg }
    180   1.1  mrg 
    181   1.1  mrg #ifdef __ppc__
    182   1.1  mrg /* This comes from Csu.  It works only before 10.4.  The prototype has
    183   1.1  mrg    been altered a bit to avoid casting.  */
    184   1.1  mrg extern int _dyld_func_lookup(const char *dyld_func_name,
    185   1.1  mrg      void *address) __attribute__((visibility("hidden")));
    186   1.1  mrg 
    187   1.1  mrg static void our_atexit (void);
    188   1.1  mrg 
    189   1.1  mrg /* We're running on 10.3.9.  Find the address of the system atexit()
    190   1.1  mrg    function.  So easy to say, so hard to do.  */
    191   1.1  mrg static atexit_p
    192   1.1  mrg find_atexit_10_3 (void)
    193   1.1  mrg {
    194   1.1  mrg   unsigned int (*dyld_image_count_fn)(void);
    195   1.1  mrg   const char *(*dyld_get_image_name_fn)(unsigned int image_index);
    196   1.1  mrg   const void *(*dyld_get_image_header_fn)(unsigned int image_index);
    197   1.1  mrg   const void *(*NSLookupSymbolInImage_fn)(const void *image,
    198   1.1  mrg 					  const char *symbolName,
    199   1.1  mrg 					  unsigned int options);
    200   1.1  mrg   void *(*NSAddressOfSymbol_fn)(const void *symbol);
    201   1.1  mrg   unsigned i, count;
    202   1.1  mrg 
    203   1.1  mrg   /* Find some dyld functions.  */
    204   1.1  mrg   _dyld_func_lookup("__dyld_image_count", &dyld_image_count_fn);
    205   1.1  mrg   _dyld_func_lookup("__dyld_get_image_name", &dyld_get_image_name_fn);
    206   1.1  mrg   _dyld_func_lookup("__dyld_get_image_header", &dyld_get_image_header_fn);
    207   1.1  mrg   _dyld_func_lookup("__dyld_NSLookupSymbolInImage", &NSLookupSymbolInImage_fn);
    208   1.1  mrg   _dyld_func_lookup("__dyld_NSAddressOfSymbol", &NSAddressOfSymbol_fn);
    209   1.1  mrg 
    210   1.1  mrg   /* If any of these don't exist, that's an error.  */
    211   1.1  mrg   if (! dyld_image_count_fn || ! dyld_get_image_name_fn
    212   1.1  mrg       || ! dyld_get_image_header_fn || ! NSLookupSymbolInImage_fn
    213   1.1  mrg       || ! NSAddressOfSymbol_fn)
    214   1.1  mrg     return NULL;
    215   1.1  mrg 
    216   1.1  mrg   count = dyld_image_count_fn ();
    217   1.1  mrg   for (i = 0; i < count; i++)
    218   1.1  mrg     {
    219   1.1  mrg       const char * path = dyld_get_image_name_fn (i);
    220   1.1  mrg       const void * image;
    221   1.1  mrg       const void * symbol;
    222   1.1  mrg 
    223   1.1  mrg       if (strcmp (path, "/usr/lib/libSystem.B.dylib") != 0)
    224   1.1  mrg 	continue;
    225   1.1  mrg       image = dyld_get_image_header_fn (i);
    226   1.1  mrg       if (! image)
    227   1.1  mrg 	return NULL;
    228   1.1  mrg       /* '4' is NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR.  */
    229   1.1  mrg       symbol = NSLookupSymbolInImage_fn (image, "_atexit", 4);
    230   1.1  mrg       if (! symbol)
    231   1.1  mrg 	return NULL;
    232   1.1  mrg       return NSAddressOfSymbol_fn (symbol);
    233   1.1  mrg     }
    234   1.1  mrg   return NULL;
    235   1.1  mrg }
    236   1.1  mrg #endif
    237   1.1  mrg 
    238   1.1  mrg /* Create (if necessary), find, lock, fill in, and return our globals.
    239   1.1  mrg    Return NULL on error, in which case the globals will not be locked.
    240   1.1  mrg    The caller should call keymgr_set_and_unlock.  */
    241   1.1  mrg static struct keymgr_atexit_list *
    242   1.1  mrg get_globals (void)
    243   1.1  mrg {
    244   1.1  mrg   struct keymgr_atexit_list * r;
    245   1.1  mrg 
    246   1.1  mrg #ifdef __ppc__
    247   1.1  mrg   /* 10.3.9 doesn't have _keymgr_get_and_lock_processwide_ptr_2 so the
    248   1.1  mrg      PPC side can't use it.  On 10.4 this just means the error gets
    249   1.1  mrg      reported a little later when
    250   1.1  mrg      _keymgr_set_and_unlock_processwide_ptr finds that the key was
    251   1.1  mrg      never locked.  */
    252   1.1  mrg   r = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
    253   1.1  mrg #else
    254   1.1  mrg   void * rr;
    255   1.1  mrg   if (_keymgr_get_and_lock_processwide_ptr_2 (KEYMGR_ATEXIT_LIST, &rr))
    256   1.1  mrg     return NULL;
    257   1.1  mrg   r = rr;
    258   1.1  mrg #endif
    259   1.1  mrg 
    260   1.1  mrg   if (r == NULL)
    261   1.1  mrg     {
    262   1.1  mrg       r = calloc (sizeof (struct keymgr_atexit_list), 1);
    263   1.1  mrg       if (! r)
    264   1.1  mrg 	return NULL;
    265   1.1  mrg     }
    266   1.1  mrg 
    267   1.1  mrg   if (r->atexit_status == atexit_status_unknown)
    268   1.1  mrg     {
    269   1.1  mrg       void *handle;
    270   1.1  mrg 
    271   1.1  mrg       handle = dlopen ("/usr/lib/libSystem.B.dylib", RTLD_NOLOAD);
    272   1.1  mrg       if (!handle)
    273   1.1  mrg 	{
    274   1.1  mrg #ifdef __ppc__
    275   1.1  mrg 	  r->atexit_status = atexit_status_missing;
    276   1.1  mrg 	  r->atexit_f = find_atexit_10_3 ();
    277   1.1  mrg 	  if (! r->atexit_f)
    278   1.1  mrg 	    goto error;
    279   1.1  mrg 	  if (r->atexit_f (our_atexit))
    280   1.1  mrg 	    goto error;
    281   1.1  mrg #else
    282   1.1  mrg 	  goto error;
    283   1.1  mrg #endif
    284   1.1  mrg 	}
    285   1.1  mrg       else
    286   1.1  mrg 	{
    287   1.1  mrg 	  int chk_result;
    288   1.1  mrg 
    289   1.1  mrg 	  r->cxa_atexit_f = (cxa_atexit_p)dlsym (handle, "__cxa_atexit");
    290   1.1  mrg 	  r->cxa_finalize_f = (cxa_finalize_p)dlsym (handle, "__cxa_finalize");
    291   1.1  mrg 	  if (! r->cxa_atexit_f || ! r->cxa_finalize_f)
    292   1.1  mrg 	    goto error;
    293   1.1  mrg 
    294   1.1  mrg 	  chk_result = check_cxa_atexit (r->cxa_atexit_f, r->cxa_finalize_f);
    295   1.1  mrg 	  if (chk_result == -1)
    296   1.1  mrg 	    goto error;
    297   1.1  mrg 	  else if (chk_result == 0)
    298   1.1  mrg 	    r->atexit_status = atexit_status_broken;
    299   1.1  mrg 	  else
    300   1.1  mrg 	    {
    301   1.1  mrg 	      r->atexit_f = (atexit_p)dlsym (handle, "atexit");
    302   1.1  mrg 	      if (! r->atexit_f)
    303   1.1  mrg 		goto error;
    304   1.1  mrg 	      r->atexit_status = atexit_status_working;
    305   1.1  mrg 	    }
    306   1.1  mrg 	}
    307   1.1  mrg     }
    308   1.1  mrg 
    309   1.1  mrg   return r;
    310   1.1  mrg 
    311   1.1  mrg  error:
    312   1.1  mrg   _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, r);
    313   1.1  mrg   return NULL;
    314   1.1  mrg }
    315   1.1  mrg 
    316   1.1  mrg /* Add TO_ADD to ATEXIT_LIST.  ATEXIT_LIST may be NULL but is
    317   1.1  mrg    always the result of calling _keymgr_get_and_lock_processwide_ptr and
    318   1.1  mrg    so KEYMGR_ATEXIT_LIST is known to be locked; this routine is responsible
    319   1.1  mrg    for unlocking it.  */
    320   1.1  mrg 
    321   1.1  mrg static int
    322   1.1  mrg add_routine (struct keymgr_atexit_list * g,
    323   1.1  mrg 	     const struct one_atexit_routine * to_add)
    324   1.1  mrg {
    325   1.1  mrg   struct atexit_routine_list * s
    326   1.1  mrg     = malloc (sizeof (struct atexit_routine_list));
    327   1.1  mrg   int result;
    328   1.1  mrg 
    329   1.1  mrg   if (!s)
    330   1.1  mrg     {
    331   1.1  mrg       _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
    332   1.1  mrg       return -1;
    333   1.1  mrg     }
    334   1.1  mrg   s->r = *to_add;
    335   1.1  mrg   s->next = g->l;
    336   1.1  mrg   g->l = s;
    337   1.1  mrg   result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
    338   1.1  mrg   return CHECK_KEYMGR_ERROR (result) == 0 ? 0 : -1;
    339   1.1  mrg }
    340   1.1  mrg 
    341   1.1  mrg /* This runs the routines in G->L up to STOP.  */
    342   1.1  mrg static struct keymgr_atexit_list *
    343   1.1  mrg run_routines (struct keymgr_atexit_list *g,
    344   1.1  mrg 	      struct atexit_routine_list *stop)
    345   1.1  mrg {
    346   1.1  mrg   for (;;)
    347   1.1  mrg     {
    348   1.1  mrg       struct atexit_routine_list * cur = g->l;
    349   1.1  mrg       if (! cur || cur == stop)
    350   1.1  mrg 	break;
    351   1.1  mrg       g->l = cur->next;
    352   1.1  mrg       _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
    353   1.1  mrg 
    354   1.1  mrg       switch (cur->r.has_arg) {
    355   1.1  mrg       case 0: case 2: case 4:
    356   1.1  mrg 	cur->r.callback.ac ();
    357   1.1  mrg 	break;
    358   1.1  mrg       case 1: case 3: case 5:
    359   1.1  mrg 	cur->r.callback.cac (cur->r.arg);
    360   1.1  mrg 	break;
    361   1.1  mrg       default:
    362   1.1  mrg 	/* Don't understand, so don't call it.  */
    363   1.1  mrg 	break;
    364   1.1  mrg       }
    365   1.1  mrg       free (cur);
    366   1.1  mrg 
    367   1.1  mrg       g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
    368   1.1  mrg       if (! g)
    369   1.1  mrg 	break;
    370   1.1  mrg     }
    371   1.1  mrg   return g;
    372   1.1  mrg }
    373   1.1  mrg 
    374   1.1  mrg /* Call the routine described by ROUTINE_PARAM and then call any
    375   1.1  mrg    routines added to KEYMGR_ATEXIT_LIST while that routine was
    376   1.1  mrg    running, all with in_cxa_finalize set.  */
    377   1.1  mrg 
    378   1.1  mrg static void
    379   1.1  mrg cxa_atexit_wrapper (void* routine_param)
    380   1.1  mrg {
    381   1.1  mrg   struct one_atexit_routine * routine = routine_param;
    382   1.1  mrg   struct keymgr_atexit_list *g;
    383   1.1  mrg   struct atexit_routine_list * base = NULL;
    384   1.1  mrg   char prev_running = 0;
    385   1.1  mrg 
    386   1.1  mrg   g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
    387   1.1  mrg   if (g)
    388   1.1  mrg     {
    389   1.1  mrg       prev_running = g->running_routines;
    390   1.1  mrg       g->running_routines = 1;
    391   1.1  mrg       base = g->l;
    392   1.1  mrg       _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
    393   1.1  mrg     }
    394   1.1  mrg 
    395   1.1  mrg   if (routine->has_arg)
    396   1.1  mrg     routine->callback.cac (routine->arg);
    397   1.1  mrg   else
    398   1.1  mrg     routine->callback.ac ();
    399   1.1  mrg 
    400   1.1  mrg   if (g)
    401   1.1  mrg     g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
    402   1.1  mrg   if (g)
    403   1.1  mrg     g = run_routines (g, base);
    404   1.1  mrg   if (g)
    405   1.1  mrg     {
    406   1.1  mrg       g->running_routines = prev_running;
    407   1.1  mrg       _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
    408   1.1  mrg     }
    409   1.1  mrg }
    410   1.1  mrg 
    411   1.1  mrg #ifdef __ppc__
    412   1.1  mrg /* This code is used while running on 10.3.9, when __cxa_atexit doesn't
    413   1.1  mrg    exist in the system library.  10.3.9 only supported regular PowerPC,
    414   1.1  mrg    so this code isn't necessary on x86 or ppc64.  */
    415   1.1  mrg 
    416   1.1  mrg /* This routine is called from the system atexit(); it runs everything
    417   1.1  mrg    registered on the KEYMGR_ATEXIT_LIST.  */
    418   1.1  mrg 
    419   1.1  mrg static void
    420   1.1  mrg our_atexit (void)
    421   1.1  mrg {
    422   1.1  mrg   struct keymgr_atexit_list *g;
    423   1.1  mrg   char prev_running;
    424   1.1  mrg 
    425   1.1  mrg   g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
    426   1.1  mrg   if (! g || g->version != 0 || g->atexit_status != atexit_status_missing)
    427   1.1  mrg     return;
    428   1.1  mrg 
    429   1.1  mrg   prev_running = g->running_routines;
    430   1.1  mrg   g->running_routines = 1;
    431   1.1  mrg   g = run_routines (g, NULL);
    432   1.1  mrg   if (! g)
    433   1.1  mrg     return;
    434   1.1  mrg   g->running_routines = prev_running;
    435   1.1  mrg   _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
    436   1.1  mrg }
    437   1.1  mrg #endif
    438   1.1  mrg 
    439   1.1  mrg /* This is our wrapper around atexit and __cxa_atexit.  It will return
    440   1.1  mrg    nonzero if an error occurs, and otherwise:
    441   1.1  mrg    - if in_cxa_finalize is set, or running on 10.3.9, add R to
    442   1.1  mrg      KEYMGR_ATEXIT_LIST; or
    443   1.1  mrg    - call the system __cxa_atexit to add cxa_atexit_wrapper with an argument
    444   1.1  mrg      that indicates how cxa_atexit_wrapper should call R.  */
    445   1.1  mrg 
    446   1.1  mrg static int
    447   1.1  mrg atexit_common (const struct one_atexit_routine *r, const void *dso)
    448   1.1  mrg {
    449   1.1  mrg   struct keymgr_atexit_list *g = get_globals ();
    450   1.1  mrg 
    451   1.1  mrg   if (! g)
    452   1.1  mrg     return -1;
    453   1.1  mrg 
    454   1.1  mrg   if (g->running_routines || g->atexit_status == atexit_status_missing)
    455   1.1  mrg     return add_routine (g, r);
    456   1.1  mrg 
    457   1.1  mrg   if (g->atexit_status >= atexit_status_working)
    458   1.1  mrg     {
    459   1.1  mrg       int result;
    460   1.1  mrg       if (r->has_arg)
    461   1.1  mrg 	{
    462   1.1  mrg 	  cxa_atexit_p cxa_atexit = g->cxa_atexit_f;
    463   1.1  mrg 	  result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST,
    464   1.1  mrg 							   g);
    465   1.1  mrg 	  if (CHECK_KEYMGR_ERROR (result))
    466   1.1  mrg 	    return -1;
    467   1.1  mrg 	  return cxa_atexit (r->callback.cac, r->arg, dso);
    468   1.1  mrg 	}
    469   1.1  mrg       else
    470   1.1  mrg 	{
    471   1.1  mrg 	  atexit_p atexit_f = g->atexit_f;
    472   1.1  mrg 	  result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST,
    473   1.1  mrg 							   g);
    474   1.1  mrg 	  if (CHECK_KEYMGR_ERROR (result))
    475   1.1  mrg 	    return -1;
    476   1.1  mrg 	  return atexit_f (r->callback.ac);
    477   1.1  mrg 	}
    478   1.1  mrg     }
    479   1.1  mrg   else
    480   1.1  mrg     {
    481   1.1  mrg       cxa_atexit_p cxa_atexit = g->cxa_atexit_f;
    482   1.1  mrg       struct one_atexit_routine *alloced;
    483   1.1  mrg       int result;
    484   1.1  mrg 
    485   1.1  mrg       result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
    486   1.1  mrg       if (CHECK_KEYMGR_ERROR (result))
    487   1.1  mrg 	return -1;
    488   1.1  mrg 
    489   1.1  mrg       alloced = malloc (sizeof (struct one_atexit_routine));
    490   1.1  mrg       if (! alloced)
    491   1.1  mrg 	return -1;
    492   1.1  mrg       *alloced = *r;
    493   1.1  mrg       return cxa_atexit (cxa_atexit_wrapper, alloced, dso);
    494   1.1  mrg     }
    495   1.1  mrg }
    496   1.1  mrg 
    497   1.1  mrg /* These are the actual replacement routines; they just funnel into
    498   1.1  mrg    atexit_common.  */
    499   1.1  mrg 
    500   1.1  mrg int __cxa_atexit (cxa_atexit_callback func, void* arg,
    501   1.1  mrg 		  const void* dso) __attribute__((visibility("hidden")));
    502   1.1  mrg 
    503   1.1  mrg int
    504   1.1  mrg __cxa_atexit (cxa_atexit_callback func, void* arg, const void* dso)
    505   1.1  mrg {
    506   1.1  mrg   struct one_atexit_routine r;
    507   1.1  mrg   r.callback.cac = func;
    508   1.1  mrg   r.has_arg = 1;
    509   1.1  mrg   r.arg = arg;
    510   1.1  mrg   return atexit_common (&r, dso);
    511   1.1  mrg }
    512   1.1  mrg 
    513   1.1  mrg int atexit (atexit_callback func) __attribute__((visibility("hidden")));
    514   1.1  mrg 
    515   1.1  mrg /* Use __dso_handle to allow even bundles that call atexit() to be unloaded
    516   1.1  mrg    on 10.4.  */
    517   1.1  mrg extern void __dso_handle;
    518   1.1  mrg 
    519   1.1  mrg int
    520   1.1  mrg atexit (atexit_callback func)
    521   1.1  mrg {
    522   1.1  mrg   struct one_atexit_routine r;
    523   1.1  mrg   r.callback.ac = func;
    524   1.1  mrg   r.has_arg = 0;
    525   1.1  mrg   return atexit_common (&r, &__dso_handle);
    526   1.1  mrg }
    527   1.1  mrg 
    528   1.1  mrg #endif /* __PIC__ */
    529