This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: second thoughts on using dl_iterate_phdr() for cache-validation


>>>>> On Thu, 4 Nov 2004 19:27:43 -0800, Roland McGrath <roland@redhat.com> said:

  Roland> Actually, what I said is that the GLIBC_2.3.4 ABI is frozen.
  Roland> It doesn't necessarily work as you say.  If there is a
  Roland> complete, desireable, and working new interface ready to go
  Roland> in, there is no "opening date" for it.  It just won't be in
  Roland> the ABI version that is already frozen.

OK, I did misunderstand you then.

How does the patch below look?

I decided to stick with 64-bit counters, since dealing with overflows
is probably not worth the trouble (either we'd be emulating 64-bit
counters, which would needlessly hurt 64-bit platforms or we'd need a
call-back interface, which is tricky due to memory-management and
multi-threading/locking considerations).  The implementation below is
safe for 32-bit platforms because it falls back on locked accesses.
That will hurt, but we can fix that at least for those platforms which
can do atomic 64-bit loads and stores (on x86, we could certainly use
CMPXCHG8; perhaps there are even better instructions for doing 64-bit
atomic read and store, since that's all we really need here).

If the approach below looks reasonable to you, I'll finish the patch
up and do more testing (particularly on a 32-bit platform) and
documentation.

	--david

Index: Versions.def
--- Versions.def
+++ Versions.def
@@ -35,6 +35,7 @@
   GLIBC_2.0
   GLIBC_2.1
   GLIBC_2.3.3
+  GLIBC_2.3.5
 }
 libm {
   GLIBC_2.0
Index: elf/Makefile
--- elf/Makefile
+++ elf/Makefile
@@ -21,7 +21,7 @@
 subdir		:= elf
 
 headers		= elf.h bits/elfclass.h link.h
-routines	= $(dl-routines) dl-open dl-close dl-support dl-iteratephdr \
+routines	= $(dl-routines) dl-counters dl-open dl-close dl-support dl-iteratephdr \
 		  dl-addr enbl-secure dl-profstub \
 		  dl-origin dl-libc dl-sym dl-tsd
 
Index: elf/Versions
--- elf/Versions
+++ elf/Versions
@@ -11,6 +11,10 @@
   GLIBC_2.2.4 {
     dl_iterate_phdr;
   }
+  GLIBC_2.3.5 {
+    dl_phdr_additions_counter;
+    dl_phdr_removals_counter;
+  }
 %ifdef EXPORT_UNWIND_FIND_FDE
   GCC_3.0 {
     __register_frame_info_bases; __deregister_frame_info_bases;
Index: elf/dl-close.c
--- elf/dl-close.c
+++ elf/dl-close.c
@@ -368,6 +368,7 @@
   /* Notify the debugger we are about to remove some loaded objects.  */
   _r_debug.r_state = RT_DELETE;
   GLRO(dl_debug_state) ();
+  ++GL(dl_load_subs);
 
 #ifdef USE_TLS
   size_t tls_free_start;
Index: elf/dl-counters.c
--- /dev/null
+++ elf/dl-counters.c
@@ -0,0 +1,68 @@
+/* Access to dl-object addition/removal counters.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by David Mosberger <davidm@hpl.hp.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <ldsodefs.h>
+#include <stddef.h>
+#include <bits/libc-lock.h>
+
+static void
+cancel_handler (void *arg __attribute__((unused)))
+{
+  __rtld_lock_unlock_recursive (GL(dl_load_lock));
+}
+
+static unsigned long long int
+locked_read (unsigned long long int *ptr)
+{
+  unsigned long long int ret;
+
+  __rtld_lock_lock_recursive (GL(dl_load_lock));
+  __libc_cleanup_push (cancel_handler, 0);
+
+  ret = *ptr;
+
+  __libc_cleanup_pop (0);
+  __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+  return ret;
+}
+
+unsigned long long int
+__dl_phdr_additions_counter (void)
+{
+  if (sizeof (unsigned long long int) > sizeof (unsigned long int))
+    /* read of "unsigned long long int" may not be atomic; do it the hard way */
+    return locked_read (&GL(dl_load_adds));
+  else
+    return GL(dl_load_adds);
+}
+weak_alias (__dl_phdr_additions_counter, dl_phdr_additions_counter);
+
+unsigned long long int
+__dl_phdr_removals_counter (void)
+{
+  if (sizeof (unsigned long long int) > sizeof (unsigned long int))
+    /* read of "unsigned long long int" may not be atomic; do it the hard way */
+    return locked_read (&GL(dl_load_subs));
+  else
+    return GL(dl_load_subs);
+}
+weak_alias (__dl_phdr_removals_counter, dl_phdr_removals_counter);
Index: elf/dl-support.c
--- elf/dl-support.c
+++ elf/dl-support.c
@@ -73,6 +73,9 @@
 /* Incremented whenever something may have been added to dl_loaded. */
 unsigned long long _dl_load_adds;
 
+/* Incremented whenever something may have been removed from dl_loaded. */
+unsigned long long _dl_load_subs;
+
 /* Fake scope.  In dynamically linked binaries this is the scope of the
    main application but here we don't have something like this.  So
    create a fake scope containing nothing.  */
Index: elf/tst-dlmodcount.c
--- elf/tst-dlmodcount.c
+++ elf/tst-dlmodcount.c
@@ -71,6 +71,39 @@
   return -1;
 }
 
+static void
+check (int cmd)
+{
+  static int last_adds = 0, last_subs = 0;
+
+  printf ("  additions = %Lu removals = %Lu\n",
+	  dl_phdr_additions_counter (), dl_phdr_removals_counter ());
+
+  switch (cmd)
+    {
+    case SET:
+      break;
+
+    case ADD:
+      if (leq (dl_phdr_additions_counter (), last_adds))
+	{
+	  fprintf (stderr, "dlpi_adds failed to get incremented!\n");
+	  exit (3);
+	}
+      break;
+
+    case REMOVE:
+      if (leq (dl_phdr_removals_counter (), last_subs))
+	{
+	  fprintf (stderr, "dlpi_subs failed to get incremented!\n");
+	  exit (4);
+	}
+      break;
+    }
+  last_adds = dl_phdr_additions_counter ();
+  last_subs = dl_phdr_removals_counter ();
+}
+
 static void *
 load (const char *path)
 {
@@ -81,6 +114,7 @@
   if (!handle)
     exit (1);
   dl_iterate_phdr (callback, (void *)(intptr_t) ADD);
+  check (ADD);
   return handle;
 }
 
@@ -91,6 +125,7 @@
   if (dlclose (handle) < 0)
     exit (2);
   dl_iterate_phdr (callback, (void *)(intptr_t) REMOVE);
+  check (REMOVE);
 }
 
 int
@@ -99,6 +134,7 @@
   void *handle1, *handle2;
 
   dl_iterate_phdr (callback, (void *)(intptr_t) SET);
+  check (SET);
   handle1 = load ("firstobj.so");
   handle2 = load ("globalmod1.so");
   unload ("firstobj.so", handle1);
Index: include/link.h
--- include/link.h
+++ include/link.h
@@ -317,4 +317,23 @@
 					       size_t size, void *data),
 			      void *data);
 
+/* The value returned by this function increments by at least 1
+   (modulo N, where N=2^64 on platforms with 64-bit "long long int")
+   when objects are added to the list visited by dl_iterate_phdr().
+
+   This function may not be serialized with respect to
+   dl_iterate_phdr().  If serialization is needed, this function
+   should be called from within a dl_itereate_phdr() callback.  */
+extern unsigned long long int dl_phdr_additions_counter (void);
+
+/* The value returned by this function increments by at least 1
+   (modulo N, where N=2^64 on platforms with 64-bit "long long int")
+   when objects are removed from the list visited by
+   dl_iterate_phdr().
+
+   This function may not be serialized with respect to
+   dl_iterate_phdr().  If serialization is needed, this function
+   should be called from within a dl_itereate_phdr() callback.  */
+extern unsigned long long int dl_phdr_removals_counter (void);
+
 #endif /* link.h */
Index: sysdeps/generic/ldsodefs.h
--- sysdeps/generic/ldsodefs.h
+++ sysdeps/generic/ldsodefs.h
@@ -250,6 +250,9 @@
   /* Incremented whenever something may have been added to dl_loaded.  */
   EXTERN unsigned long long _dl_load_adds;
 
+  /* Incremented whenever something may have been removed from dl_loaded.  */
+  EXTERN unsigned long long _dl_load_subs;
+
 #ifndef MAP_ANON
   /* File descriptor referring to the zero-fill device.  */
   EXTERN int _dl_zerofd;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]