diff options
author | Ian Lance Taylor <ian@airs.com> | 2010-02-12 03:23:26 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@airs.com> | 2010-02-12 03:23:26 +0000 |
commit | 114dfbe13efea1a1405dbcf5d9254e59d309382f (patch) | |
tree | c9a9058321b21712c1502a2bbc05225b370f7a23 /gold/gold-threads.cc | |
parent | 2310652a4f4b6568a96583e6930904e7c25efdcd (diff) | |
download | gdb-114dfbe13efea1a1405dbcf5d9254e59d309382f.zip gdb-114dfbe13efea1a1405dbcf5d9254e59d309382f.tar.gz gdb-114dfbe13efea1a1405dbcf5d9254e59d309382f.tar.bz2 |
* gold-threads.h (class Once): Define.
(class Initialize_lock): Rewrite as child of Once.
* gold-threads.cc (class Once_initialize): Define.
(once_pointer_control): New static variable.
(once_pointer, once_arg): New static variables.
(c_run_once): New static function.
(Once::Once, Once::run_once, Once::internal_run): New functions.
(class Initialize_lock_once): Remove.
(initialize_lock_control): Remove.
(initialize_lock_pointer): Remove.
(initialize_lock_once): Remove.
(Initialize_lock::Initialize_lock): Move to gold-threads.h.
(Initialize_lock::initialize): Rewrite.
(Initialize_lock::do_run_once): New function.
* archive.cc (Archive::interpret_header): Only clear name if it is
not already empty.
* fileread.cc: Include "gold-threads.h"
(file_counts_lock): New static variable.
(file_counts_initialize_lock): Likewise.
(File_read::release): Only increment counts when using --stats.
Use a lock around the increment.
* parameters.cc (class Set_parameters_target_once): Define.
(set_parameters_target_once): New static variable.
(Parameters::Parameters): Move here from parameters.h.
(Parameters::set_target): Rewrite.
(Parameters::set_target_once): New function.
(Parameters::clear_target): Move here and rewrite.
* parameters.h (class Parameters): Update declarations. Add
set_parameters_target_once_ field.
(Parameters::Parameters): Move to parameters.cc.
(Parameters::clear_target): Likewise.
* readsyms.cc (Read_symbols::do_group): Create a Start_group
task.
(Start_group::~Start_group): New function.
(Start_group::is_runnable): New function.
(Start_group::locks, Start_group::run): New functions.
(Finish_group::run): Change saw_undefined to size_t.
* readsyms.h (class Start_group): Define.
(class Finish_group): Change saw_undefined_ field to size_t.
(Finish_group::Finish_group): Remove saw_undefined and
this_blocker parameters. Change all callers.
(Finish_group::set_saw_undefined): New function.
(Finish_group::set_blocker): New function.
* symtab.h (class Symbol_table): Change saw_undefined to return
size_t. Change saw_undefined_ field to size_t.
* target-select.cc (Set_target_once::do_run_once): New function.
(Target_selector::Target_selector): Initialize set_target_once_
field. Don't initialize lock_ and initialize_lock_ fields.
(Target_selector::instantiate_target): Rewrite.
(Target_selector::set_target): New function.
* target-select.h (class Set_target_once): Define.
(class Target_selector): Update declarations. Make
Set_target_once a friend. Remove lock_ and initialize_lock_
fields. Add set_target_once_ field.
Diffstat (limited to 'gold/gold-threads.cc')
-rw-r--r-- | gold/gold-threads.cc | 160 |
1 files changed, 102 insertions, 58 deletions
diff --git a/gold/gold-threads.cc b/gold/gold-threads.cc index b99cf27..f5347bf 100644 --- a/gold/gold-threads.cc +++ b/gold/gold-threads.cc @@ -1,6 +1,6 @@ // gold-threads.cc -- thread support for gold -// Copyright 2006, 2007, 2008 Free Software Foundation, Inc. +// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. // Written by Ian Lance Taylor <iant@google.com>. // This file is part of gold. @@ -278,13 +278,13 @@ Condvar::~Condvar() #ifdef ENABLE_THREADS -// Class Initialize_lock_once. This exists to hold a pthread_once_t -// structure for Initialize_lock. +// Class Once_initialize. This exists to hold a pthread_once_t +// structure for Once. -class Initialize_lock_once +class Once_initialize { public: - Initialize_lock_once() + Once_initialize() : once_(PTHREAD_ONCE_INIT) { } @@ -297,107 +297,151 @@ class Initialize_lock_once pthread_once_t once_; }; -#endif // !defined(ENABLE_THREADS) +#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. +// A single lock which controls access to once_pointer. This is used +// because we can't pass parameters to functions passed to +// pthread_once. + +static pthread_mutex_t once_pointer_control = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t initialize_lock_control = PTHREAD_MUTEX_INITIALIZER; +// A pointer to Once structure we want to run. Access to this is +// controlled by once_pointer_control. -// A pointer to a pointer to the lock which we need to initialize -// once. Access to this is controlled by initialize_lock_control. +static Once* once_pointer; -static Lock** initialize_lock_pointer; +// The argument to pass to the Once structure. Access to this is +// controlled by once_pointer_control. -// A routine passed to pthread_once which initializes the lock which -// initialize_lock_pointer points to. +static void* once_arg; + +// A routine passed to pthread_once which runs the Once pointer. extern "C" { static void -initialize_lock_once() +c_run_once(void) { - *initialize_lock_pointer = new Lock(); + once_pointer->internal_run(once_arg); } } -#endif // !defined(ENABLE_THREADS) +#endif // defined(ENABLE_THREADS) -// Class Initialize_lock. +// Class Once. -Initialize_lock::Initialize_lock(Lock** pplock) - : pplock_(pplock) +Once::Once() + : was_run_(false), was_run_lock_(0) { #ifndef ENABLE_THREADS this->once_ = NULL; #else - this->once_ = new Initialize_lock_once(); + this->once_ = new Once_initialize(); #endif } -// Initialize the lock. +// Run the function once. -bool -Initialize_lock::initialize() +void +Once::run_once(void* arg) { - // 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; +#ifndef ENABLE_THREADS - // We can't initialize the lock until we have read the options. - if (!parameters->options_valid()) - return false; + // If there is no threads support, we don't need to use pthread_once. + if (!this->was_run_) + this->internal_run(arg); - // If the user did not use --threads, then we can initialize - // directly. - if (!parameters->options().threads()) +#else // defined(ENABLE_THREADS) + + if (parameters->options_valid() && !parameters->options().threads()) { - *this->pplock_ = new Lock(); - return true; + // If we are not using threads, we don't need to lock. + if (!this->was_run_) + this->internal_run(arg); + return; } -#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) + // If we have the sync builtins, use them to skip the lock if the + // value has already been initialized. +#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 + while (true) + { + if (__sync_bool_compare_and_swap(&this->was_run_lock_, 0, 1)) + break; + } + bool was_run = this->was_run_; + while (true) + { + if (__sync_bool_compare_and_swap(&this->was_run_lock_, 1, 0)) + break; + } + if (was_run) + return; +#endif // 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. + // pthread_once, we use a static variable: once_pointer. This in + // turns means that we need to use a mutex to control access to + // once_pointer. - int err = pthread_mutex_lock(&initialize_lock_control); + int err = pthread_mutex_lock(&once_pointer_control); if (err != 0) gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err)); - initialize_lock_pointer = this->pplock_; + once_pointer = this; + once_arg = arg; - err = pthread_once(this->once_->once_control(), initialize_lock_once); + err = pthread_once(this->once_->once_control(), c_run_once); if (err != 0) gold_fatal(_("pthread_once failed: %s"), strerror(err)); - initialize_lock_pointer = NULL; + once_pointer = NULL; + once_arg = NULL; - err = pthread_mutex_unlock(&initialize_lock_control); + err = pthread_mutex_unlock(&once_pointer_control); if (err != 0) - gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err)); + gold_fatal(_("pthread_mutex_unlock falied: %s"), strerror(err)); - gold_assert(*this->pplock_ != NULL); +#endif // defined(ENABLE_THREADS) +} + +// Actually run the function in the child class. This function will +// be run only once. + +void +Once::internal_run(void* arg) +{ + this->do_run_once(arg); + this->was_run_ = true; +} + +// Class Initialize_lock. + +// Initialize the lock. + +bool +Initialize_lock::initialize() +{ + // We can't initialize the lock until we have read the options. + if (!parameters->options_valid()) + return false; + else + { + this->run_once(NULL); + return true; + } +} -#endif // !defined(ENABLE_THREADS) +// Initialize the lock exactly once. - return true; +void +Initialize_lock::do_run_once(void*) +{ + *this->pplock_ = new Lock(); } } // End namespace gold. |