fgetws implementation.
[kopensolaris-gnu/glibc.git] / elf / dl-close.c
index 3b1e3c9..a738b11 100644 (file)
@@ -1,5 +1,5 @@
 /* Close a shared object opened by `_dl_open'.
-   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -57,8 +57,8 @@ _dl_close (struct link_map *map)
       return;
     }
 
-  list = map->l_searchlist;
-  nsearchlist = map->l_nsearchlist;
+  list = map->l_searchlist.r_list;
+  nsearchlist = map->l_searchlist.r_nlist;
 
   /* Call all termination functions at once.  */
   for (i = 0; i < nsearchlist; ++i)
@@ -103,16 +103,18 @@ _dl_close (struct link_map *map)
          if (imap->l_global)
            {
              /* This object is in the global scope list.  Remove it.  */
-             struct link_map **tail = _dl_global_scope_end;
+             int cnt = _dl_main_searchlist->r_nlist;
+
              do
-               --tail;
-             while (*tail != imap);
-             while (tail < _dl_global_scope_end)
-               {
-                 tail[0] = tail[1];
-                 ++tail;
-               }
-             --_dl_global_scope_end;
+               --cnt;
+             while (_dl_main_searchlist->r_list[cnt] != imap);
+
+             /* The object was already correctly registered.  */
+             while (++cnt < _dl_main_searchlist->r_nlist)
+               _dl_main_searchlist->r_list[cnt - 1]
+                 = _dl_main_searchlist->r_list[cnt];
+
+             --_dl_main_searchlist->r_nlist;
            }
 
          /* We can unmap all the maps at once.  We determined the
@@ -135,12 +137,10 @@ _dl_close (struct link_map *map)
 #endif
          if (imap->l_next)
            imap->l_next->l_prev = imap->l_prev;
-         if (imap->l_searchlist && imap->l_searchlist != list)
-           free (imap->l_searchlist);
 
          if (imap->l_versions != NULL)
            free (imap->l_versions);
-         if (imap->l_origin != NULL)
+         if (imap->l_origin != NULL && imap->l_origin != (char *) -1)
            free ((char *) imap->l_origin);
 
          /* This name always is allocated.  */
@@ -156,15 +156,17 @@ _dl_close (struct link_map *map)
          while (lnp != NULL);
 
          /* Remove the searchlists.  */
-         if (imap->l_dupsearchlist != imap->l_searchlist)
+         if (imap->l_searchlist.r_duplist != imap->l_searchlist.r_list)
            {
-             /* If a l_searchlist object exists there always also is
-                a l_dupsearchlist object.  */
-             assert (imap->l_dupsearchlist != NULL);
-             free (imap->l_dupsearchlist);
+             /* If a r_list exists there always also is a r_duplist.  */
+             assert (imap->l_searchlist.r_list != NULL);
+             free (imap->l_searchlist.r_duplist);
            }
-         if (imap != map && imap->l_searchlist != NULL)
-           free (imap->l_searchlist);
+         if (imap != map && imap->l_searchlist.r_list != NULL)
+           free (imap->l_searchlist.r_list);
+
+         if (imap->l_phdr_allocated)
+           free ((void *) imap->l_phdr);
 
          free (imap);
        }
@@ -172,6 +174,22 @@ _dl_close (struct link_map *map)
 
   free (list);
 
+  if (_dl_global_scope_alloc != 0
+      && _dl_main_searchlist->r_nlist == _dl_initial_searchlist.r_nlist)
+    {
+      /* All object dynamically loaded by the program are unloaded.  Free
+        the memory allocated for the global scope variable.  */
+      struct link_map **old = _dl_main_searchlist->r_list;
+
+      /* Put the old map in.  */
+      _dl_main_searchlist->r_list = _dl_initial_searchlist.r_list;
+      /* Signal that the original map is used.  */
+      _dl_global_scope_alloc = 0;
+
+      /* Now free the old map.  */
+      free (old);
+    }
+
   /* Notify the debugger those objects are finalized and gone.  */
   _r_debug.r_state = RT_CONSISTENT;
   _dl_debug_state ();