* elf/dl-fini.c (_dl_fini): Split sorting of the maps in separate
authorUlrich Drepper <drepper@redhat.com>
Sat, 19 Mar 2005 07:22:23 +0000 (07:22 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sat, 19 Mar 2005 07:22:23 +0000 (07:22 +0000)
function _dl_sort_fini.
(_dl_sort_fini): New function.
* sysdeps/generic/ldsodefs.h: Declare _dl_sort_fini.
* elf/dl-close.c (_dl_close): Call _dl_sort_fini before running
destructors to call them in the right order.

ChangeLog
elf/dl-close.c
elf/dl-fini.c
sysdeps/generic/ldsodefs.h

index c2f12b6..608538f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2005-03-18  Ulrich Drepper  <drepper@redhat.com>
+
+       * elf/dl-fini.c (_dl_fini): Split sorting of the maps in separate
+       function _dl_sort_fini.
+       (_dl_sort_fini): New function.
+       * sysdeps/generic/ldsodefs.h: Declare _dl_sort_fini.
+       * elf/dl-close.c (_dl_close): Call _dl_sort_fini before running
+       destructors to call them in the right order.
+
 2005-02-07  Steven Munroe  <sjmunroe@us.ibm.com>
 
        * sysdeps/powerpc/bits/link.h (La_ppc64_regs): Add lr_vrsave.
index 51b958d..cd4fa7c 100644 (file)
@@ -136,15 +136,9 @@ _dl_close (void *_map)
       return;
     }
 
-#define NWORDS(n) (((n) + 8 * sizeof (unsigned long int) - 1) \
-                  / (sizeof (unsigned long int)))
-#define SETBIT(a, n) a[(n) / sizeof (unsigned long int)] \
-                      |= 1 << ((n) % (sizeof (unsigned long int)))
-#define ISSET(a, n) (a[(n) / sizeof (unsigned long int)] \
-                    & 1 << ((n) % (sizeof (unsigned long int))))
   const unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
-  unsigned long int used[NWORDS (nloaded)];
-  unsigned long int done[NWORDS (nloaded)];
+  char used[nloaded];
+  char done[nloaded];
   struct link_map *maps[nloaded];
 
   /* Run over the list and assign indeces to the link maps and enter
@@ -168,7 +162,7 @@ _dl_close (void *_map)
     {
       struct link_map *l = maps[done_index];
 
-      if (ISSET (done, done_index))
+      if (done[done_index])
        /* Already handled.  */
        continue;
 
@@ -176,12 +170,14 @@ _dl_close (void *_map)
       if (l->l_type == lt_loaded
          && l->l_direct_opencount == 0
          && (l->l_flags_1 & DF_1_NODELETE) == 0
-         && !ISSET (used, done_index))
+         && !used[done_index])
        continue;
 
       /* We need this object and we handle it now.  */
-      SETBIT (done, done_index);
-      SETBIT (used, done_index);
+      done[done_index] = 1;
+      used[done_index] = 1;
+      /* Signal the object is still needed.  */
+      l->l_idx = -1;
 
       /* Mark all dependencies as used.  */
       if (l->l_initfini != NULL)
@@ -189,13 +185,16 @@ _dl_close (void *_map)
          struct link_map **lp = &l->l_initfini[1];
          while (*lp != NULL)
            {
-             assert ((*lp)->l_idx >= 0 && (*lp)->l_idx < nloaded);
-
-             if (!ISSET (used, (*lp)->l_idx))
+             if ((*lp)->l_idx != -1)
                {
-                 SETBIT (used, (*lp)->l_idx);
-                 if ((*lp)->l_idx - 1 < done_index)
-                   done_index = (*lp)->l_idx - 1;
+                 assert ((*lp)->l_idx >= 0 && (*lp)->l_idx < nloaded);
+
+                 if (!used[(*lp)->l_idx])
+                   {
+                     used[(*lp)->l_idx] = 1;
+                     if ((*lp)->l_idx - 1 < done_index)
+                       done_index = (*lp)->l_idx - 1;
+                   }
                }
 
              ++lp;
@@ -207,17 +206,23 @@ _dl_close (void *_map)
          {
            struct link_map *jmap = l->l_reldeps[j];
 
-           assert (jmap->l_idx >= 0 && jmap->l_idx < nloaded);
-
-           if (!ISSET (used, jmap->l_idx))
+           if (jmap->l_idx != -1)
              {
-               SETBIT (used, jmap->l_idx);
-               if (jmap->l_idx - 1 < done_index)
-                 done_index = jmap->l_idx - 1;
+               assert (jmap->l_idx >= 0 && jmap->l_idx < nloaded);
+
+               if (!used[jmap->l_idx])
+                 {
+                   used[jmap->l_idx] = 1;
+                   if (jmap->l_idx - 1 < done_index)
+                     done_index = jmap->l_idx - 1;
+                 }
              }
          }
     }
 
+  /* Sort the entries.  */
+  _dl_sort_fini (GL(dl_ns)[ns]._ns_loaded, maps, nloaded, used, ns);
+
   /* Call all termination functions at once.  */
 #ifdef SHARED
   bool do_audit = GLRO(dl_naudit) > 0 && !GL(dl_ns)[ns]._ns_loaded->l_auditing;
@@ -231,7 +236,7 @@ _dl_close (void *_map)
       /* All elements must be in the same namespace.  */
       assert (imap->l_ns == ns);
 
-      if (!ISSET (used, i))
+      if (!used[i])
        {
          assert (imap->l_type == lt_loaded
                  && (imap->l_flags_1 & DF_1_NODELETE) == 0);
@@ -291,7 +296,7 @@ _dl_close (void *_map)
          if (i < first_loaded)
            first_loaded = i;
        }
-      /* Else ISSET (used, i).  */
+      /* Else used[i].  */
       else if (imap->l_type == lt_loaded)
        {
          if (imap->l_searchlist.r_list == NULL
@@ -320,8 +325,9 @@ _dl_close (void *_map)
                  }
            }
 
-         /* The loader is gone, so mark the object as not having one.  */
-         if (imap->l_loader != NULL && !ISSET (used, imap->l_loader->l_idx))
+         /* The loader is gone, so mark the object as not having one.
+            Note: l_idx == -1 -> object will be removed.  */
+         if (imap->l_loader != NULL && imap->l_loader->l_idx != -1)
            imap->l_loader = NULL;
 
          /* Remember where the first dynamically loaded object is.  */
@@ -370,7 +376,7 @@ _dl_close (void *_map)
   for (i = first_loaded; i < nloaded; ++i)
     {
       struct link_map *imap = maps[i];
-      if (!ISSET (used, i))
+      if (!used[i])
        {
          assert (imap->l_type == lt_loaded);
 
index a01b998..3cd7e7b 100644 (file)
@@ -29,6 +29,94 @@ typedef void (*fini_t) (void);
 
 void
 internal_function
+_dl_sort_fini (struct link_map *l, struct link_map **maps, size_t nmaps,
+              char *used, Lmid_t ns)
+{
+  if (ns == LM_ID_BASE)
+    /* The main executable always comes first.  */
+    l = l->l_next;
+
+  for (; l != NULL; l = l->l_next)
+    /* Do not handle ld.so in secondary namespaces and object which
+       are not removed.  */
+    if (l == l->l_real && l->l_idx != -1)
+      {
+       /* Find the place in the 'maps' array.  */
+       unsigned int j;
+       for (j = ns == LM_ID_BASE ? 1 : 0; maps[j] != l; ++j)
+         assert (j < nmaps);
+
+       /* Find all object for which the current one is a dependency
+          and move the found object (if necessary) in front.  */
+       for (unsigned int k = j + 1; k < nmaps; ++k)
+         {
+           struct link_map **runp = maps[k]->l_initfini;
+           if (runp != NULL)
+             {
+               while (*runp != NULL)
+                 if (*runp == l)
+                   {
+                     struct link_map *here = maps[k];
+
+                     /* Move it now.  */
+                     memmove (&maps[j] + 1,
+                              &maps[j], (k - j) * sizeof (struct link_map *));
+                     maps[j] = here;
+
+                     if (used != NULL)
+                       {
+                         char here_used = used[k];
+
+                         memmove (&used[j] + 1,
+                                  &used[j], (k - j) * sizeof (char));
+                         used[j] = here_used;
+                       }
+
+                     ++j;
+
+                     break;
+                   }
+                 else
+                   ++runp;
+             }
+
+           if (__builtin_expect (maps[k]->l_reldeps != NULL, 0))
+             {
+               unsigned int m = maps[k]->l_reldepsact;
+               struct link_map **relmaps = maps[k]->l_reldeps;
+
+               while (m-- > 0)
+                 {
+                   if (relmaps[m] == l)
+                     {
+                       struct link_map *here = maps[k];
+
+                       /* Move it now.  */
+                       memmove (&maps[j] + 1,
+                                &maps[j],
+                                (k - j) * sizeof (struct link_map *));
+                       maps[j] = here;
+
+                       if (used != NULL)
+                         {
+                           char here_used = used[k];
+
+                           memmove (&used[j] + 1,
+                                    &used[j], (k - j) * sizeof (char));
+                           used[j] = here_used;
+                         }
+
+                       break;
+                     }
+                 }
+             }
+         }
+      }
+}
+
+
+void
+internal_function
 _dl_fini (void)
 {
   /* Lots of fun ahead.  We have to call the destructors for all still
@@ -52,25 +140,25 @@ _dl_fini (void)
   int do_audit = 0;
  again:
 #endif
-  for (Lmid_t cnt = DL_NNS - 1; cnt >= 0; --cnt)
+  for (Lmid_t ns = DL_NNS - 1; ns >= 0; --ns)
     {
       /* Protect against concurrent loads and unloads.  */
       __rtld_lock_lock_recursive (GL(dl_load_lock));
 
       unsigned int nmaps = 0;
-      unsigned int nloaded = GL(dl_ns)[cnt]._ns_nloaded;
+      unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
       /* No need to do anything for empty namespaces or those used for
         auditing DSOs.  */
       if (nloaded == 0
 #ifdef SHARED
-         || GL(dl_ns)[cnt]._ns_loaded->l_auditing != do_audit
+         || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit
 #endif
          )
        goto out;
 
       /* XXX Could it be (in static binaries) that there is no object
         loaded?  */
-      assert (cnt != LM_ID_BASE || nloaded > 0);
+      assert (ns != LM_ID_BASE || nloaded > 0);
 
       /* Now we can allocate an array to hold all the pointers and copy
         the pointers in.  */
@@ -89,87 +177,28 @@ _dl_fini (void)
 
       unsigned int i;
       struct link_map *l;
-      assert (nloaded != 0 || GL(dl_ns)[cnt]._ns_loaded == NULL);
-      for (l = GL(dl_ns)[cnt]._ns_loaded, i = 0; l != NULL; l = l->l_next)
+      assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL);
+      for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next)
        /* Do not handle ld.so in secondary namespaces.  */
        if (l == l->l_real)
          {
            assert (i < nloaded);
 
-           maps[i++] = l;
+           maps[i] = l;
+           l->l_idx = i;
+           ++i;
 
            /* Bump l_direct_opencount of all objects so that they are
               not dlclose()ed from underneath us.  */
            ++l->l_direct_opencount;
          }
-      assert (cnt != LM_ID_BASE || i == nloaded);
-      assert (cnt == LM_ID_BASE || i == nloaded || i == nloaded - 1);
+      assert (ns != LM_ID_BASE || i == nloaded);
+      assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
       nmaps = i;
 
       if (nmaps != 0)
-       {
-         /* Now we have to do the sorting.  */
-         l = GL(dl_ns)[cnt]._ns_loaded;
-         if (cnt == LM_ID_BASE)
-           /* The main executable always comes first.  */
-           l = l->l_next;
-         for (; l != NULL; l = l->l_next)
-           /* Do not handle ld.so in secondary namespaces.  */
-           if (l == l->l_real)
-             {
-               /* Find the place in the 'maps' array.  */
-               unsigned int j;
-               for (j = cnt == LM_ID_BASE ? 1 : 0; maps[j] != l; ++j)
-                 assert (j < nmaps);
-
-               /* Find all object for which the current one is a dependency
-                  and move the found object (if necessary) in front.  */
-               for (unsigned int k = j + 1; k < nmaps; ++k)
-                 {
-                   struct link_map **runp = maps[k]->l_initfini;
-                   if (runp != NULL)
-                     {
-                       while (*runp != NULL)
-                         if (*runp == l)
-                           {
-                             struct link_map *here = maps[k];
-
-                             /* Move it now.  */
-                             memmove (&maps[j] + 1,
-                                      &maps[j],
-                                      (k - j) * sizeof (struct link_map *));
-                             maps[j++] = here;
-
-                             break;
-                           }
-                         else
-                           ++runp;
-                     }
-
-                   if (__builtin_expect (maps[k]->l_reldeps != NULL, 0))
-                     {
-                       unsigned int m = maps[k]->l_reldepsact;
-                       struct link_map **relmaps = maps[k]->l_reldeps;
-
-                       while (m-- > 0)
-                         {
-                           if (relmaps[m] == l)
-                             {
-                               struct link_map *here = maps[k];
-
-                               /* Move it now.  */
-                               memmove (&maps[j] + 1,
-                                        &maps[j],
-                                        (k - j) * sizeof (struct link_map *));
-                               maps[j] = here;
-
-                               break;
-                             }
-                         }
-                     }
-                 }
-             }
-       }
+       /* Now we have to do the sorting.  */
+       _dl_sort_fini (GL(dl_ns)[ns]._ns_loaded, maps, nmaps, NULL, ns);
 
       /* We do not rely on the linked list of loaded object anymore from
         this point on.  We have our own list here (maps).  The various
@@ -200,7 +229,7 @@ _dl_fini (void)
                                        & DL_DEBUG_IMPCALLS, 0))
                    _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
                                      l->l_name[0] ? l->l_name : rtld_progname,
-                                     cnt);
+                                     ns);
 
                  /* First see whether an array is given.  */
                  if (l->l_info[DT_FINI_ARRAY] != NULL)
@@ -247,7 +276,6 @@ _dl_fini (void)
       do_audit = 1;
       goto again;
     }
-#endif
 
   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS, 0))
     _dl_debug_printf ("\nruntime linker statistics:\n"
@@ -255,4 +283,5 @@ _dl_fini (void)
                      "final number of relocations from cache: %lu\n",
                      GL(dl_num_relocations),
                      GL(dl_num_cache_relocations));
+#endif
 }
index a3cef20..dd1b2c8 100644 (file)
@@ -892,6 +892,11 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv,
    initializer functions have completed.  */
 extern void _dl_fini (void) internal_function;
 
+/* Sort array MAPS according to dependencies of the contained objects.  */
+extern void _dl_sort_fini (struct link_map *l, struct link_map **maps,
+                          size_t nmaps, char *used, Lmid_t ns)
+     internal_function;
+
 /* The dynamic linker calls this function before and having changing
    any shared object mappings.  The `r_state' member of `struct r_debug'
    says what change is taking place.  This function's address is