gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gold / gold-threads.cc
index 347170814d587d1ab4412cca9f00bd1580152023..f972a8c97d35a2cb17001658e87eb5ca74ef5407 100644 (file)
@@ -1,6 +1,6 @@
 // gold-threads.cc -- thread support for gold
 
-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Copyright (C) 2006-2020 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -100,14 +100,14 @@ Lock_impl_threads::Lock_impl_threads()
   pthread_mutexattr_t attr;
   int err = pthread_mutexattr_init(&attr);
   if (err != 0)
-    gold_fatal(_("pthead_mutextattr_init failed: %s"), strerror(err));
-#ifdef PTHREAD_MUTEXT_ADAPTIVE_NP
-  err = pthread_mutextattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
+    gold_fatal(_("pthead_mutexattr_init failed: %s"), strerror(err));
+#ifdef PTHREAD_MUTEX_ADAPTIVE_NP
+  err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
   if (err != 0)
-    gold_fatal(_("pthread_mutextattr_settype failed: %s"), strerror(err));
+    gold_fatal(_("pthread_mutexattr_settype failed: %s"), strerror(err));
 #endif
 
-  err = pthread_mutex_init (&this->mutex_, &attr);
+  err = pthread_mutex_init(&this->mutex_, &attr);
   if (err != 0)
     gold_fatal(_("pthread_mutex_init failed: %s"), strerror(err));
 
@@ -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,154 @@ 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_pointer.
+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)
+#if defined(ENABLE_THREADS) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
+    , was_run_lock_(0)
+#endif
 {
 #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_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.
This page took 0.043628 seconds and 4 git commands to generate.