aboutsummaryrefslogtreecommitdiff
path: root/gold/gold-threads.cc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>2010-02-12 03:23:26 +0000
committerIan Lance Taylor <ian@airs.com>2010-02-12 03:23:26 +0000
commit114dfbe13efea1a1405dbcf5d9254e59d309382f (patch)
treec9a9058321b21712c1502a2bbc05225b370f7a23 /gold/gold-threads.cc
parent2310652a4f4b6568a96583e6930904e7c25efdcd (diff)
downloadfsf-binutils-gdb-114dfbe13efea1a1405dbcf5d9254e59d309382f.zip
fsf-binutils-gdb-114dfbe13efea1a1405dbcf5d9254e59d309382f.tar.gz
fsf-binutils-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.cc160
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.