2009-03-23 Ian Lance Taylor <iant@google.com>
* gold-threads.h (class Initialize_lock): Define. * gold-threads.cc (class Initialize_lock_once): Define. (initialize_lock_control): New static variable. (initialize_lock_pointer): New static variable. (initialize_lock_once): New static function. (Initialize_lock::Initialize_lock): Define. (Initialize_lock::initialize): Define. * target-select.h: Include "gold-threads.h". (class Target_selector): Add lock_ and initialize_lock_ fields. Don't define instantiate_target, just declare it. * target-select.cc (Target_selector::Target_selector): Initialize new fields. (Target_selector::instantiate_target): Define. * descriptors.h: Include "gold-threads.h". (class Descriptors): Add initialize_lock_ field. * descriptors.cc (Descriptors::Descriptors): Initialize new field. (Descriptors::open): Use initialize_lock_ field * errors.h (class Errors): Add initialize_lock_ field. * errors.cc (Errors::Errors): Initialize new field. (Errors::initialize_lock): Use initialize_lock_ field. * powerpc.cc (class Target_selector_powerpc): Remove instantiated_target_ field. In do_recognize call instantiate_target rather than do_instantiate_target. In do_instantiate_target just allocate a new target. * sparc.cc (class Target_selector_sparc): Likewise.
This commit is contained in:
parent
c39465150b
commit
7f055c204a
11 changed files with 220 additions and 39 deletions
|
@ -1,5 +1,32 @@
|
|||
2009-03-23 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* gold-threads.h (class Initialize_lock): Define.
|
||||
* gold-threads.cc (class Initialize_lock_once): Define.
|
||||
(initialize_lock_control): New static variable.
|
||||
(initialize_lock_pointer): New static variable.
|
||||
(initialize_lock_once): New static function.
|
||||
(Initialize_lock::Initialize_lock): Define.
|
||||
(Initialize_lock::initialize): Define.
|
||||
* target-select.h: Include "gold-threads.h".
|
||||
(class Target_selector): Add lock_ and initialize_lock_ fields.
|
||||
Don't define instantiate_target, just declare it.
|
||||
* target-select.cc (Target_selector::Target_selector): Initialize
|
||||
new fields.
|
||||
(Target_selector::instantiate_target): Define.
|
||||
* descriptors.h: Include "gold-threads.h".
|
||||
(class Descriptors): Add initialize_lock_ field.
|
||||
* descriptors.cc (Descriptors::Descriptors): Initialize new
|
||||
field.
|
||||
(Descriptors::open): Use initialize_lock_ field
|
||||
* errors.h (class Errors): Add initialize_lock_ field.
|
||||
* errors.cc (Errors::Errors): Initialize new field.
|
||||
(Errors::initialize_lock): Use initialize_lock_ field.
|
||||
* powerpc.cc (class Target_selector_powerpc): Remove
|
||||
instantiated_target_ field. In do_recognize call
|
||||
instantiate_target rather than do_instantiate_target. In
|
||||
do_instantiate_target just allocate a new target.
|
||||
* sparc.cc (class Target_selector_sparc): Likewise.
|
||||
|
||||
* freebsd.h: New file.
|
||||
* i386.cc: Include "freebsd.h".
|
||||
(Target_i386): Derive from Target_freebsd rather than
|
||||
|
|
|
@ -51,8 +51,8 @@ namespace gold
|
|||
// adjusted downward if we run out of file descriptors.
|
||||
|
||||
Descriptors::Descriptors()
|
||||
: lock_(NULL), open_descriptors_(), stack_top_(-1), current_(0),
|
||||
limit_(8192 - 16)
|
||||
: lock_(NULL), initialize_lock_(&this->lock_), open_descriptors_(),
|
||||
stack_top_(-1), current_(0), limit_(8192 - 16)
|
||||
{
|
||||
this->open_descriptors_.reserve(128);
|
||||
}
|
||||
|
@ -66,13 +66,9 @@ Descriptors::open(int descriptor, const char* name, int flags, int mode)
|
|||
// initialize a Lock until we have parsed the options to find out
|
||||
// whether we are running with threads. We can be called before
|
||||
// options are valid when reading a linker script.
|
||||
if (this->lock_ == NULL)
|
||||
{
|
||||
if (parameters->options_valid())
|
||||
this->lock_ = new Lock();
|
||||
else
|
||||
gold_assert(descriptor < 0);
|
||||
}
|
||||
bool lock_initialized = this->initialize_lock_.initialize();
|
||||
|
||||
gold_assert(lock_initialized || descriptor < 0);
|
||||
|
||||
if (descriptor >= 0)
|
||||
{
|
||||
|
|
|
@ -25,11 +25,11 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "gold-threads.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
class Lock;
|
||||
|
||||
// This class manages file descriptors for gold.
|
||||
|
||||
class Descriptors
|
||||
|
@ -78,6 +78,8 @@ class Descriptors
|
|||
|
||||
// We need to lock before accessing any fields.
|
||||
Lock* lock_;
|
||||
// Used to initialize the lock_ field exactly once.
|
||||
Initialize_lock initialize_lock_;
|
||||
// Information for descriptors.
|
||||
std::vector<Open_descriptor> open_descriptors_;
|
||||
// Top of stack.
|
||||
|
|
|
@ -39,8 +39,8 @@ namespace gold
|
|||
const int Errors::max_undefined_error_report;
|
||||
|
||||
Errors::Errors(const char* program_name)
|
||||
: program_name_(program_name), lock_(NULL), error_count_(0),
|
||||
warning_count_(0), undefined_symbols_()
|
||||
: program_name_(program_name), lock_(NULL), initialize_lock_(&this->lock_),
|
||||
error_count_(0), warning_count_(0), undefined_symbols_()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -53,9 +53,7 @@ Errors::Errors(const char* program_name)
|
|||
bool
|
||||
Errors::initialize_lock()
|
||||
{
|
||||
if (this->lock_ == NULL && parameters->options_valid())
|
||||
this->lock_ = new Lock;
|
||||
return this->lock_ != NULL;
|
||||
return this->initialize_lock_.initialize();
|
||||
}
|
||||
|
||||
// Increment a counter, holding the lock if available.
|
||||
|
|
|
@ -116,6 +116,8 @@ class Errors
|
|||
// This class can be accessed from multiple threads. This lock is
|
||||
// used to control access to the data structures.
|
||||
Lock* lock_;
|
||||
// Used to initialize the lock_ field exactly once.
|
||||
Initialize_lock initialize_lock_;
|
||||
// Numbers of errors reported.
|
||||
int error_count_;
|
||||
// Number of warnings reported.
|
||||
|
|
|
@ -276,4 +276,128 @@ Condvar::~Condvar()
|
|||
delete this->condvar_;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
|
||||
// Class Initialize_lock_once. This exists to hold a pthread_once_t
|
||||
// structure for Initialize_lock.
|
||||
|
||||
class Initialize_lock_once
|
||||
{
|
||||
public:
|
||||
Initialize_lock_once()
|
||||
: once_(PTHREAD_ONCE_INIT)
|
||||
{ }
|
||||
|
||||
// Return a pointer to the pthread_once_t variable.
|
||||
pthread_once_t*
|
||||
once_control()
|
||||
{ return &this->once_; }
|
||||
|
||||
private:
|
||||
pthread_once_t once_;
|
||||
};
|
||||
|
||||
#endif // !defined(ENABLE_THREADS)
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
|
||||
// A single lock which controls access to initialize_lock_pointer.
|
||||
// This is used because we can't pass parameters to functions passed
|
||||
// to pthread_once.
|
||||
|
||||
static pthread_mutex_t initialize_lock_control = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// A pointer to a pointer to the lock which we need to initialize
|
||||
// once. Access to this is controlled by initialize_lock_pointer.
|
||||
|
||||
static Lock** initialize_lock_pointer;
|
||||
|
||||
// A routine passed to pthread_once which initializes the lock which
|
||||
// initialize_lock_pointer points to.
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
static void
|
||||
initialize_lock_once()
|
||||
{
|
||||
*initialize_lock_pointer = new Lock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // !defined(ENABLE_THREADS)
|
||||
|
||||
// Class Initialize_lock.
|
||||
|
||||
Initialize_lock::Initialize_lock(Lock** pplock)
|
||||
: pplock_(pplock)
|
||||
{
|
||||
#ifndef ENABLE_THREADS
|
||||
this->once_ = NULL;
|
||||
#else
|
||||
this->once_ = new Initialize_lock_once();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Initialize the lock.
|
||||
|
||||
bool
|
||||
Initialize_lock::initialize()
|
||||
{
|
||||
// If the lock has already been initialized, we don't need to do
|
||||
// anything. Note that this assumes that the pointer value will be
|
||||
// set completely or not at all. I hope this is always safe. We
|
||||
// want to do this for efficiency.
|
||||
if (*this->pplock_ != NULL)
|
||||
return true;
|
||||
|
||||
// We can't initialize the lock until we have read the options.
|
||||
if (!parameters->options_valid())
|
||||
return false;
|
||||
|
||||
// If the user did not use --threads, then we can initialize
|
||||
// directly.
|
||||
if (!parameters->options().threads())
|
||||
{
|
||||
*this->pplock_ = new Lock();
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef ENABLE_THREADS
|
||||
|
||||
// If there is no threads support, we don't need to use
|
||||
// pthread_once.
|
||||
*this->pplock_ = new Lock();
|
||||
|
||||
#else // !defined(ENABLE_THREADS)
|
||||
|
||||
// Since we can't pass parameters to routines called by
|
||||
// pthread_once, we use a static variable: initialize_lock_pointer.
|
||||
// That in turns means that we need to use a mutex to control access
|
||||
// to initialize_lock_pointer.
|
||||
|
||||
int err = pthread_mutex_lock(&initialize_lock_control);
|
||||
if (err != 0)
|
||||
gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err));
|
||||
|
||||
initialize_lock_pointer = this->pplock_;
|
||||
|
||||
err = pthread_once(this->once_->once_control(), initialize_lock_once);
|
||||
if (err != 0)
|
||||
gold_fatal(_("pthread_once failed: %s"), strerror(err));
|
||||
|
||||
initialize_lock_pointer = NULL;
|
||||
|
||||
err = pthread_mutex_unlock(&initialize_lock_control);
|
||||
if (err != 0)
|
||||
gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err));
|
||||
|
||||
gold_assert(*this->pplock_ != NULL);
|
||||
|
||||
#endif // !defined(ENABLE_THREADS)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace gold
|
|||
{
|
||||
|
||||
class Condvar;
|
||||
class Initialize_lock_once;
|
||||
|
||||
// The interface for the implementation of a Lock.
|
||||
|
||||
|
@ -190,6 +191,33 @@ class Condvar
|
|||
Condvar_impl* condvar_;
|
||||
};
|
||||
|
||||
// A class used to initialize a lock exactly once, after the options
|
||||
// have been read. This is needed because the implementation of locks
|
||||
// depends on whether we've seen the --threads option. Before the
|
||||
// options have been read, we know we are single-threaded, so we can
|
||||
// get by without using a lock. This class should be an instance
|
||||
// variable of the class which has a lock which needs to be
|
||||
// initialized.
|
||||
|
||||
class Initialize_lock
|
||||
{
|
||||
public:
|
||||
// The class which uses this will have a pointer to a lock. This
|
||||
// must be constructed with a pointer to that pointer.
|
||||
Initialize_lock(Lock** pplock);
|
||||
|
||||
// Initialize the lock. Return true if the lock is now initialized,
|
||||
// false if it is not (because the options have not yet been read).
|
||||
bool
|
||||
initialize();
|
||||
|
||||
private:
|
||||
// A pointer to the lock pointer which must be initialized.
|
||||
Lock** const pplock_;
|
||||
// If needed, a pointer to a pthread_once_t structure.
|
||||
Initialize_lock_once* once_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_THREADS_H)
|
||||
|
|
|
@ -1982,8 +1982,6 @@ public:
|
|||
(big_endian ? "elf32-powerpc" : "elf32-powerpcle")))
|
||||
{ }
|
||||
|
||||
Target* instantiated_target_;
|
||||
|
||||
Target* do_recognize(int machine, int, int)
|
||||
{
|
||||
switch (size)
|
||||
|
@ -2002,15 +2000,11 @@ public:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return do_instantiate_target();
|
||||
return this->instantiate_target();
|
||||
}
|
||||
|
||||
Target* do_instantiate_target()
|
||||
{
|
||||
if (this->instantiated_target_ == NULL)
|
||||
this->instantiated_target_ = new Target_powerpc<size, big_endian>();
|
||||
return this->instantiated_target_;
|
||||
}
|
||||
{ return new Target_powerpc<size, big_endian>(); }
|
||||
};
|
||||
|
||||
Target_selector_powerpc<32, true> target_selector_ppc32;
|
||||
|
|
|
@ -3240,8 +3240,6 @@ public:
|
|||
(size == 64 ? "elf64-sparc" : "elf32-sparc"))
|
||||
{ }
|
||||
|
||||
Target* instantiated_target_;
|
||||
|
||||
Target* do_recognize(int machine, int, int)
|
||||
{
|
||||
switch (size)
|
||||
|
@ -3261,15 +3259,11 @@ public:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return do_instantiate_target();
|
||||
return this->instantiate_target();
|
||||
}
|
||||
|
||||
Target* do_instantiate_target()
|
||||
{
|
||||
if (this->instantiated_target_ == NULL)
|
||||
this->instantiated_target_ = new Target_sparc<size, big_endian>();
|
||||
return this->instantiated_target_;
|
||||
}
|
||||
{ return new Target_sparc<size, big_endian>(); }
|
||||
};
|
||||
|
||||
Target_selector_sparc<32, true> target_selector_sparc32;
|
||||
|
|
|
@ -46,13 +46,27 @@ namespace gold
|
|||
Target_selector::Target_selector(int machine, int size, bool is_big_endian,
|
||||
const char* bfd_name)
|
||||
: machine_(machine), size_(size), is_big_endian_(is_big_endian),
|
||||
bfd_name_(bfd_name), instantiated_target_(NULL)
|
||||
bfd_name_(bfd_name), instantiated_target_(NULL), lock_(NULL),
|
||||
initialize_lock_(&this->lock_)
|
||||
|
||||
{
|
||||
this->next_ = target_selectors;
|
||||
target_selectors = this;
|
||||
}
|
||||
|
||||
// Instantiate the target and return it. Use a lock to avoid
|
||||
// instantiating two instances of the same target.
|
||||
|
||||
Target*
|
||||
Target_selector::instantiate_target()
|
||||
{
|
||||
this->initialize_lock_.initialize();
|
||||
Hold_optional_lock hl(this->lock_);
|
||||
if (this->instantiated_target_ == NULL)
|
||||
this->instantiated_target_ = this->do_instantiate_target();
|
||||
return this->instantiated_target_;
|
||||
}
|
||||
|
||||
// Find the target for an ELF file.
|
||||
|
||||
Target*
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "gold-threads.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
|
@ -136,12 +138,7 @@ class Target_selector
|
|||
|
||||
// Instantiate the target and return it.
|
||||
Target*
|
||||
instantiate_target()
|
||||
{
|
||||
if (this->instantiated_target_ == NULL)
|
||||
this->instantiated_target_ = this->do_instantiate_target();
|
||||
return this->instantiated_target_;
|
||||
}
|
||||
instantiate_target();
|
||||
|
||||
private:
|
||||
// ELF machine code.
|
||||
|
@ -157,6 +154,11 @@ class Target_selector
|
|||
// The singleton Target structure--this points to an instance of the
|
||||
// real implementation.
|
||||
Target* instantiated_target_;
|
||||
// Lock to make sure that we don't instantiate the target more than
|
||||
// once.
|
||||
Lock* lock_;
|
||||
// We only want to initialize the lock_ pointer once.
|
||||
Initialize_lock initialize_lock_;
|
||||
};
|
||||
|
||||
// Select the target for an ELF file.
|
||||
|
|
Loading…
Reference in a new issue