diff options
author | Ian Lance Taylor <ian@airs.com> | 2009-03-24 04:50:32 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@airs.com> | 2009-03-24 04:50:32 +0000 |
commit | 7f055c204a4371154123a1816fbec9855ee60ad5 (patch) | |
tree | 847b6ee09451800cc64d2f3fd933daf82f3a699b /gold/gold-threads.cc | |
parent | c39465150b2129c17f0a520d91dad23cc0632694 (diff) | |
download | binutils-gdb-7f055c204a4371154123a1816fbec9855ee60ad5.tar.gz |
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.
Diffstat (limited to 'gold/gold-threads.cc')
-rw-r--r-- | gold/gold-threads.cc | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/gold/gold-threads.cc b/gold/gold-threads.cc index 9aa883d6cc1..347170814d5 100644 --- a/gold/gold-threads.cc +++ b/gold/gold-threads.cc @@ -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. |