about summary refs log tree commit diff
path: root/elf/dl-close.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/dl-close.c')
-rw-r--r--elf/dl-close.c145
1 files changed, 100 insertions, 45 deletions
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 7c268392ce..4f015fd6df 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -130,6 +130,10 @@ _dl_close (void *_map)
   /* Acquire the lock.  */
   __rtld_lock_lock_recursive (GL(dl_load_lock));
 
+  /* One less direct use.  */
+  assert (map->l_direct_opencount > 0);
+  --map->l_direct_opencount;
+
   /* Decrement the reference count.  */
   if (map->l_opencount > 1 || map->l_type != lt_loaded)
     {
@@ -141,6 +145,12 @@ _dl_close (void *_map)
       /* Decrement the object's reference counter, not the dependencies'.  */
       --map->l_opencount;
 
+      /* If the direct use counter reaches zero we have to decrement
+	 all the dependencies' usage counter.  */
+      if (map->l_direct_opencount == 0)
+	for (i = 1; i < map->l_searchlist.r_nlist; ++i)
+	  --map->l_searchlist.r_list[i]->l_opencount;
+
       __rtld_lock_unlock_recursive (GL(dl_load_lock));
       return;
     }
@@ -167,12 +177,13 @@ _dl_close (void *_map)
   for (i = 1; list[i] != NULL; ++i)
     if ((list[i]->l_flags_1 & DF_1_NODELETE) == 0
 	/* Decrement counter.  */
-	&& --new_opencount[i] == 0)
+	&& (assert (new_opencount[i] > 0), --new_opencount[i] == 0))
       {
 	void mark_removed (struct link_map *remmap)
 	  {
 	    /* Test whether this object was also loaded directly.  */
-	    if (remmap->l_searchlist.r_list != NULL)
+	    if (remmap->l_searchlist.r_list != NULL
+		&& remmap->l_direct_opencount > 0)
 	      {
 		/* In this case we have to decrement all the dependencies of
 		   this object.  They are all in MAP's dependency list.  */
@@ -184,6 +195,7 @@ _dl_close (void *_map)
 		      || ! dep_list[j]->l_init_called)
 		{
 		  assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist);
+		  assert (new_opencount[dep_list[j]->l_idx] > 0);
 		  if (--new_opencount[dep_list[j]->l_idx] == 0)
 		    {
 		      assert (dep_list[j]->l_type == lt_loaded);
@@ -197,17 +209,53 @@ _dl_close (void *_map)
 		unsigned int j;
 		for (j = 0; j < remmap->l_reldepsact; ++j)
 		  {
+		    struct link_map *depmap = remmap->l_reldeps[j];
+
 		    /* Find out whether this object is in our list.  */
-		    if (remmap->l_reldeps[j]->l_idx < nopencount
-			&& (list[remmap->l_reldeps[j]->l_idx]
-			    == remmap->l_reldeps[j]))
-		      /* Yes, it is.  */
-		      if (--new_opencount[remmap->l_reldeps[j]->l_idx] == 0)
-			{
-			  /* This one is now gone, too.  */
-			  assert (remmap->l_reldeps[j]->l_type == lt_loaded);
-			  mark_removed (remmap->l_reldeps[j]);
-			}
+		    if (depmap->l_idx < nopencount
+			&& list[depmap->l_idx] == depmap)
+		      {
+			/* Yes, it is.  If is has a search list, make a
+			   recursive call to handle this.  */
+			if (depmap->l_searchlist.r_list != NULL)
+			  {
+			    assert (new_opencount[depmap->l_idx] > 0);
+			    if (--new_opencount[depmap->l_idx] == 0)
+			      {
+				/* This one is now gone, too.  */
+				assert (depmap->l_type == lt_loaded);
+				mark_removed (depmap);
+			      }
+			  }
+			else
+			  {
+			    /* Otherwise we have to handle the dependency
+			       deallocation here.  */
+			    unsigned int k;
+			    for (k = 0; depmap->l_initfini[k] != NULL; ++k)
+			      {
+				struct link_map *rl = depmap->l_initfini[k];
+
+				if (rl->l_idx < nopencount
+				    & list[rl->l_idx] == rl)
+				  {
+				    assert (new_opencount[rl->l_idx] > 0);
+				    if (--new_opencount[rl->l_idx] ==  0)
+				      {
+					/* Another module to remove.  */
+					assert (rl->l_type == lt_loaded);
+					mark_removed (rl);
+				      }
+				  }
+				else
+				  {
+				    assert (rl->l_opencount > 0);
+				    if (--rl->l_opencount == 0)
+				      mark_removed (rl);
+				  }
+			      }
+			  }
+		      }
 		  }
 	      }
 	  }
@@ -225,7 +273,8 @@ _dl_close (void *_map)
 	{
 	  /* When debugging print a message first.  */
 	  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
-	    GLRO(dl_debug_printf) ("\ncalling fini: %s\n\n", imap->l_name);
+	    GLRO(dl_debug_printf) ("\ncalling fini: %s [%lu]\n\n",
+				   imap->l_name, imap->l_ns);
 
 	  /* Call its termination function.  Do not do it for
 	     half-cooked objects.  */
@@ -340,18 +389,21 @@ _dl_close (void *_map)
 	  if (__builtin_expect (imap->l_global, 0))
 	    {
 	      /* This object is in the global scope list.  Remove it.  */
-	      unsigned int cnt = GL(dl_main_searchlist)->r_nlist;
+	      unsigned int cnt
+		= GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist;
 
 	      do
 		--cnt;
-	      while (GL(dl_main_searchlist)->r_list[cnt] != imap);
+	      while (GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt]
+		     != imap);
 
 	      /* The object was already correctly registered.  */
-	      while (++cnt < GL(dl_main_searchlist)->r_nlist)
-		GL(dl_main_searchlist)->r_list[cnt - 1]
-		  = GL(dl_main_searchlist)->r_list[cnt];
+	      while (++cnt
+		     < GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist)
+		GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt - 1]
+		  = GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt];
 
-	      --GL(dl_main_searchlist)->r_nlist;
+	      --GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist;
 	    }
 
 #ifdef USE_TLS
@@ -442,19 +494,18 @@ _dl_close (void *_map)
 	  DL_UNMAP (imap);
 
 	  /* Finally, unlink the data structure and free it.  */
-#ifdef SHARED
-	  /* We will unlink the first object only if this is a statically
-	     linked program.  */
-	  assert (imap->l_prev != NULL);
-	  imap->l_prev->l_next = imap->l_next;
-#else
 	  if (imap->l_prev != NULL)
 	    imap->l_prev->l_next = imap->l_next;
 	  else
-	    GL(dl_loaded) = imap->l_next;
+	    {
+#ifdef SHARED
+	      assert (imap->l_ns != LM_ID_BASE);
 #endif
-	  --GL(dl_nloaded);
-	  if (imap->l_next)
+	      GL(dl_ns)[imap->l_ns]._ns_loaded = imap->l_next;
+	    }
+
+	  --GL(dl_ns)[imap->l_ns]._ns_nloaded;
+	  if (imap->l_next != NULL)
 	    imap->l_next->l_prev = imap->l_prev;
 
 	  free (imap->l_versions);
@@ -528,7 +579,7 @@ _dl_close (void *_map)
   if (any_tls)
     {
       if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
-	__libc_fatal (_("TLS generation counter wrapped!  Please send report as described in <http://www.gnu.org/software/libc/bugs.html>."));
+	__libc_fatal (_("TLS generation counter wrapped!  Please report as described in <http://www.gnu.org/software/libc/bugs.html>."));
 
       if (tls_free_end == GL(dl_tls_static_used))
 	GL(dl_tls_static_used) = tls_free_start;
@@ -596,22 +647,26 @@ free_slotinfo (struct dtv_slotinfo_list **elemp)
 
 libc_freeres_fn (free_mem)
 {
-  if (__builtin_expect (GL(dl_global_scope_alloc), 0) != 0
-      && (GL(dl_main_searchlist)->r_nlist
-	  == GLRO(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 = GL(dl_main_searchlist)->r_list;
-
-      /* Put the old map in.  */
-      GL(dl_main_searchlist)->r_list = GLRO(dl_initial_searchlist).r_list;
-      /* Signal that the original map is used.  */
-      GL(dl_global_scope_alloc) = 0;
-
-      /* Now free the old map.  */
-      free (old);
-    }
+  for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
+    if (__builtin_expect (GL(dl_ns)[ns]._ns_global_scope_alloc, 0) != 0
+	&& (GL(dl_ns)[ns]._ns_main_searchlist->r_nlist
+	    // XXX Check whether we need NS-specific initial_searchlist
+	    == GLRO(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 = GL(dl_ns)[ns]._ns_main_searchlist->r_list;
+
+	/* Put the old map in.  */
+	GL(dl_ns)[ns]._ns_main_searchlist->r_list
+	  // XXX Check whether we need NS-specific initial_searchlist
+	  = GLRO(dl_initial_searchlist).r_list;
+	/* Signal that the original map is used.  */
+	GL(dl_ns)[ns]._ns_global_scope_alloc = 0;
+
+	/* Now free the old map.  */
+	free (old);
+      }
 
 #ifdef USE_TLS
   if (USE___THREAD || GL(dl_tls_dtv_slotinfo_list) != NULL)