about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--elf/dl-close.c56
-rw-r--r--elf/dl-deps.c21
-rw-r--r--elf/dl-load.c15
-rw-r--r--elf/dl-lookup.c6
-rw-r--r--elf/dl-open.c11
-rw-r--r--elf/loadtest.c8
-rw-r--r--elf/rtld.c16
8 files changed, 91 insertions, 58 deletions
diff --git a/ChangeLog b/ChangeLog
index 79c3c0ded2..4c0a9057cb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2000-10-24  Ulrich Drepper  <drepper@redhat.com>
+
+	Complete revamp of the reference counter handling.
+	* include/link.h (struct link_map): Add l_idx field.
+	* elf/dl-close.c: Handle decrementing of reference counters more
+	correctly. If necessary decrement reference counters of dependencies
+	of dependencies.
+	* elf/dl-lookup.c (add_dependency): Only increment reference counter
+	of the object itself and not also its dependencies.
+	* elf/dl-open.c: Increment reference counters here.
+	* elf/dl-deps.c: Remove reference counter handling here.
+	* elf/dl-load.c: Likewise.
+	* elf/rtld.c: Adjust for _dl_map_deps not handling reference counters.
+
+	* elf/loadtest.c: Print loaded objects at the beginning.
+
 2000-10-24  Andreas Jaeger  <aj@suse.de>
 
 	* sysdeps/mips/dl-machine.h: Partly revert patch from 2000-10-18.
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 4c861a1d06..21305402c0 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -49,6 +49,7 @@ _dl_close (void *_map)
   unsigned int nsearchlist;
   unsigned int nrellist;
   unsigned int i;
+  unsigned int *new_opencount;
 
   /* First see whether we can remove the object at all.  */
   if (map->l_flags_1 & DF_1_NODELETE)
@@ -61,9 +62,6 @@ _dl_close (void *_map)
   /* Acquire the lock.  */
   __libc_lock_lock (_dl_load_lock);
 
-  list = map->l_searchlist.r_list;
-  nsearchlist = map->l_searchlist.r_nlist;
-
   /* Decrement the reference count.  */
   if (map->l_opencount > 1 || map->l_type != lt_loaded)
     {
@@ -81,14 +79,46 @@ _dl_close (void *_map)
 			     "\n", NULL);
 	}
 
-      for (i = 0; i < nsearchlist; ++i)
-	if (! (list[i]->l_flags_1 & DF_1_NODELETE))
-	  --list[i]->l_opencount;
+      /* One decrement the object itself, not the dependencies.  */
+      --map->l_opencount;
 
       __libc_lock_unlock (_dl_load_lock);
       return;
     }
 
+  list = map->l_searchlist.r_list;
+  nsearchlist = map->l_searchlist.r_nlist;
+
+  /* Compute the new l_opencount values.  */
+  new_opencount = (unsigned int *) alloca (nsearchlist
+					   * sizeof (unsigned int));
+  for (i = 0; i < nsearchlist; ++i)
+    {
+      list[i]->l_idx = i;
+      new_opencount[i] = list[i]->l_opencount;
+    }
+  --new_opencount[0];
+  for (i = 1; i < nsearchlist; ++i)
+    if (! (list[i]->l_flags_1 & DF_1_NODELETE)
+	/* Decrement counter.  */
+	&& --new_opencount[i] == 0
+	/* Test whether this object was also loaded directly.  */
+	&& list[i]->l_searchlist.r_list != NULL)
+      {
+	/* In this case we have the decrement all the dependencies of
+           this object.  They are all in MAP's dependency list.  */
+	unsigned int j;
+	struct link_map **dep_list = list[i]->l_searchlist.r_list;
+
+	for (j = 1; j < list[i]->l_searchlist.r_nlist; ++j)
+	  if (! (dep_list[j]->l_flags_1 & DF_1_NODELETE))
+	    {
+	      assert (dep_list[j]->l_idx < nsearchlist);
+	      --new_opencount[dep_list[j]->l_idx];
+	    }
+      }
+  assert (new_opencount[0] == 0);
+
   rellist = map->l_reldeps;
   nrellist = map->l_reldepsact;
 
@@ -96,7 +126,7 @@ _dl_close (void *_map)
   for (i = 0; i < nsearchlist; ++i)
     {
       struct link_map *imap = map->l_initfini[i];
-      if (imap->l_opencount == 1 && imap->l_type == lt_loaded
+      if (new_opencount[i] == 0 && imap->l_type == lt_loaded
 	  && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY])
 	  && ! (imap->l_flags_1 & DF_1_NODELETE)
 	  /* Skip any half-cooked objects that were never initialized.  */
@@ -126,19 +156,17 @@ _dl_close (void *_map)
 	    (*(void (*) (void)) ((void *) imap->l_addr
 				 + imap->l_info[DT_FINI]->d_un.d_ptr)) ();
 	}
+
+      /* Store the new l_opencount value.  */
+      imap->l_opencount = new_opencount[i];
+      /* Just a sanity check.  */
+      assert (imap->l_type == lt_loaded || imap->l_opencount > 0);
     }
 
   /* Notify the debugger we are about to remove some loaded objects.  */
   _r_debug.r_state = RT_DELETE;
   _dl_debug_state ();
 
-  /* The search list contains a counted reference to each object it
-     points to, the 0th elt being MAP itself.  Decrement the reference
-     counts on all the objects MAP depends on.  */
-  for (i = 0; i < nsearchlist; ++i)
-    if (! (list[i]->l_flags_1 & DF_1_NODELETE))
-      --list[i]->l_opencount;
-
   /* Check each element of the search list to see if all references to
      it are gone.  */
   for (i = 0; i < nsearchlist; ++i)
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index c4582926b8..c3feb98270 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -243,18 +243,7 @@ _dl_map_object_deps (struct link_map *map,
 		dtail = newp;
 		++nduplist;
 
-		if (dep->l_reserved)
-		  {
-		    /* This object is already in the search list we are
-		       building.  Don't add a duplicate pointer.
-		       Release the reference just added by
-		       _dl_map_object.  */
-		    if (dep->l_initfini != NULL)
-		      for (i = 1; dep->l_initfini[i] != NULL; ++i)
-			--dep->l_initfini[i]->l_opencount;
-		    --dep->l_opencount;
-		  }
-		else
+		if (! dep->l_reserved)
 		  {
 		    /* Append DEP to the unique list.  */
 		    newp->done = 0;
@@ -363,13 +352,7 @@ _dl_map_object_deps (struct link_map *map,
 
 		    /* This object is already in the search list we
 		       are building.  Don't add a duplicate pointer.
-		       Release the reference just added by
-		       _dl_map_object.  */
-		    if (args.aux->l_initfini != NULL)
-		      for (i = 1; args.aux->l_initfini[i] != NULL; ++i)
-			--args.aux->l_initfini[i]->l_opencount;
-		    --args.aux->l_opencount;
-
+		       Just added by _dl_map_object.  */
 		    for (late = newp; late->unique; late = late->unique)
 		      if (late->unique->map == args.aux)
 			break;
diff --git a/elf/dl-load.c b/elf/dl-load.c
index bb3a2e3187..80fbf65c6b 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -785,10 +785,6 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
 	free (realname);
 	add_name_to_object (l, name);
 
-	if (l->l_initfini != NULL)
-	  for (i = 1; l->l_initfini[i] != NULL; ++i)
-	    ++l->l_initfini[i]->l_opencount;
-	++l->l_opencount;
 	return l;
       }
 
@@ -821,7 +817,6 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
   l = _dl_new_object (realname, name, l_type, loader);
   if (__builtin_expect (! l, 0))
     LOSE (ENOMEM, N_("cannot create shared object descriptor"));
-  l->l_opencount = 1;
 
   /* Extract the remaining details we need from the ELF header
      and then read in the program header table.  */
@@ -1467,7 +1462,9 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
       /* If the requested name matches the soname of a loaded object,
 	 use that object.  Elide this check for names that have not
 	 yet been opened.  */
-      if (l->l_opencount <= 0)
+      /* XXX Is this test still correct after the reference counter
+	 handling rewrite?  */
+      if (l->l_opencount == 0)
 	continue;
       if (!_dl_name_match_p (name, l))
 	{
@@ -1487,11 +1484,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
 	  l->l_soname_added = 1;
 	}
 
-      /* We have a match -- bump the reference count and return it.  */
-      if (l->l_initfini != NULL)
-	for (i = 1; l->l_initfini[i] != NULL; ++i)
-	  ++l->l_initfini[i]->l_opencount;
-      ++l->l_opencount;
+      /* We have a match.  */
       return l;
     }
 
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index d9476817c3..1284e2b3dc 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -160,11 +160,7 @@ add_dependency (struct link_map *undef_map, struct link_map *map)
 	      if (__builtin_expect (act < undef_map->l_reldepsmax, 1))
 		undef_map->l_reldeps[undef_map->l_reldepsact++] = map;
 
-	      /* And increment the counter in the referenced object
-                 and its dependencies.  */
-	      if (map->l_initfini != NULL)
-		for (j = 1; map->l_initfini[j] != NULL; ++j)
-		  ++map->l_initfini[j]->l_opencount;
+	      /* And increment the counter in the referenced object.  */
 	      ++map->l_opencount;
 
 	      /* Display information if we are debugging.  */
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 5c078d9be8..b278e2043e 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -238,7 +238,8 @@ dl_open_worker (void *a)
       return;
     }
 
-  if (new->l_searchlist.r_list)
+  /* It was already open.  */
+  if (new->l_searchlist.r_list != NULL)
     {
       /* Let the user know about the opencount.  */
       if (__builtin_expect (_dl_debug_files, 0))
@@ -259,13 +260,19 @@ dl_open_worker (void *a)
       if ((mode & RTLD_GLOBAL) && new->l_global == 0)
 	(void) add_to_global (new);
 
-      /* It was already open.  */
+      /* Increment just the reference counter of the object.  */
+      ++new->l_opencount;
+
       return;
     }
 
   /* Load that object's dependencies.  */
   _dl_map_object_deps (new, NULL, 0, 0);
 
+  /* Increment the open count for all dependencies.  */
+  for (i = 0; i < new->l_searchlist.r_nlist; ++i)
+    ++new->l_searchlist.r_list[i]->l_opencount;
+
   /* So far, so good.  Now check the versions.  */
   for (i = 0; i < new->l_searchlist.r_nlist; ++i)
     if (new->l_searchlist.r_list[i]->l_versions == NULL)
diff --git a/elf/loadtest.c b/elf/loadtest.c
index 4a3c4c08be..25b27005f1 100644
--- a/elf/loadtest.c
+++ b/elf/loadtest.c
@@ -83,17 +83,23 @@ main (int argc, char *argv[])
   int debug = argc > 1 && argv[1][0] != '\0';
   int count = TEST_ROUNDS;
   int result = 0;
+  struct link_map *map;
 
   mtrace ();
 
   /* Just a seed.  */
   srandom (TEST_ROUNDS);
 
+  if (debug)
+    {
+      puts ("in the beginning");
+      OUT;
+    }
+
   while (count--)
     {
       int nr = random () % NTESTS;
       int index = tests[nr].index;
-      struct link_map *map;
 
       printf ("%4d: %4d: ", count + 1, nr);
       fflush (stdout);
diff --git a/elf/rtld.c b/elf/rtld.c
index ea5d7b5a3d..c44506acc4 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -550,7 +550,6 @@ of this helper program; chances are you did not intend to run this program.\n\
       _dl_loaded->l_phdr = phdr;
       _dl_loaded->l_phnum = phent;
       _dl_loaded->l_entry = *user_entry;
-      _dl_loaded->l_opencount = 1;
 
       /* At this point we are in a bit of trouble.  We would have to
 	 fill in the values for l_dev and l_ino.  But in general we
@@ -707,7 +706,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 	  {
 	    struct link_map *new_map = _dl_map_object (_dl_loaded, p, 1,
 						       lt_library, 0, 0);
-	    if (new_map->l_opencount == 1)
+	    if (++new_map->l_opencount == 1)
 	      /* It is no duplicate.  */
 	      ++npreloads;
 	  }
@@ -775,7 +774,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 	      {
 		struct link_map *new_map = _dl_map_object (_dl_loaded, p, 1,
 							   lt_library, 0, 0);
-		if (new_map->l_opencount == 1)
+		if (++new_map->l_opencount == 1)
 		  /* It is no duplicate.  */
 		  ++npreloads;
 	      }
@@ -786,7 +785,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 	  char *p = strndupa (problem, file_size - (problem - file));
 	  struct link_map *new_map = _dl_map_object (_dl_loaded, p, 1,
 						     lt_library, 0, 0);
-	  if (new_map->l_opencount == 1)
+	  if (++new_map->l_opencount == 1)
 	    /* It is no duplicate.  */
 	    ++npreloads;
 	}
@@ -823,9 +822,14 @@ of this helper program; chances are you did not intend to run this program.\n\
   HP_TIMING_DIFF (diff, start, stop);
   HP_TIMING_ACCUM_NT (load_time, diff);
 
-  /* Mark all objects as being in the global scope.  */
+  /* Mark all objects as being in the global scope and set the open
+     counter.  */
   for (i = _dl_loaded->l_searchlist.r_nlist; i > 0; )
-    _dl_loaded->l_searchlist.r_list[--i]->l_global = 1;
+    {
+      --i;
+      _dl_loaded->l_searchlist.r_list[i]->l_global = 1;
+      ++_dl_loaded->l_searchlist.r_list[i]->l_opencount;
+    }
 
 #ifndef MAP_ANON
   /* We are done mapping things, so close the zero-fill descriptor.  */