summaryrefslogtreecommitdiff
path: root/gold/gold-threads.cc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>2009-03-24 04:50:32 +0000
committerIan Lance Taylor <ian@airs.com>2009-03-24 04:50:32 +0000
commit7f055c204a4371154123a1816fbec9855ee60ad5 (patch)
tree847b6ee09451800cc64d2f3fd933daf82f3a699b /gold/gold-threads.cc
parentc39465150b2129c17f0a520d91dad23cc0632694 (diff)
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.cc124
1 files changed, 124 insertions, 0 deletions
diff --git a/gold/gold-threads.cc b/gold/gold-threads.cc
index 9aa883d6cc..347170814d 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.