Manage objfiles with shared_ptr

This changes objfiles to be managed using a shared_ptr.  shared_ptr is
chosen because it enables the use of objfiles in background threads.

The simplest way to do this was to introduce a new iterator that will
return the underlying objfile, rather than a shared_ptr.  (I also
tried changing the rest of gdb to use shared_ptr, but this was quite
large; and to using intrusive reference counting, but this also was
tricky.)

gdb/ChangeLog
2019-12-12  Tom Tromey  <tom@tromey.com>

	* progspace.h (objfile_list): New typedef.
	(class unwrapping_objfile_iterator)
	(struct unwrapping_objfile_range): Newl
	(struct program_space) <objfiles_range>: Change type.
	<objfiles>: Change return type.
	<add_objfile>: Change type of "objfile" parameter.
	<objfiles_list>: Now a list of shared_ptr.
	* progspace.c (program_space::add_objfile): Change type of
	"objfile".  Update.
	(program_space::remove_objfile): Update.
	* objfiles.h (struct objfile) <~objfile>: Make public.
	* objfiles.c (objfile::make): Update.
	(objfile::unlink): Don't call delete.

Change-Id: I6fb7fbf06efb7cb7474c525908365863eae27eb3
This commit is contained in:
Tom Tromey 2019-11-03 14:47:55 -07:00
parent 343cc95202
commit 7d7167ce1b
5 changed files with 123 additions and 17 deletions

View file

@ -1,3 +1,19 @@
2019-12-12 Tom Tromey <tom@tromey.com>
* progspace.h (objfile_list): New typedef.
(class unwrapping_objfile_iterator)
(struct unwrapping_objfile_range): Newl
(struct program_space) <objfiles_range>: Change type.
<objfiles>: Change return type.
<add_objfile>: Change type of "objfile" parameter.
<objfiles_list>: Now a list of shared_ptr.
* progspace.c (program_space::add_objfile): Change type of
"objfile". Update.
(program_space::remove_objfile): Update.
* objfiles.h (struct objfile) <~objfile>: Make public.
* objfiles.c (objfile::make): Update.
(objfile::unlink): Don't call delete.
2019-12-12 Tom Tromey <tom@tromey.com> 2019-12-12 Tom Tromey <tom@tromey.com>
* symfile.c (symbol_file_clear): Update. * symfile.c (symbol_file_clear): Update.

View file

@ -486,7 +486,10 @@ objfile::make (bfd *bfd_, const char *name_, objfile_flags flags_,
if (parent != nullptr) if (parent != nullptr)
add_separate_debug_objfile (result, parent); add_separate_debug_objfile (result, parent);
current_program_space->add_objfile (result, parent); /* Using std::make_shared might be a bit nicer here, but that would
require making the constructor public. */
current_program_space->add_objfile (std::shared_ptr<objfile> (result),
parent);
/* Rebuild section map next time we need it. */ /* Rebuild section map next time we need it. */
get_objfile_pspace_data (current_program_space)->new_objfiles_available = 1; get_objfile_pspace_data (current_program_space)->new_objfiles_available = 1;
@ -500,7 +503,6 @@ void
objfile::unlink () objfile::unlink ()
{ {
current_program_space->remove_objfile (this); current_program_space->remove_objfile (this);
delete this;
} }
/* Free all separate debug objfile of OBJFILE, but don't free OBJFILE /* Free all separate debug objfile of OBJFILE, but don't free OBJFILE

View file

@ -28,12 +28,14 @@
#include "registry.h" #include "registry.h"
#include "gdb_bfd.h" #include "gdb_bfd.h"
#include "psymtab.h" #include "psymtab.h"
#include <atomic>
#include <bitset> #include <bitset>
#include <vector> #include <vector>
#include "gdbsupport/next-iterator.h" #include "gdbsupport/next-iterator.h"
#include "gdbsupport/safe-iterator.h" #include "gdbsupport/safe-iterator.h"
#include "bcache.h" #include "bcache.h"
#include "gdbarch.h" #include "gdbarch.h"
#include "gdbsupport/refcounted-object.h"
struct htab; struct htab;
struct objfile_data; struct objfile_data;
@ -399,11 +401,16 @@ private:
/* The only way to create an objfile is to call objfile::make. */ /* The only way to create an objfile is to call objfile::make. */
objfile (bfd *, const char *, objfile_flags); objfile (bfd *, const char *, objfile_flags);
/* The only way to free an objfile is via 'unlink'. */
~objfile ();
public: public:
/* Normally you should not call delete. Instead, call 'unlink' to
remove it from the program space's list. In some cases, you may
need to hold a reference to an objfile that is independent of its
existence on the program space's list; for this case, the
destructor must be public so that shared_ptr can reference
it. */
~objfile ();
/* Create an objfile. */ /* Create an objfile. */
static objfile *make (bfd *bfd_, const char *name_, objfile_flags flags_, static objfile *make (bfd *bfd_, const char *name_, objfile_flags flags_,
objfile *parent = nullptr); objfile *parent = nullptr);

View file

@ -175,16 +175,20 @@ program_space::free_all_objfiles ()
/* See progspace.h. */ /* See progspace.h. */
void void
program_space::add_objfile (struct objfile *objfile, struct objfile *before) program_space::add_objfile (std::shared_ptr<objfile> &&objfile,
struct objfile *before)
{ {
if (before == nullptr) if (before == nullptr)
objfiles_list.push_back (objfile); objfiles_list.push_back (std::move (objfile));
else else
{ {
auto iter = std::find (objfiles_list.begin (), objfiles_list.end (), auto iter = std::find_if (objfiles_list.begin (), objfiles_list.end (),
before); [=] (const std::shared_ptr<::objfile> &objf)
{
return objf.get () == before;
});
gdb_assert (iter != objfiles_list.end ()); gdb_assert (iter != objfiles_list.end ());
objfiles_list.insert (iter, objfile); objfiles_list.insert (iter, std::move (objfile));
} }
} }
@ -193,8 +197,11 @@ program_space::add_objfile (struct objfile *objfile, struct objfile *before)
void void
program_space::remove_objfile (struct objfile *objfile) program_space::remove_objfile (struct objfile *objfile)
{ {
auto iter = std::find (objfiles_list.begin (), objfiles_list.end (), auto iter = std::find_if (objfiles_list.begin (), objfiles_list.end (),
objfile); [=] (const std::shared_ptr<::objfile> &objf)
{
return objf.get () == objfile;
});
gdb_assert (iter != objfiles_list.end ()); gdb_assert (iter != objfiles_list.end ());
objfiles_list.erase (iter); objfiles_list.erase (iter);

View file

@ -38,6 +38,79 @@ struct address_space;
struct program_space_data; struct program_space_data;
struct address_space_data; struct address_space_data;
typedef std::list<std::shared_ptr<objfile>> objfile_list;
/* An iterator that wraps an iterator over std::shared_ptr<objfile>,
and dereferences the returned object. This is useful for iterating
over a list of shared pointers and returning raw pointers -- which
helped avoid touching a lot of code when changing how objfiles are
managed. */
class unwrapping_objfile_iterator
{
public:
typedef unwrapping_objfile_iterator self_type;
typedef typename ::objfile *value_type;
typedef typename ::objfile &reference;
typedef typename ::objfile **pointer;
typedef typename objfile_list::iterator::iterator_category iterator_category;
typedef typename objfile_list::iterator::difference_type difference_type;
unwrapping_objfile_iterator (const objfile_list::iterator &iter)
: m_iter (iter)
{
}
objfile *operator* () const
{
return m_iter->get ();
}
unwrapping_objfile_iterator operator++ ()
{
++m_iter;
return *this;
}
bool operator!= (const unwrapping_objfile_iterator &other) const
{
return m_iter != other.m_iter;
}
private:
/* The underlying iterator. */
objfile_list::iterator m_iter;
};
/* A range that returns unwrapping_objfile_iterators. */
struct unwrapping_objfile_range
{
typedef unwrapping_objfile_iterator iterator;
unwrapping_objfile_range (objfile_list &ol)
: m_list (ol)
{
}
iterator begin () const
{
return iterator (m_list.begin ());
}
iterator end () const
{
return iterator (m_list.end ());
}
private:
objfile_list &m_list;
};
/* A program space represents a symbolic view of an address space. /* A program space represents a symbolic view of an address space.
Roughly speaking, it holds all the data associated with a Roughly speaking, it holds all the data associated with a
non-running-yet program (main executable, main symbols), and when non-running-yet program (main executable, main symbols), and when
@ -139,15 +212,15 @@ struct program_space
program_space (address_space *aspace_); program_space (address_space *aspace_);
~program_space (); ~program_space ();
typedef std::list<struct objfile *> objfiles_range; typedef unwrapping_objfile_range objfiles_range;
/* Return an iterable object that can be used to iterate over all /* Return an iterable object that can be used to iterate over all
objfiles. The basic use is in a foreach, like: objfiles. The basic use is in a foreach, like:
for (objfile *objf : pspace->objfiles ()) { ... } */ for (objfile *objf : pspace->objfiles ()) { ... } */
objfiles_range &objfiles () objfiles_range objfiles ()
{ {
return objfiles_list; return unwrapping_objfile_range (objfiles_list);
} }
typedef basic_safe_range<objfiles_range> objfiles_safe_range; typedef basic_safe_range<objfiles_range> objfiles_safe_range;
@ -167,7 +240,8 @@ struct program_space
/* Add OBJFILE to the list of objfiles, putting it just before /* Add OBJFILE to the list of objfiles, putting it just before
BEFORE. If BEFORE is nullptr, it will go at the end of the BEFORE. If BEFORE is nullptr, it will go at the end of the
list. */ list. */
void add_objfile (struct objfile *objfile, struct objfile *before); void add_objfile (std::shared_ptr<objfile> &&objfile,
struct objfile *before);
/* Remove OBJFILE from the list of objfiles. */ /* Remove OBJFILE from the list of objfiles. */
void remove_objfile (struct objfile *objfile); void remove_objfile (struct objfile *objfile);
@ -234,7 +308,7 @@ struct program_space
struct objfile *symfile_object_file = NULL; struct objfile *symfile_object_file = NULL;
/* All known objfiles are kept in a linked list. */ /* All known objfiles are kept in a linked list. */
std::list<struct objfile *> objfiles_list; std::list<std::shared_ptr<objfile>> objfiles_list;
/* The set of target sections matching the sections mapped into /* The set of target sections matching the sections mapped into
this program space. Managed by both exec_ops and solib.c. */ this program space. Managed by both exec_ops and solib.c. */