This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


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

[PATCH 05/10] introduce a BFD cache


This introduces a BFD cache.  This cache lets us share BFDs across
multiple objfiles.

This is a trimmed-down version of the patch from my earlier series.
Unlike the earlier series, this patch does not introduce any users
of the cache.

I made this change because the earlier patch required a somewhat hacky
change to some target section logic (which relies on BFDs not being
shared).

I do plan to resurrect that old series (see some recent followups I
sent); but meanwhile this will let us share .dwz files easily.  This
doesn't suffer from the same problem as the earlier version of this
patch because dwz sharing is purely internal to dwarf2read.

2012-07-18  Tom Tromey  <tromey@redhat.com>

	* gdb_bfd.c (struct gdb_bfd_data): New.
	(gdb_bfd_cache): New global.
	(struct gdb_bfd_cache_search): New.
	(hash_bfd, eq_bfd, gdb_bfd_open): New functions.
	(gdb_bfd_ref, gdb_bfd_unref): Use gdb_bfd_data.
	* gdb_bfd.h (gdb_bfd_open): Declare.

Index: gdb_bfd.c
===================================================================
RCS file: /cvs/src/src/gdb/gdb_bfd.c,v
retrieving revision 1.2
diff -u -r1.2 gdb_bfd.c
--- gdb_bfd.c	18 Jul 2012 19:34:57 -0000	1.2
+++ gdb_bfd.c	18 Jul 2012 19:48:03 -0000
@@ -1,6 +1,6 @@
 /* Definitions for BFD wrappers used by GDB.
 
-   Copyright (C) 2011
+   Copyright (C) 2011, 2012
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -22,6 +22,7 @@
 #include "gdb_bfd.h"
 #include "gdb_assert.h"
 #include "gdb_string.h"
+#include "hashtab.h"
 
 /* See gdb_bfd.h.  */
 
@@ -38,6 +39,116 @@
   abfd->filename = data;
 }
 
+/* An object of this type is stored in each BFD's user data.  */
+
+struct gdb_bfd_data
+{
+  /* The reference count.  */
+  int refc;
+
+  /* The mtime of the BFD at the point the cache entry was made.  */
+  time_t mtime;
+};
+
+/* A hash table storing all the BFDs maintained in the cache.  */
+
+static htab_t gdb_bfd_cache;
+
+/* The type of an object being looked up in gdb_bfd_cache.  We use
+   htab's capability of storing one kind of object (BFD in this case)
+   and using a different sort of object for searching.  */
+
+struct gdb_bfd_cache_search
+{
+  /* The filename.  */
+  const char *filename;
+  /* The mtime.  */
+  time_t mtime;
+};
+
+/* A hash function for BFDs.  */
+
+static hashval_t
+hash_bfd (const void *b)
+{
+  const bfd *abfd = b;
+
+  /* It is simplest to just hash the filename.  */
+  return htab_hash_string (bfd_get_filename (abfd));
+}
+
+/* An equality function for BFDs.  Note that this expects the caller
+   to search using struct gdb_bfd_cache_search only, not BFDs.  */
+
+static int
+eq_bfd (const void *a, const void *b)
+{
+  const bfd *abfd = a;
+  const struct gdb_bfd_cache_search *s = b;
+  struct gdb_bfd_data *gdata = bfd_usrdata (abfd);
+
+  return (gdata->mtime == s->mtime
+	  && strcmp (bfd_get_filename (abfd), s->filename) == 0);
+}
+
+/* See gdb_bfd.h.  */
+
+struct bfd *
+gdb_bfd_open (const char *name, const char *target, int fd)
+{
+  hashval_t hash;
+  void **slot;
+  bfd *abfd;
+  struct gdb_bfd_cache_search search;
+  struct stat st;
+
+  if (gdb_bfd_cache == NULL)
+    gdb_bfd_cache = htab_create_alloc (1, hash_bfd, eq_bfd, NULL,
+				       xcalloc, xfree);
+
+  if (fd == -1)
+    {
+      fd = open (name, O_RDONLY | O_BINARY);
+      if (fd == -1)
+	{
+	  bfd_set_error (bfd_error_system_call);
+	  return NULL;
+	}
+    }
+
+  search.filename = name;
+  if (fstat (fd, &st) < 0)
+    {
+      /* Weird situation here.  */
+      search.mtime = 0;
+    }
+  else
+    search.mtime = st.st_mtime;
+
+  /* Note that this must compute the same result as hash_bfd.  */
+  hash = htab_hash_string (name);
+  /* Note that we cannot use htab_find_slot_with_hash here, because
+     opening the BFD may fail; and this would violate hashtab
+     invariants.  */
+  abfd = htab_find_with_hash (gdb_bfd_cache, &search, hash);
+  if (abfd != NULL)
+    {
+      close (fd);
+      return gdb_bfd_ref (abfd);
+    }
+
+  abfd = bfd_fopen (name, target, FOPEN_RB, fd);
+  if (abfd == NULL)
+    return NULL;
+
+  slot = htab_find_slot_with_hash (gdb_bfd_cache, &search, hash, INSERT);
+  gdb_assert (!*slot);
+  *slot = abfd;
+
+  gdb_bfd_stash_filename (abfd);
+  return gdb_bfd_ref (abfd);
+}
+
 /* Close ABFD, and warn if that fails.  */
 
 static int
@@ -60,22 +171,23 @@
 struct bfd *
 gdb_bfd_ref (struct bfd *abfd)
 {
-  int *p_refcount;
+  struct gdb_bfd_data *gdata;
 
   if (abfd == NULL)
     return NULL;
 
-  p_refcount = bfd_usrdata (abfd);
+  gdata = bfd_usrdata (abfd);
 
-  if (p_refcount != NULL)
+  if (gdata != NULL)
     {
-      *p_refcount += 1;
+      gdata->refc += 1;
       return abfd;
     }
 
-  p_refcount = xmalloc (sizeof (*p_refcount));
-  *p_refcount = 1;
-  bfd_usrdata (abfd) = p_refcount;
+  gdata = bfd_zalloc (abfd, sizeof (struct gdb_bfd_data));
+  gdata->refc = 1;
+  gdata->mtime = bfd_get_mtime (abfd);
+  bfd_usrdata (abfd) = gdata;
 
   return abfd;
 }
@@ -85,22 +197,35 @@
 void
 gdb_bfd_unref (struct bfd *abfd)
 {
-  int *p_refcount;
-  char *name;
+  struct gdb_bfd_data *gdata;
+  struct gdb_bfd_cache_search search;
 
   if (abfd == NULL)
     return;
 
-  p_refcount = bfd_usrdata (abfd);
-  gdb_assert (*p_refcount >= 1);
+  gdata = bfd_usrdata (abfd);
+  gdb_assert (gdata->refc >= 1);
 
-  *p_refcount -= 1;
-  if (*p_refcount > 0)
+  gdata->refc -= 1;
+  if (gdata->refc > 0)
     return;
 
-  xfree (p_refcount);
+  search.filename = bfd_get_filename (abfd);
+
+  if (gdb_bfd_cache && search.filename)
+    {
+      hashval_t hash = htab_hash_string (search.filename);
+      void **slot;
+
+      search.mtime = gdata->mtime;
+      slot = htab_find_slot_with_hash (gdb_bfd_cache, &search, hash,
+				       NO_INSERT);
+
+      if (slot && *slot)
+	htab_clear_slot (gdb_bfd_cache, slot);
+    }
+
   bfd_usrdata (abfd) = NULL;  /* Paranoia.  */
 
-  name = bfd_get_filename (abfd);
   gdb_bfd_close_or_warn (abfd);
 }
Index: gdb_bfd.h
===================================================================
RCS file: /cvs/src/src/gdb/gdb_bfd.h,v
retrieving revision 1.2
diff -u -r1.2 gdb_bfd.h
--- gdb_bfd.h	18 Jul 2012 19:34:57 -0000	1.2
+++ gdb_bfd.h	18 Jul 2012 19:48:03 -0000
@@ -27,6 +27,14 @@
 
 void gdb_bfd_stash_filename (struct bfd *abfd);
 
+/* Open a read-only (FOPEN_RB) BFD given arguments like bfd_fopen.
+   Returns NULL on error.  On success, returns a new reference to the
+   BFD, which must be freed with gdb_bfd_unref.  BFDs returned by this
+   call are shared among all callers opening the same file.  If FD is
+   not -1, then after this call it is owned by BFD.  */
+
+struct bfd *gdb_bfd_open (const char *name, const char *target, int fd);
+
 /* Acquire a new reference to ABFD.  Returns ABFD for convenience.
    It is fine for ABFD to be NULL; in this case the function does
    nothing and returns NULL.  */


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