* gold-threads.h (class Once): Define.
authorIan Lance Taylor <ian@airs.com>
Fri, 12 Feb 2010 03:23:26 +0000 (03:23 +0000)
committerIan Lance Taylor <ian@airs.com>
Fri, 12 Feb 2010 03:23:26 +0000 (03:23 +0000)
(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.

13 files changed:
gold/ChangeLog
gold/archive.cc
gold/fileread.cc
gold/fileread.h
gold/gold-threads.cc
gold/gold-threads.h
gold/parameters.cc
gold/parameters.h
gold/readsyms.cc
gold/readsyms.h
gold/symtab.h
gold/target-select.cc
gold/target-select.h

index 21d04a58787c12958082c688e44d85b945505130..346806f93dd8686bfe627ab0247694bd7150deba 100644 (file)
@@ -1,3 +1,60 @@
+2010-02-11  Ian Lance Taylor  <iant@google.com>
+
+       * 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.
+
 2010-02-10  Ian Lance Taylor  <iant@google.com>
 
        * dirsearch.cc (Dirsearch::initialize): Add all blockers before
index 011c36ddd613a660d00c623c8494a5779f8d3651..a8b0fc6c7d81b27e9616bbaeba7383752e51e79b 100644 (file)
@@ -1,6 +1,6 @@
 // archive.cc -- archive support for gold
 
-// Copyright 2006, 2007, 2008, 2009 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.
@@ -275,7 +275,8 @@ Archive::interpret_header(const Archive_header* hdr, off_t off,
   else if (hdr->ar_name[1] == ' ')
     {
       // This is the symbol table.
-      pname->clear();
+      if (!pname->empty())
+       pname->clear();
     }
   else if (hdr->ar_name[1] == '/')
     {
index ac30769216eb83d0ed515283939708628c416200..4e8157f7957c33cfb786ca9b693319e6eaa74774 100644 (file)
@@ -1,6 +1,6 @@
 // fileread.cc -- read files for gold
 
-// Copyright 2006, 2007, 2008, 2009 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.
@@ -38,6 +38,7 @@
 #include "target.h"
 #include "binary.h"
 #include "descriptors.h"
+#include "gold-threads.h"
 #include "fileread.h"
 
 #ifndef HAVE_READV
@@ -95,6 +96,10 @@ File_read::View::is_locked()
 
 // Class File_read.
 
+// A lock for the File_read static variables.
+static Lock* file_counts_lock = NULL;
+static Initialize_lock file_counts_initialize_lock(&file_counts_lock);
+
 // The File_read static variables.
 unsigned long long File_read::total_mapped_bytes;
 unsigned long long File_read::current_mapped_bytes;
@@ -204,11 +209,17 @@ File_read::release()
 {
   gold_assert(this->is_locked());
 
-  File_read::total_mapped_bytes += this->mapped_bytes_;
-  File_read::current_mapped_bytes += this->mapped_bytes_;
+  if (!parameters->options_valid() || parameters->options().stats())
+    {
+      file_counts_initialize_lock.initialize();
+      Hold_optional_lock hl(file_counts_lock);
+      File_read::total_mapped_bytes += this->mapped_bytes_;
+      File_read::current_mapped_bytes += this->mapped_bytes_;
+      if (File_read::current_mapped_bytes > File_read::maximum_mapped_bytes)
+       File_read::maximum_mapped_bytes = File_read::current_mapped_bytes;
+    }
+
   this->mapped_bytes_ = 0;
-  if (File_read::current_mapped_bytes > File_read::maximum_mapped_bytes)
-    File_read::maximum_mapped_bytes = File_read::current_mapped_bytes;
 
   // Only clear views if there is only one attached object.  Otherwise
   // we waste time trying to clear cached archive views.  Similarly
index 47c8e0ff27e31a4946b0b6e9b64f3c53697d1319..5aac7ad62741d17288865225b0d4fd9645b2773d 100644 (file)
@@ -1,6 +1,6 @@
 // fileread.h -- read files for gold   -*- C++ -*-
 
-// Copyright 2006, 2007, 2008, 2009 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.
@@ -218,16 +218,15 @@ class File_read
   File_read(const File_read&);
   File_read& operator=(const File_read&);
 
-  // Total bytes mapped into memory during the link.  This variable
-  // may not be accurate when running multi-threaded.
+  // Total bytes mapped into memory during the link if --stats.
   static unsigned long long total_mapped_bytes;
 
-  // Current number of bytes mapped into memory during the link.  This
-  // variable may not be accurate when running multi-threaded.
+  // Current number of bytes mapped into memory during the link if
+  // --stats.
   static unsigned long long current_mapped_bytes;
 
-  // High water mark of bytes mapped into memory during the link.
-  // This variable may not be accurate when running multi-threaded.
+  // High water mark of bytes mapped into memory during the link if
+  // --stats.
   static unsigned long long maximum_mapped_bytes;
 
   // A view into the file.
index b99cf27584746d906f82a465da1e5bb100c0b30b..f5347bfcb4ae9a616f681ca38108a48a01a3ee93 100644 (file)
@@ -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.
index 9c49b57d071697927f1a40618ccc1bf86fe3a628..78a87b24d645221839425b3ff3060067e9b4aba9 100644 (file)
@@ -1,6 +1,6 @@
 // gold-threads.h -- thread support for gold  -*- C++ -*-
 
-// 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.
@@ -35,6 +35,7 @@ namespace gold
 {
 
 class Condvar;
+class Once_initialize;
 class Initialize_lock_once;
 
 // The interface for the implementation of a Lock.
@@ -191,6 +192,39 @@ class Condvar
   Condvar_impl* condvar_;
 };
 
+// A class used to do something once.  This is an abstract parent
+// class; any actual use will involve a child of this.
+
+class Once
+{
+ public:
+  Once();
+
+  // Call this function to do whatever it is.  We pass an argument
+  // even though you have to use a child class because in some uses
+  // setting the argument would itself require a Once class.
+  void
+  run_once(void* arg);
+
+  // This is an internal function, which must be public because it is
+  // run by an extern "C" function called via pthread_once.
+  void
+  internal_run(void* arg);
+
+ protected:
+  // This must be implemented by the child class.
+  virtual void
+  do_run_once(void* arg) = 0;
+
+ private:
+  // True if we have already run the function.
+  bool was_run_;
+  // Internal compare-and-swap lock on was_run_;
+  uint32_t was_run_lock_;
+  // The lock to run the function only once.
+  Once_initialize* once_;
+};
+
 // A class used to initialize a lock exactly once, after the options
 // have been read.  This is needed because the implementation of locks
 // depends on whether we've seen the --threads option.  Before the
@@ -199,23 +233,27 @@ class Condvar
 // variable of the class which has a lock which needs to be
 // initialized.
 
-class Initialize_lock
+class Initialize_lock : public Once
 {
  public:
   // The class which uses this will have a pointer to a lock.  This
   // must be constructed with a pointer to that pointer.
-  Initialize_lock(Lock** pplock);
+  Initialize_lock(Lock** pplock)
+    : pplock_(pplock)
+  { }
 
   // Initialize the lock.  Return true if the lock is now initialized,
   // false if it is not (because the options have not yet been read).
   bool
   initialize();
 
+ protected:
+  void
+  do_run_once(void*);
+
  private:
   // A pointer to the lock pointer which must be initialized.
   Lock** const pplock_;
-  // If needed, a pointer to a pthread_once_t structure.
-  Initialize_lock_once* once_;
 };
 
 } // End namespace gold.
index 9cf78080fab97640b0a4941ca1c9a7b60a068047..1d0f082e197d1ef3644ece068c50c1a1cc414edf 100644 (file)
@@ -1,6 +1,6 @@
 // parameters.cc -- general parameters for a link using 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.
 namespace gold
 {
 
+// Our local version of the variable, which is not const.
+
+static Parameters static_parameters;
+
+// The global variable.
+
+const Parameters* parameters = &static_parameters;
+
+// A helper class to set the target once.
+
+class Set_parameters_target_once : public Once
+{
+ public:
+  Set_parameters_target_once(Parameters* parameters)
+    : parameters_(parameters)
+  { }
+
+ protected:
+  void
+  do_run_once(void* arg)
+  { this->parameters_->set_target_once(static_cast<Target*>(arg)); }
+
+ private:
+  Parameters* parameters_;
+};
+
+// We only need one Set_parameters_target_once.
+
+static
+Set_parameters_target_once set_parameters_target_once(&static_parameters);
+
+// Class Parameters.
+
+Parameters::Parameters()
+   : errors_(NULL), options_(NULL), target_(NULL),
+     doing_static_link_valid_(false), doing_static_link_(false),
+     debug_(0),
+     set_parameters_target_once_(&set_parameters_target_once)
+ {
+ }
+
 void
 Parameters::set_errors(Errors* errors)
 {
@@ -61,10 +102,28 @@ Parameters::set_doing_static_link(bool doing_static_link)
 void
 Parameters::set_target(Target* target)
 {
-  if (!this->target_valid())
-    this->target_ = target;
-  else
-    gold_assert(target == this->target_);
+  this->set_parameters_target_once_->run_once(static_cast<void*>(target));
+  gold_assert(target == this->target_);
+}
+
+// This is called at most once.
+
+void
+Parameters::set_target_once(Target* target)
+{
+  gold_assert(this->target_ == NULL);
+  this->target_ = target;
+}
+
+// Clear the target, for testing.
+
+void
+Parameters::clear_target()
+{
+  this->target_ = NULL;
+  // We need a new Set_parameters_target_once so that we can set the
+  // target again.
+  this->set_parameters_target_once_ = new Set_parameters_target_once(this);
 }
 
 // Return whether TARGET is compatible with the target we are using.
@@ -122,15 +181,6 @@ Parameters::size_and_endianness() const
     gold_unreachable();
 }
 
-
-// Our local version of the variable, which is not const.
-
-static Parameters static_parameters;
-
-// The global variable.
-
-const Parameters* parameters = &static_parameters;
-
 void
 set_parameters_errors(Errors* errors)
 { static_parameters.set_errors(errors); }
index 88d8a870323cff9727cac299d7d5ee1476143472..85b8ef6d67d89043762d07c5d4cc8ff8456c6fa1 100644 (file)
@@ -1,6 +1,6 @@
 // parameters.h -- general parameters for a link using gold  -*- C++ -*-
 
-// 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.
@@ -31,6 +31,7 @@ class Errors;
 class Target;
 template<int size, bool big_endian>
 class Sized_target;
+class Set_parameters_target_once;
 
 // Here we define the Parameters class which simply holds simple
 // general parameters which apply to the entire link.  We use a global
@@ -49,11 +50,7 @@ class Sized_target;
 class Parameters
 {
  public:
-  Parameters()
-    : errors_(NULL), options_(NULL), target_(NULL),
-      doing_static_link_valid_(false), doing_static_link_(false),
-      debug_(0)
-  { }
+  Parameters();
 
   // These should be called as soon as they are known.
   void
@@ -112,8 +109,7 @@ class Parameters
 
   // Clear the target, for testing.
   void
-  clear_target()
-  { this->target_ = NULL; }
+  clear_target();
 
   // Return true if TARGET is compatible with the current target.
   bool
@@ -150,12 +146,18 @@ class Parameters
 
 
  private:
+  void
+  set_target_once(Target*);
+
+  friend class Set_parameters_target_once;
+
   Errors* errors_;
   const General_options* options_;
   Target* target_;
   bool doing_static_link_valid_;
   bool doing_static_link_;
   int debug_;
+  Set_parameters_target_once* set_parameters_target_once_;
 };
 
 // This is a global variable.
index 6cff8534bb9ff679bac69211bcf88723144c3598..cd8814c70f5fbf085d6ca136fb91582884f78693 100644 (file)
@@ -1,6 +1,6 @@
 // readsyms.cc -- read input file symbols for gold
 
-// Copyright 2006, 2007, 2008, 2009 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.
@@ -360,6 +360,19 @@ Read_symbols::do_group(Workqueue* workqueue)
   const Input_file_group* group = this->input_argument_->group();
   Task_token* this_blocker = this->this_blocker_;
 
+  Finish_group* finish_group = new Finish_group(this->input_objects_,
+                                               this->symtab_,
+                                               this->layout_,
+                                               this->mapfile_,
+                                               input_group,
+                                               this->next_blocker_);
+
+  Task_token* next_blocker = new Task_token(true);
+  next_blocker->add_blocker();
+  workqueue->queue_soon(new Start_group(this->symtab_, finish_group,
+                                       this_blocker, next_blocker));
+  this_blocker = next_blocker;
+
   for (Input_file_group::const_iterator p = group->begin();
        p != group->end();
        ++p)
@@ -367,7 +380,7 @@ Read_symbols::do_group(Workqueue* workqueue)
       const Input_argument* arg = &*p;
       gold_assert(arg->is_file());
 
-      Task_token* next_blocker = new Task_token(true);
+      next_blocker = new Task_token(true);
       next_blocker->add_blocker();
       workqueue->queue_soon(new Read_symbols(this->input_objects_,
                                             this->symtab_, this->layout_,
@@ -377,15 +390,9 @@ Read_symbols::do_group(Workqueue* workqueue)
       this_blocker = next_blocker;
     }
 
-  const int saw_undefined = this->symtab_->saw_undefined();
-  workqueue->queue_soon(new Finish_group(this->input_objects_,
-                                        this->symtab_,
-                                        this->layout_,
-                                        this->mapfile_,
-                                        input_group,
-                                        saw_undefined,
-                                        this_blocker,
-                                        this->next_blocker_));
+  finish_group->set_blocker(this_blocker);
+
+  workqueue->queue_soon(finish_group);
 }
 
 // Return a debugging name for a Read_symbols task.
@@ -476,6 +483,40 @@ Add_symbols::run(Workqueue*)
   this->sd_ = NULL;
 }
 
+// Class Start_group.
+
+Start_group::~Start_group()
+{
+  if (this->this_blocker_ != NULL)
+    delete this->this_blocker_;
+  // next_blocker_ is deleted by the task associated with the first
+  // file in the group.
+}
+
+// We need to wait for THIS_BLOCKER_ and unblock NEXT_BLOCKER_.
+
+Task_token*
+Start_group::is_runnable()
+{
+  if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+    return this->this_blocker_;
+  return NULL;
+}
+
+void
+Start_group::locks(Task_locker* tl)
+{
+  tl->add(this, this->next_blocker_);
+}
+
+// Store the number of undefined symbols we see now.
+
+void
+Start_group::run(Workqueue*)
+{
+  this->finish_group_->set_saw_undefined(this->symtab_->saw_undefined());
+}
+
 // Class Finish_group.
 
 Finish_group::~Finish_group()
@@ -507,7 +548,7 @@ Finish_group::locks(Task_locker* tl)
 void
 Finish_group::run(Workqueue*)
 {
-  int saw_undefined = this->saw_undefined_;
+  size_t saw_undefined = this->saw_undefined_;
   while (saw_undefined != this->symtab_->saw_undefined())
     {
       saw_undefined = this->symtab_->saw_undefined();
index c054b57d7c6c59d405f83a7e5286da8893db2298..626cb38ce21d284ece2010d1317bf3480f8b8cfc 100644 (file)
@@ -1,6 +1,6 @@
 // readsyms.h -- read input file symbols for gold   -*- C++ -*-
 
-// 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.
@@ -35,6 +35,7 @@ class Input_objects;
 class Symbol_table;
 class Input_group;
 class Archive;
+class Finish_group;
 
 // This Task is responsible for reading the symbols from an input
 // file.  This also includes reading the relocations so that we can
@@ -200,6 +201,43 @@ class Input_group
   Archives archives_;
 };
 
+// This class starts the handling of a group.  It exists only to pick
+// up the number of undefined symbols at that point, so that we only
+// run back through the group if we saw a new undefined symbol.
+
+class Start_group : public Task
+{
+ public:
+  Start_group(Symbol_table* symtab, Finish_group* finish_group,
+             Task_token* this_blocker, Task_token* next_blocker)
+    : symtab_(symtab), finish_group_(finish_group),
+      this_blocker_(this_blocker), next_blocker_(next_blocker)
+  { }
+
+  ~Start_group();
+
+  // The standard Task methods.
+
+  Task_token*
+  is_runnable();
+
+  void
+  locks(Task_locker*);
+
+  void
+  run(Workqueue*);
+
+  std::string
+  get_name() const
+  { return "Start_group"; }
+
+ private:
+  Symbol_table* symtab_;
+  Finish_group* finish_group_;
+  Task_token* this_blocker_;
+  Task_token* next_blocker_;
+};
+
 // This class is used to finish up handling a group.  It is just a
 // closure.
 
@@ -208,16 +246,28 @@ class Finish_group : public Task
  public:
   Finish_group(Input_objects* input_objects, Symbol_table* symtab,
               Layout* layout, Mapfile* mapfile, Input_group* input_group,
-              int saw_undefined, Task_token* this_blocker,
               Task_token* next_blocker)
     : input_objects_(input_objects), symtab_(symtab),
       layout_(layout), mapfile_(mapfile), input_group_(input_group),
-      saw_undefined_(saw_undefined), this_blocker_(this_blocker),
-      next_blocker_(next_blocker)
+      saw_undefined_(0), this_blocker_(NULL), next_blocker_(next_blocker)
   { }
 
   ~Finish_group();
 
+  // Set the number of undefined symbols when we start processing the
+  // group.  This is called by the Start_group task.
+  void
+  set_saw_undefined(size_t saw_undefined)
+  { this->saw_undefined_ = saw_undefined; }
+
+  // Set the blocker to use for this task.
+  void
+  set_blocker(Task_token* this_blocker)
+  {
+    gold_assert(this->this_blocker_ == NULL);
+    this->this_blocker_ = this_blocker;
+  }
+
   // The standard Task methods.
 
   Task_token*
@@ -239,7 +289,7 @@ class Finish_group : public Task
   Layout* layout_;
   Mapfile* mapfile_;
   Input_group* input_group_;
-  int saw_undefined_;
+  size_t saw_undefined_;
   Task_token* this_blocker_;
   Task_token* next_blocker_;
 };
index c8aac26bd8e649e8a0f780c60d1e13958d7a7cce..1a81fd11ed8f8ecb5705b0109d9f47b6aa88c350 100644 (file)
@@ -1354,7 +1354,7 @@ class Symbol_table
   get_sized_symbol(const Symbol*) const;
 
   // Return the count of undefined symbols seen.
-  int
+  size_t
   saw_undefined() const
   { return this->saw_undefined_; }
 
@@ -1709,7 +1709,7 @@ class Symbol_table
 
   // We increment this every time we see a new undefined symbol, for
   // use in archive groups.
-  int saw_undefined_;
+  size_t saw_undefined_;
   // The index of the first global symbol in the output file.
   unsigned int first_global_index_;
   // The file offset within the output symtab section where we should
index dcd3017f07c31694d77b9a77589b7120ab858ce8..859bc3bd62c9acffc5c0291c41ee7723388ce3ff 100644 (file)
@@ -1,6 +1,6 @@
 // target-select.cc -- select a target for an object file
 
-// 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.
@@ -39,6 +39,14 @@ gold::Target_selector* target_selectors;
 namespace gold
 {
 
+// Class Set_target_once.
+
+void
+Set_target_once::do_run_once(void*)
+{
+  this->target_selector_->set_target();
+}
+
 // Construct a Target_selector, which means adding it to the linked
 // list.  This runs at global constructor time, so we want it to be
 // fast.
@@ -46,32 +54,31 @@ namespace gold
 Target_selector::Target_selector(int machine, int size, bool is_big_endian,
                                 const char* bfd_name)
   : machine_(machine), size_(size), is_big_endian_(is_big_endian),
-    bfd_name_(bfd_name), instantiated_target_(NULL), lock_(NULL),
-    initialize_lock_(&this->lock_)
-    
+    bfd_name_(bfd_name), instantiated_target_(NULL), set_target_once_(this)
 {
   this->next_ = target_selectors;
   target_selectors = this;
 }
 
-// Instantiate the target and return it.  Use a lock to avoid
-// instantiating two instances of the same target.
+// Instantiate the target and return it.  Use SET_TARGET_ONCE_ to
+// avoid instantiating two instances of the same target.
 
 Target*
 Target_selector::instantiate_target()
 {
-  // We assume that the pointer will either be written entirely or not
-  // at all.
-  if (this->instantiated_target_ == NULL)
-    {
-      this->initialize_lock_.initialize();
-      Hold_optional_lock hl(this->lock_);
-      if (this->instantiated_target_ == NULL)
-       this->instantiated_target_ = this->do_instantiate_target();
-    }
+  this->set_target_once_.run_once(NULL);
   return this->instantiated_target_;
 }
 
+// Instantiate the target.  This is called at most once.
+
+void
+Target_selector::set_target()
+{
+  gold_assert(this->instantiated_target_ == NULL);
+  this->instantiated_target_ = this->do_instantiate_target();
+}
+
 // Find the target for an ELF file.
 
 Target*
index d1cd44f229d042745426eaf35f7b315800dfb18f..4e2ea92268434fef69d65ac760258540cae1639d 100644 (file)
@@ -1,6 +1,6 @@
 // target-select.h -- select a target for an object file  -*- C++ -*-
 
-// 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.
@@ -31,6 +31,24 @@ namespace gold
 {
 
 class Target;
+class Target_selector;
+
+// Used to set the target only once.
+
+class Set_target_once : public Once
+{
+ public:
+  Set_target_once(Target_selector* target_selector)
+    : target_selector_(target_selector)
+  { }
+
+ protected:
+  void
+  do_run_once(void*);
+
+ private:
+  Target_selector* target_selector_;
+};
 
 // We want to avoid a master list of targets, which implies using a
 // global constructor.  And we also want the program to start up as
@@ -141,6 +159,12 @@ class Target_selector
   instantiate_target();
 
  private:
+  // Set the target.
+  void
+  set_target();
+
+  friend class Set_target_once;
+
   // ELF machine code.
   const int machine_;
   // Target size--32 or 64.
@@ -154,11 +178,8 @@ class Target_selector
   // The singleton Target structure--this points to an instance of the
   // real implementation.
   Target* instantiated_target_;
-  // Lock to make sure that we don't instantiate the target more than
-  // once.
-  Lock* lock_;
-  // We only want to initialize the lock_ pointer once.
-  Initialize_lock initialize_lock_;
+  // Used to set the target only once.
+  Set_target_once set_target_once_;
 };
 
 // Select the target for an ELF file.