]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Add threading support.
authorIan Lance Taylor <iant@google.com>
Thu, 22 Nov 2007 00:05:51 +0000 (00:05 +0000)
committerIan Lance Taylor <iant@google.com>
Thu, 22 Nov 2007 00:05:51 +0000 (00:05 +0000)
31 files changed:
gold/Makefile.am
gold/Makefile.in
gold/archive.cc
gold/archive.h
gold/common.cc
gold/common.h
gold/debug.h [new file with mode: 0644]
gold/dirsearch.cc
gold/errors.cc
gold/errors.h
gold/gold-threads.cc
gold/gold-threads.h
gold/gold.cc
gold/layout.h
gold/options.cc
gold/options.h
gold/parameters.cc
gold/parameters.h
gold/po/POTFILES.in
gold/po/gold.pot
gold/readsyms.cc
gold/readsyms.h
gold/reloc.cc
gold/reloc.h
gold/script.cc
gold/symtab.cc
gold/symtab.h
gold/workqueue-internal.h [new file with mode: 0644]
gold/workqueue-threads.cc [new file with mode: 0644]
gold/workqueue.cc
gold/workqueue.h

index a91a1c80cc85d560e21234a2736ab013227d4d56..de9be2062bfcb3371f9b169dd0d7f24f80887ff6 100644 (file)
@@ -53,7 +53,8 @@ CCFILES = \
        stringpool.cc \
        target-select.cc \
        version.cc \
-       workqueue.cc
+       workqueue.cc \
+       workqueue-threads.cc
 
 HFILES = \
        archive.h \
@@ -84,7 +85,8 @@ HFILES = \
        target-reloc.h \
        target-select.h \
        tls.h \
-       workqueue.h
+       workqueue.h \
+       workqueue-internal.h
 
 YFILES = \
        yyscript.y
index 9ca37010131611c3971cd5c33c9d37bbd15e2087..fd981d6b9876c9e9b6235cbdf835aa73b8baf0f7 100644 (file)
@@ -78,7 +78,8 @@ am__objects_1 = archive.$(OBJEXT) common.$(OBJEXT) defstd.$(OBJEXT) \
        output.$(OBJEXT) parameters.$(OBJEXT) readsyms.$(OBJEXT) \
        reloc.$(OBJEXT) resolve.$(OBJEXT) script.$(OBJEXT) \
        symtab.$(OBJEXT) stringpool.$(OBJEXT) target-select.$(OBJEXT) \
-       version.$(OBJEXT) workqueue.$(OBJEXT)
+       version.$(OBJEXT) workqueue.$(OBJEXT) \
+       workqueue-threads.$(OBJEXT)
 am__objects_2 =
 am__objects_3 = yyscript.$(OBJEXT)
 am_libgold_a_OBJECTS = $(am__objects_1) $(am__objects_2) \
@@ -307,7 +308,8 @@ CCFILES = \
        stringpool.cc \
        target-select.cc \
        version.cc \
-       workqueue.cc
+       workqueue.cc \
+       workqueue-threads.cc
 
 HFILES = \
        archive.h \
@@ -338,7 +340,8 @@ HFILES = \
        target-reloc.h \
        target-select.h \
        tls.h \
-       workqueue.h
+       workqueue.h \
+       workqueue-internal.h
 
 YFILES = \
        yyscript.y
@@ -487,6 +490,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symtab.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/target-select.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/workqueue-threads.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/workqueue.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x86_64.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/yyscript.Po@am__quote@
index 1442731f045ef867507b3acc203df318802ae24e..dc12ea95701bbb4797238af472c54e8e98c5a5ae 100644 (file)
@@ -475,6 +475,7 @@ Add_archive_symbols::run(Workqueue*)
     {
       // We no longer need to know about this archive.
       delete this->archive_;
+      this->archive_ = NULL;
     }
 }
 
index 61d4d4b891f69ff8483f8e9e7bcaedade121c9ff..57af1673563835e3715acab82d2674d9397f069e 100644 (file)
@@ -187,6 +187,14 @@ class Add_archive_symbols : public Task
   void
   run(Workqueue*);
 
+  std::string
+  get_name() const
+  {
+    if (this->archive_ == NULL)
+      return "Add_archive_symbols";
+    return "Add_archive_symbols " + this->archive_->file().filename();
+  }
+
  private:
   class Add_archive_symbols_locker;
 
index f723de30e19101b6694fc741754f6491baf452c1..3b616b154a1a5661e710357bae3b0e076da1a693 100644 (file)
@@ -226,12 +226,9 @@ Symbol_table::do_allocate_commons(const General_options&,
 
       off = align_address(off, ssym->value());
 
-      Size_type symsize = ssym->symsize();
-      ssym->init(ssym->name(), poc, off, symsize, ssym->type(),
-                ssym->binding(), ssym->visibility(), ssym->nonvis(),
-                false);
+      ssym->allocate_common(poc, off);
 
-      off += symsize;
+      off += ssym->symsize();
     }
 
   poc->set_space_size(off);
index e7fe84e4c66ea60ca69c8f8dfc6fe2cd27f8486b..bd24985c9bea51fe17afa131e20f5b16f15dcf4f 100644 (file)
@@ -54,6 +54,10 @@ class Allocate_commons_task : public Task
   void
   run(Workqueue*);
 
+  std::string
+  get_name() const
+  { return "Allocate_commons_task"; }
+
  private:
   class Allocate_commons_locker;
 
diff --git a/gold/debug.h b/gold/debug.h
new file mode 100644 (file)
index 0000000..c6bfb7a
--- /dev/null
@@ -0,0 +1,51 @@
+// debug.h -- gold internal debugging support   -*- C++ -*-
+
+// Copyright 2007 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#ifndef GOLD_DEBUG_H
+#define GOLD_DEBUG_H
+
+#include "parameters.h"
+#include "errors.h"
+
+namespace gold
+{
+
+// The different types of debugging we support.  These are bitflags.
+
+const int DEBUG_TASK = 1;
+
+const int DEBUG_ALL = DEBUG_TASK;
+
+// Print a debug message if TYPE is enabled.  This is a macro so that
+// we only evaluate the arguments if necessary.
+
+#define gold_debug(TYPE, FORMAT, ...)                          \
+  do                                                           \
+    {                                                          \
+      if (is_debugging_enabled(TYPE))                          \
+       parameters->errors()->debug(FORMAT, __VA_ARGS__);       \
+    }                                                          \
+  while (0)
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_DEBUG_H)
index 45caf86daf269688f49863e29c4d98105c36bae5..dd1c7e6eb2c884d4cb47b6f49027741787822b9c 100644 (file)
@@ -158,7 +158,7 @@ Dir_caches::lookup(const char* dirname) const
 
 // The caches.
 
-Dir_caches caches;
+Dir_caches* caches;
 
 // A Task to read the directory.
 
@@ -169,11 +169,18 @@ class Dir_cache_task : public gold::Task
     : dir_(dir), token_(token)
   { }
 
-  Is_runnable_type is_runnable(gold::Workqueue*);
+  Is_runnable_type
+  is_runnable(gold::Workqueue*);
 
-  gold::Task_locker* locks(gold::Workqueue*);
+  gold::Task_locker*
+  locks(gold::Workqueue*);
 
-  void run(gold::Workqueue*);
+  void
+  run(gold::Workqueue*);
+
+  std::string
+  get_name() const
+  { return std::string("Dir_cache_task ") + this->dir_; }
 
  private:
   const char* dir_;
@@ -202,7 +209,7 @@ Dir_cache_task::locks(gold::Workqueue* workqueue)
 void
 Dir_cache_task::run(gold::Workqueue*)
 {
-  caches.add(this->dir_);
+  caches->add(this->dir_);
 }
 
 }
@@ -214,6 +221,8 @@ void
 Dirsearch::initialize(Workqueue* workqueue,
                      const General_options::Dir_list* directories)
 {
+  gold_assert(caches == NULL);
+  caches = new Dir_caches;
   this->directories_ = directories;
   for (General_options::Dir_list::const_iterator p = directories->begin();
        p != directories->end();
@@ -235,7 +244,7 @@ Dirsearch::find(const std::string& n1, const std::string& n2,
        p != this->directories_->end();
        ++p)
     {
-      Dir_cache* pdc = caches.lookup(p->name().c_str());
+      Dir_cache* pdc = caches->lookup(p->name().c_str());
       gold_assert(pdc != NULL);
       if (pdc->find(n1))
        {
index 2da1a2569edd9e6943b42a522becdf82c893ad1a..c979463dfc25014bcf0138706d7c6682f7e7deac 100644 (file)
@@ -39,11 +39,20 @@ namespace gold
 const int Errors::max_undefined_error_report;
 
 Errors::Errors(const char* program_name)
-  : program_name_(program_name), lock_(), error_count_(0), warning_count_(0),
-    undefined_symbols_()
+  : program_name_(program_name), lock_(NULL), error_count_(0),
+    warning_count_(0), undefined_symbols_()
 {
 }
 
+// Initialize the lock_ field.
+
+void
+Errors::initialize_lock()
+{
+  if (this->lock_ == NULL)
+    this->lock_ = new Lock;
+}
+
 // Report a fatal error.
 
 void
@@ -63,8 +72,10 @@ Errors::error(const char* format, va_list args)
   fprintf(stderr, "%s: ", this->program_name_);
   vfprintf(stderr, format, args);
   fputc('\n', stderr);
+
+  this->initialize_lock();
   {
-    Hold_lock h(this->lock_);
+    Hold_lock h(*this->lock_);
     ++this->error_count_;
   }
 }
@@ -77,8 +88,10 @@ Errors::warning(const char* format, va_list args)
   fprintf(stderr, _("%s: warning: "), this->program_name_);
   vfprintf(stderr, format, args);
   fputc('\n', stderr);
+
+  this->initialize_lock();
   {
-    Hold_lock h(this->lock_);
+    Hold_lock h(*this->lock_);
     ++this->warning_count_;
   }
 }
@@ -95,8 +108,10 @@ Errors::error_at_location(const Relocate_info<size, big_endian>* relinfo,
          relinfo->location(relnum, reloffset).c_str());
   vfprintf(stderr, format, args);
   fputc('\n', stderr);
+
+  this->initialize_lock();
   {
-    Hold_lock h(this->lock_);
+    Hold_lock h(*this->lock_);
     ++this->error_count_;
   }
 }
@@ -113,8 +128,10 @@ Errors::warning_at_location(const Relocate_info<size, big_endian>* relinfo,
          relinfo->location(relnum, reloffset).c_str());
   vfprintf(stderr, format, args);
   fputc('\n', stderr);
+
+  this->initialize_lock();
   {
-    Hold_lock h(this->lock_);
+    Hold_lock h(*this->lock_);
     ++this->warning_count_;
   }
 }
@@ -127,8 +144,9 @@ Errors::undefined_symbol(const Symbol* sym,
                         const Relocate_info<size, big_endian>* relinfo,
                         size_t relnum, off_t reloffset)
 {
+  this->initialize_lock();
   {
-    Hold_lock h(this->lock_);
+    Hold_lock h(*this->lock_);
     if (++this->undefined_symbols_[sym] >= max_undefined_error_report)
       return;
     ++this->error_count_;
@@ -138,6 +156,20 @@ Errors::undefined_symbol(const Symbol* sym,
          sym->demangled_name().c_str());
 }
 
+// Issue a debugging message.
+
+void
+Errors::debug(const char* format, ...)
+{
+  fprintf(stderr, _("%s: "), this->program_name_);
+
+  va_list args;
+  va_start(args, format);
+  vfprintf(stderr, format, args);
+  va_end(args);
+
+  fputc('\n', stderr);
+}
 
 // The functions which the rest of the code actually calls.
 
index 545c463bad31568fe1df813b62c9cbf4da1995be..17b72e10b368b5da6619bb5c19b8ba38e7ba8a13 100644 (file)
@@ -80,6 +80,10 @@ class Errors
                   const Relocate_info<size, big_endian>* relinfo,
                   size_t relnum, off_t reloffset);
 
+  // Report a debugging message.
+  void
+  debug(const char* format, ...) ATTRIBUTE_PRINTF_2;
+
   // Return the number of errors.
   int
   error_count() const
@@ -89,6 +93,12 @@ class Errors
   Errors(const Errors&);
   Errors& operator=(const Errors&);
 
+  // Initialize the lock.  We don't do this in the constructor because
+  // lock initialization wants to know whether we are using threads or
+  // not.
+  void
+  initialize_lock();
+
   // The number of times we report an undefined symbol.
   static const int max_undefined_error_report = 5;
 
@@ -96,7 +106,7 @@ class Errors
   const char* program_name_;
   // This class can be accessed from multiple threads.  This lock is
   // used to control access to the data structures.
-  Lock lock_;
+  Lock* lock_;
   // Numbers of errors reported.
   int error_count_;
   // Number of warnings reported.
index 396e6c10631ae7df124a1aa1cfedcb59d09db3a8..4ebbdd84960804a208a7a97654ca03f2a7fae34b 100644 (file)
 
 #include "gold.h"
 
-#include <cerrno>
 #include <cstring>
 
 #ifdef ENABLE_THREADS
 #include <pthread.h>
 #endif
 
+#include "parameters.h"
 #include "gold-threads.h"
 
 namespace gold
 {
 
-// Class Lock_impl. 
+class Condvar_impl_nothreads;
 
-class Lock_impl
+// The non-threaded version of Lock_impl.
+
+class Lock_impl_nothreads : public Lock_impl
 {
  public:
-  Lock_impl();
-  ~Lock_impl();
+  Lock_impl_nothreads()
+    : acquired_(false)
+  { }
+
+  ~Lock_impl_nothreads()
+  { gold_assert(!this->acquired_); }
+
+  void
+  acquire()
+  {
+    gold_assert(!this->acquired_);
+    this->acquired_ = true;
+  }
+
+  void
+  release()
+  {
+    gold_assert(this->acquired_);
+    this->acquired_ = false;
+  }
+
+ private:
+  friend class Condvar_impl_nothreads;
+
+  bool acquired_;
+};
+
+#ifdef ENABLE_THREADS
+
+class Condvar_impl_threads;
+
+// The threaded version of Lock_impl.
+
+class Lock_impl_threads : public Lock_impl
+{
+ public:
+  Lock_impl_threads();
+  ~Lock_impl_threads();
 
   void acquire();
 
@@ -48,187 +86,188 @@ class Lock_impl
 
 private:
   // This class can not be copied.
-  Lock_impl(const Lock_impl&);
-  Lock_impl& operator=(const Lock_impl&);
+  Lock_impl_threads(const Lock_impl_threads&);
+  Lock_impl_threads& operator=(const Lock_impl_threads&);
 
-  friend class Condvar_impl;
+  friend class Condvar_impl_threads;
 
-#ifdef ENABLE_THREADS
   pthread_mutex_t mutex_;
-#else
-  bool acquired_;
-#endif
 };
 
-#ifdef ENABLE_THREADS
-
-Lock_impl::Lock_impl()
+Lock_impl_threads::Lock_impl_threads()
 {
   pthread_mutexattr_t attr;
-  if (pthread_mutexattr_init(&attr) != 0)
-    gold_fatal(_("pthead_mutextattr_init failed: %s"), strerror(errno));
+  int err = pthread_mutexattr_init(&attr);
+  if (err != 0)
+    gold_fatal(_("pthead_mutextattr_init failed: %s"), strerror(err));
 #ifdef PTHREAD_MUTEXT_ADAPTIVE_NP
-  if (pthread_mutextattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP) != 0)
-    gold_fatal(_("pthread_mutextattr_settype failed: %s"), strerror(errno));
+  err = pthread_mutextattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
+  if (err != 0)
+    gold_fatal(_("pthread_mutextattr_settype failed: %s"), strerror(err));
 #endif
 
-  if (pthread_mutex_init (&this->mutex_, &attr) != 0)
-    gold_fatal(_("pthread_mutex_init failed: %s"), strerror(errno));
+  err = pthread_mutex_init (&this->mutex_, &attr);
+  if (err != 0)
+    gold_fatal(_("pthread_mutex_init failed: %s"), strerror(err));
 
-  if (pthread_mutexattr_destroy(&attr) != 0)
-    gold_fatal(_("pthread_mutexattr_destroy failed: %s"), strerror(errno));
+  err = pthread_mutexattr_destroy(&attr);
+  if (err != 0)
+    gold_fatal(_("pthread_mutexattr_destroy failed: %s"), strerror(err));
 }
 
-Lock_impl::~Lock_impl()
+Lock_impl_threads::~Lock_impl_threads()
 {
-  if (pthread_mutex_destroy(&this->mutex_) != 0)
-    gold_fatal(_("pthread_mutex_destroy failed: %s"), strerror(errno));
+  int err = pthread_mutex_destroy(&this->mutex_);
+  if (err != 0)
+    gold_fatal(_("pthread_mutex_destroy failed: %s"), strerror(err));
 }
 
 void
-Lock_impl::acquire()
+Lock_impl_threads::acquire()
 {
-  if (pthread_mutex_lock(&this->mutex_) != 0)
-    gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(errno));
+  int err = pthread_mutex_lock(&this->mutex_);
+  if (err != 0)
+    gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err));
 }
 
 void
-Lock_impl::release()
+Lock_impl_threads::release()
 {
-  if (pthread_mutex_unlock(&this->mutex_) != 0)
-    gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(errno));
+  int err = pthread_mutex_unlock(&this->mutex_);
+  if (err != 0)
+    gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err));
 }
 
-#else // !defined(ENABLE_THREADS)
+#endif // defined(ENABLE_THREADS)
 
-Lock_impl::Lock_impl()
-  : acquired_(false)
-{
-}
+// Class Lock.
 
-Lock_impl::~Lock_impl()
+Lock::Lock()
 {
-  gold_assert(!this->acquired_);
+  if (!parameters->threads())
+    this->lock_ = new Lock_impl_nothreads;
+  else
+    {
+#ifdef ENABLE_THREADS
+      this->lock_ = new Lock_impl_threads;
+#else
+      gold_unreachable();
+#endif
+    }
 }
 
-void
-Lock_impl::acquire()
+Lock::~Lock()
 {
-  gold_assert(!this->acquired_);
-  this->acquired_ = true;
+  delete this->lock_;
 }
 
-void
-Lock_impl::release()
+// The non-threaded version of Condvar_impl.
+
+class Condvar_impl_nothreads : public Condvar_impl
 {
-  gold_assert(this->acquired_);
-  this->acquired_ = false;
-}
+ public:
+  Condvar_impl_nothreads()
+  { }
 
-#endif // !defined(ENABLE_THREADS)
+  ~Condvar_impl_nothreads()
+  { }
 
-// Methods for Lock class.
+  void
+  wait(Lock_impl* li)
+  { gold_assert(static_cast<Lock_impl_nothreads*>(li)->acquired_); }
 
-Lock::Lock()
-{
-  this->lock_ = new Lock_impl;
-}
-
-Lock::~Lock()
-{
-  delete this->lock_;
-}
+  void
+  signal()
+  { }
 
-void
-Lock::acquire()
-{
-  this->lock_->acquire();
-}
+  void
+  broadcast()
+  { }
+};
 
-void
-Lock::release()
-{
-  this->lock_->release();
-}
+#ifdef ENABLE_THREADS
 
-// Class Condvar_impl.
+// The threaded version of Condvar_impl.
 
-class Condvar_impl
+class Condvar_impl_threads : public Condvar_impl
 {
  public:
-  Condvar_impl();
-  ~Condvar_impl();
+  Condvar_impl_threads();
+  ~Condvar_impl_threads();
 
-  void wait(Lock_impl*);
-  void signal();
+  void
+  wait(Lock_impl*);
+
+  void
+  signal();
+
+  void
+  broadcast();
 
  private:
   // This class can not be copied.
-  Condvar_impl(const Condvar_impl&);
-  Condvar_impl& operator=(const Condvar_impl&);
+  Condvar_impl_threads(const Condvar_impl_threads&);
+  Condvar_impl_threads& operator=(const Condvar_impl_threads&);
 
-#ifdef ENABLE_THREADS
   pthread_cond_t cond_;
-#endif
 };
 
-#ifdef ENABLE_THREADS
-
-Condvar_impl::Condvar_impl()
-{
-  if (pthread_cond_init(&this->cond_, NULL) != 0)
-    gold_fatal(_("pthread_cond_init failed: %s"), strerror(errno));
-}
-
-Condvar_impl::~Condvar_impl()
+Condvar_impl_threads::Condvar_impl_threads()
 {
-  if (pthread_cond_destroy(&this->cond_) != 0)
-    gold_fatal(_("pthread_cond_destroy failed: %s"), strerror(errno));
+  int err = pthread_cond_init(&this->cond_, NULL);
+  if (err != 0)
+    gold_fatal(_("pthread_cond_init failed: %s"), strerror(err));
 }
 
-void
-Condvar_impl::wait(Lock_impl* li)
+Condvar_impl_threads::~Condvar_impl_threads()
 {
-  if (pthread_cond_wait(&this->cond_, &li->mutex_) != 0)
-    gold_fatal(_("pthread_cond_wait failed: %s"), strerror(errno));
+  int err = pthread_cond_destroy(&this->cond_);
+  if (err != 0)
+    gold_fatal(_("pthread_cond_destroy failed: %s"), strerror(err));
 }
 
 void
-Condvar_impl::signal()
-{
-  if (pthread_cond_signal(&this->cond_) != 0)
-    gold_fatal(_("pthread_cond_signal failed: %s"), strerror(errno));
-}
-
-#else // !defined(ENABLE_THREADS)
-
-Condvar_impl::Condvar_impl()
-{
-}
-
-Condvar_impl::~Condvar_impl()
+Condvar_impl_threads::wait(Lock_impl* li)
 {
+  Lock_impl_threads* lit = static_cast<Lock_impl_threads*>(li);
+  int err = pthread_cond_wait(&this->cond_, &lit->mutex_);
+  if (err != 0)
+    gold_fatal(_("pthread_cond_wait failed: %s"), strerror(err));
 }
 
 void
-Condvar_impl::wait(Lock_impl* li)
+Condvar_impl_threads::signal()
 {
-  gold_assert(li->acquired_);
+  int err = pthread_cond_signal(&this->cond_);
+  if (err != 0)
+    gold_fatal(_("pthread_cond_signal failed: %s"), strerror(err));
 }
 
 void
-Condvar_impl::signal()
+Condvar_impl_threads::broadcast()
 {
+  int err = pthread_cond_broadcast(&this->cond_);
+  if (err != 0)
+    gold_fatal(_("pthread_cond_broadcast failed: %s"), strerror(err));
 }
 
-#endif // !defined(ENABLE_THREADS)
+#endif // defined(ENABLE_THREADS)
 
 // Methods for Condvar class.
 
 Condvar::Condvar(Lock& lock)
   : lock_(lock)
 {
-  this->condvar_ = new Condvar_impl;
+  if (!parameters->threads())
+    this->condvar_ = new Condvar_impl_nothreads;
+  else
+    {
+#ifdef ENABLE_THREADS
+      this->condvar_ = new Condvar_impl_threads;
+#else
+      gold_unreachable();
+#endif
+    }
 }
 
 Condvar::~Condvar()
@@ -236,16 +275,4 @@ Condvar::~Condvar()
   delete this->condvar_;
 }
 
-void
-Condvar::wait()
-{
-  this->condvar_->wait(this->lock_.get_impl());
-}
-
-void
-Condvar::signal()
-{
-  this->condvar_->signal();
-}
-
 } // End namespace gold.
index a6f1752efe85dfac4be7bfe184acfb00111122a6..45f18ad2c5c0ffbd0447133c31b9ec92368883bf 100644 (file)
 namespace gold
 {
 
-class Lock_impl;
 class Condvar;
 
+// The interface for the implementation of a Lock.
+
+class Lock_impl
+{
+ public:
+  Lock_impl()
+  { }
+
+  virtual
+  ~Lock_impl()
+  { }
+
+  virtual void
+  acquire() = 0;
+
+  virtual void
+  release() = 0;
+};
+
 // A simple lock class.
 
 class Lock
 {
  public:
   Lock();
+
   ~Lock();
 
   // Acquire the lock.
   void
-  acquire();
+  acquire()
+  { this->lock_->acquire(); }
 
   // Release the lock.
   void
-  release();
+  release()
+  { this->lock_->release(); }
 
  private:
   // This class can not be copied.
@@ -86,7 +107,27 @@ class Hold_lock
   Lock& lock_;
 };
 
-class Condvar_impl;
+// The interface for the implementation of a condition variable.
+
+class Condvar_impl
+{
+ public:
+  Condvar_impl()
+  { }
+
+  virtual
+  ~Condvar_impl()
+  { }
+
+  virtual void
+  wait(Lock_impl*) = 0;
+
+  virtual void
+  signal() = 0;
+
+  virtual void
+  broadcast() = 0;
+};
 
 // A simple condition variable class.  It is always associated with a
 // specific lock.
@@ -100,12 +141,22 @@ class Condvar
   // Wait for the condition variable to be signalled.  This should
   // only be called when the lock is held.
   void
-  wait();
+  wait()
+  { this->condvar_->wait(this->lock_.get_impl()); }
+
+  // Signal the condition variable--wake up at least one thread
+  // waiting on the condition variable.  This should only be called
+  // when the lock is held.
+  void
+  signal()
+  { this->condvar_->signal(); }
 
-  // Signal the condition variable.  This should only be called when
-  // the lock is held.
+  // Broadcast the condition variable--wake up all threads waiting on
+  // the condition variable.  This should only be called when the lock
+  // is held.
   void
-  signal();
+  broadcast()
+  { this->condvar_->broadcast(); }
 
  private:
   // This class can not be copied.
index a4f145efba662a9efd61681fe9dee10df361025b..9baebaf6022a2f71212698ce688f2b018e18c816 100644 (file)
@@ -143,7 +143,8 @@ queue_initial_tasks(const General_options& options,
                                                       input_objects,
                                                       symtab,
                                                       layout),
-                                    this_blocker));
+                                    this_blocker,
+                                    "Task_function Middle_runner"));
 }
 
 // Queue up the middle set of tasks.  These are the tasks which run
@@ -239,7 +240,8 @@ queue_middle_tasks(const General_options& options,
                                                            input_objects,
                                                            symtab,
                                                            layout),
-                                    blocker));
+                                    blocker,
+                                    "Task_function Layout_task_runner"));
 }
 
 // Queue up the final set of tasks.  This is called at the end of
@@ -312,7 +314,8 @@ queue_final_tasks(const General_options& options,
   // Queue a task to close the output file.  This will be blocked by
   // FINAL_BLOCKER.
   workqueue->queue(new Task_function(new Close_task_runner(of),
-                                    final_blocker));
+                                    final_blocker,
+                                    "Task_function Close_task_runner"));
 }
 
 } // End namespace gold.
index 5b9f28defe6bea23055a7ae44f0196f38abb8960..9e0bcf7254345adf05cdc47b0a787bc0d91b7f50 100644 (file)
@@ -463,6 +463,10 @@ class Write_sections_task : public Task
   void
   run(Workqueue*);
 
+  std::string
+  get_name() const
+  { return "Write_sections_task"; }
+
  private:
   class Write_sections_locker;
 
@@ -494,6 +498,10 @@ class Write_data_task : public Task
   void
   run(Workqueue*);
 
+  std::string
+  get_name() const
+  { return "Write_data_task"; }
+
  private:
   const Layout* layout_;
   const Symbol_table* symtab_;
@@ -525,6 +533,10 @@ class Write_symbols_task : public Task
   void
   run(Workqueue*);
 
+  std::string
+  get_name() const
+  { return "Write_symbols_task"; }
+
  private:
   const Symbol_table* symtab_;
   const Input_objects* input_objects_;
@@ -561,6 +573,10 @@ class Write_after_input_sections_task : public Task
   void
   run(Workqueue*);
 
+  std::string
+  get_name() const
+  { return "Write_after_input_sections_task"; }
+
  private:
   class Write_sections_locker;
 
index c962188f1c26c3c78c4826e2ad078490c3d87662..fb7990182c9cb3add1c16977e09568043d4f6613 100644 (file)
@@ -28,6 +28,7 @@
 #include "filenames.h"
 #include "libiberty.h"
 
+#include "debug.h"
 #include "options.h"
 
 namespace gold
@@ -106,6 +107,17 @@ struct options::One_z_option
   void (General_options::*set)();
 };
 
+// We have a separate table for --debug options.
+
+struct options::One_debug_option
+{
+  // The name of the option.
+  const char* name;
+
+  // The flags to turn on.
+  unsigned int debug_flags;
+};
+
 class options::Command_line_options
 {
  public:
@@ -113,6 +125,8 @@ class options::Command_line_options
   static const int options_size;
   static const One_z_option z_options[];
   static const int z_options_size;
+  static const One_debug_option debug_options[];
+  static const int debug_options_size;
 };
 
 } // End namespace gold.
@@ -247,7 +261,7 @@ help(int, char**, char*, bool, gold::Command_line*)
       std::puts(options[i].doc);
     }
 
-  ::exit(0);
+  ::exit(EXIT_SUCCESS);
 
   return 0;
 }
@@ -258,7 +272,7 @@ int
 version(int, char**, char* opt, bool, gold::Command_line*)
 {
   gold::print_version(opt[0] == 'v' && opt[1] == '\0');
-  ::exit(0);
+  ::exit(EXIT_SUCCESS);
   return 0;
 }
 
@@ -466,7 +480,10 @@ options::Command_line_options::options[] =
   SPECIAL('\0', "help", N_("Report usage information"), NULL,
          TWO_DASHES, &help),
   SPECIAL('v', "version", N_("Report version information"), NULL,
-         TWO_DASHES, &version)
+         TWO_DASHES, &version),
+  GENERAL_ARG('\0', "debug", N_("Turn on debugging (all,task)"),
+             N_("--debug=TYPE"), TWO_DASHES,
+             &General_options::handle_debug_option)
 };
 
 const int options::Command_line_options::options_size =
@@ -484,6 +501,18 @@ options::Command_line_options::z_options[] =
 const int options::Command_line_options::z_options_size =
   sizeof(z_options) / sizeof(z_options[0]);
 
+// The --debug options.
+
+const options::One_debug_option
+options::Command_line_options::debug_options[] =
+{
+  { "all", DEBUG_ALL },
+  { "task", DEBUG_TASK },
+};
+
+const int options::Command_line_options::debug_options_size =
+  sizeof(debug_options) / sizeof(debug_options[0]);
+
 // The default values for the general options.
 
 General_options::General_options()
@@ -509,7 +538,8 @@ General_options::General_options()
     thread_count_initial_(0),
     thread_count_middle_(0),
     thread_count_final_(0),
-    execstack_(EXECSTACK_FROM_INPUT)
+    execstack_(EXECSTACK_FROM_INPUT),
+    debug_(0)
 {
   // We initialize demangle_ based on the environment variable
   // COLLECT_NO_DEMANGLE.  The gcc collect2 program will demangle the
@@ -547,7 +577,30 @@ General_options::handle_z_option(const char* arg)
 
   fprintf(stderr, _("%s: unrecognized -z subcommand: %s\n"),
          program_name, arg);
-  ::exit(1);
+  ::exit(EXIT_FAILURE);
+}
+
+// Handle the --debug option.
+
+void
+General_options::handle_debug_option(const char* arg)
+{
+  const int debug_options_size =
+    options::Command_line_options::debug_options_size;
+  const gold::options::One_debug_option* debug_options =
+    options::Command_line_options::debug_options;
+  for (int i = 0; i < debug_options_size; ++i)
+    {
+      if (strcmp(arg, debug_options[i].name) == 0)
+       {
+         this->set_debug(debug_options[i].debug_flags);
+         return;
+       }
+    }
+
+  fprintf(stderr, _("%s: unrecognized --debug subcommand: %s\n"),
+         program_name, arg);
+  ::exit(EXIT_FAILURE);
 }
 
 // Add the sysroot, if any, to the search paths.
@@ -961,7 +1014,7 @@ Command_line::usage()
   fprintf(stderr,
          _("%s: use the --help option for usage information\n"),
          program_name);
-  ::exit(1);
+  ::exit(EXIT_FAILURE);
 }
 
 void
index 48047c2aa3b687a3701d77e4b1ce9b007ae26862..c7b08e8633f6da0fb4d513b7890bd0742e035404 100644 (file)
@@ -46,11 +46,13 @@ class Command_line;
 class Input_file_group;
 class Position_dependent_options;
 
-namespace options {
+namespace options
+{
 
 class Command_line_options;
 struct One_option;
 struct One_z_option;
+struct One_debug_option;
 
 } // End namespace gold::options.
 
@@ -249,6 +251,11 @@ class General_options
   is_stack_executable() const
   { return this->execstack_ == EXECSTACK_YES; }
 
+  // --debug
+  unsigned int
+  debug() const
+  { return this->debug_; }
+
  private:
   // Don't copy this structure.
   General_options(const General_options&);
@@ -444,10 +451,18 @@ class General_options
   set_noexecstack()
   { this->execstack_ = EXECSTACK_NO; }
 
+  void
+  set_debug(unsigned int flags)
+  { this->debug_ = flags; }
+
   // Handle the -z option.
   void
   handle_z_option(const char*);
 
+  // Handle the --debug option.
+  void
+  handle_debug_option(const char*);
+
   // Apply any sysroot to the directory lists.
   void
   add_sysroot();
@@ -476,6 +491,7 @@ class General_options
   int thread_count_middle_;
   int thread_count_final_;
   Execstack execstack_;
+  unsigned int debug_;
 };
 
 // The current state of the position dependent options.
index 7fbbf836778957f9b7505f114ac8af35bcbc38ff..cd05ffee8ddfda4c1a3fc440b32cffdcb30d8645 100644 (file)
@@ -31,11 +31,11 @@ namespace gold
 // Initialize the parameters from the options.
 
 Parameters::Parameters(Errors* errors)
-  : errors_(errors), output_file_name_(NULL),
+  : errors_(errors), threads_(false), output_file_name_(NULL),
     output_file_type_(OUTPUT_INVALID), sysroot_(),
     strip_(STRIP_INVALID), allow_shlib_undefined_(false),
     symbolic_(false), demangle_(false), detect_odr_violations_(false),
-    optimization_level_(0), export_dynamic_(false),
+    optimization_level_(0), export_dynamic_(false), debug_(0),
     is_doing_static_link_valid_(false), doing_static_link_(false),
     is_size_and_endian_valid_(false), size_(0), is_big_endian_(false)
 {
@@ -46,6 +46,7 @@ Parameters::Parameters(Errors* errors)
 void
 Parameters::set_from_options(const General_options* options)
 {
+  this->threads_ = options->threads();
   this->output_file_name_ = options->output_file_name();
   this->sysroot_ = options->sysroot();
   this->allow_shlib_undefined_ = options->allow_shlib_undefined();
@@ -54,6 +55,7 @@ Parameters::set_from_options(const General_options* options)
   this->detect_odr_violations_ = options->detect_odr_violations();
   this->optimization_level_ = options->optimization_level();
   this->export_dynamic_ = options->export_dynamic();
+  this->debug_ = options->debug();
 
   if (options->is_shared())
     this->output_file_type_ = OUTPUT_SHARED;
index 3186b6d454d3e848beb28a2fa4536456110c1941..4e135c61e27504233c971040de210d387afab845 100644 (file)
@@ -47,6 +47,14 @@ class Parameters
   errors() const
   { return this->errors_; }
 
+  // Whether to use threads.
+  bool
+  threads() const
+  {
+    gold_assert(this->options_valid_);
+    return this->threads_;
+  }
+
   // Return the output file name.
   const char*
   output_file_name() const
@@ -166,6 +174,15 @@ class Parameters
     return this->export_dynamic_;
   }
 
+  // Return the debug flags.  These are the flags for which we should
+  // report internal debugging information.
+  unsigned int
+  debug() const
+  {
+    gold_assert(this->options_valid_);
+    return this->debug_;
+  }
+
   // Whether we are doing a static link--a link in which none of the
   // input files are shared libraries.  This is only known after we
   // have seen all the input files.
@@ -239,6 +256,8 @@ class Parameters
 
   // Whether the fields set from the options are valid.
   bool options_valid_;
+  // Whether to use threads.
+  bool threads_;
   // The output file name.
   const char* output_file_name_;
   // The type of the output file.
@@ -259,6 +278,8 @@ class Parameters
   int optimization_level_;
   // Whether the -E/--export-dynamic flag is set.
   bool export_dynamic_;
+  // The debug flags.
+  unsigned int debug_;
 
   // Whether the doing_static_link_ field is valid.
   bool is_doing_static_link_valid_;
@@ -287,6 +308,13 @@ extern void set_parameters_size_and_endianness(int size, bool is_big_endian);
 // Set whether we are doing a static link.
 extern void set_parameters_doing_static_link(bool doing_static_link);
 
+// Return whether we are doing a particular debugging type.  The
+// argument is one of the flags from debug.h.
+
+inline bool
+is_debugging_enabled(unsigned int type)
+{ return (parameters->debug() & type) != 0; }
+
 } // End namespace gold.
 
 #endif // !defined(GOLD_PARAMETERS_H)
index a78d65d0650a7a429e36de6be136b9b313e99aaa..3797b1a3b226bf9e1546cda80c15aebc7524286f 100644 (file)
@@ -54,4 +54,6 @@ tls.h
 version.cc
 workqueue.cc
 workqueue.h
+workqueue-internal.h
+workqueue-threads.cc
 x86_64.cc
index c9e1e0d10de100c07e1e9925c3c1aff35afdbcd6..73f1f01531040a5ec5f22fd25e6dc22acfcaae85 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-11-09 15:55-0800\n"
+"POT-Creation-Date: 2007-11-20 16:37-0800\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,47 +16,47 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: archive.cc:88
+#: archive.cc:95
 #, c-format
 msgid "%s: no archive symbol table (run ranlib)"
 msgstr ""
 
-#: archive.cc:138
+#: archive.cc:145
 #, c-format
 msgid "%s: bad archive symbol table names"
 msgstr ""
 
-#: archive.cc:168
+#: archive.cc:175
 #, c-format
 msgid "%s: malformed archive header at %zu"
 msgstr ""
 
-#: archive.cc:188
+#: archive.cc:195
 #, c-format
 msgid "%s: malformed archive header size at %zu"
 msgstr ""
 
-#: archive.cc:199
+#: archive.cc:206
 #, c-format
 msgid "%s: malformed archive header name at %zu"
 msgstr ""
 
-#: archive.cc:224
+#: archive.cc:231
 #, c-format
 msgid "%s: bad extended name index at %zu"
 msgstr ""
 
-#: archive.cc:234
+#: archive.cc:241
 #, c-format
 msgid "%s: bad extended name entry at header %zu"
 msgstr ""
 
-#: archive.cc:327
+#: archive.cc:334
 #, c-format
 msgid "%s: short archive header at %zu"
 msgstr ""
 
-#: archive.cc:378 archive.cc:392
+#: archive.cc:385 archive.cc:399
 #, c-format
 msgid "%s: member at %zu is not an ELF object"
 msgstr ""
@@ -66,110 +66,115 @@ msgstr ""
 msgid "%s: can not read directory: %s"
 msgstr ""
 
-#: dynobj.cc:151
+#: dynobj.cc:145
 #, c-format
 msgid "unexpected duplicate type %u section: %u, %u"
 msgstr ""
 
-#: dynobj.cc:187
+#: dynobj.cc:181
 #, c-format
 msgid "unexpected link in section %u header: %u != %u"
 msgstr ""
 
-#: dynobj.cc:222
+#: dynobj.cc:217
 #, c-format
 msgid "DYNAMIC section %u link out of range: %u"
 msgstr ""
 
-#: dynobj.cc:230
+#: dynobj.cc:225
 #, c-format
 msgid "DYNAMIC section %u link %u is not a strtab"
 msgstr ""
 
-#: dynobj.cc:250
+#: dynobj.cc:253
 #, c-format
 msgid "DT_SONAME value out of range: %lld >= %lld"
 msgstr ""
 
 #: dynobj.cc:265
+#, c-format
+msgid "DT_NEEDED value out of range: %lld >= %lld"
+msgstr ""
+
+#: dynobj.cc:278
 msgid "missing DT_NULL in dynamic segment"
 msgstr ""
 
-#: dynobj.cc:309
+#: dynobj.cc:322
 #, c-format
 msgid "invalid dynamic symbol table name index: %u"
 msgstr ""
 
-#: dynobj.cc:316
+#: dynobj.cc:329
 #, c-format
 msgid "dynamic symbol table name section has wrong type: %u"
 msgstr ""
 
-#: dynobj.cc:389 object.cc:234 object.cc:569
+#: dynobj.cc:402 object.cc:236 object.cc:571
 #, c-format
 msgid "bad section name offset for section %u: %lu"
 msgstr ""
 
-#: dynobj.cc:418
+#: dynobj.cc:431
 #, c-format
 msgid "duplicate definition for version %u"
 msgstr ""
 
-#: dynobj.cc:447
+#: dynobj.cc:460
 #, c-format
 msgid "unexpected verdef version %u"
 msgstr ""
 
-#: dynobj.cc:463
+#: dynobj.cc:476
 #, c-format
 msgid "verdef vd_cnt field too small: %u"
 msgstr ""
 
-#: dynobj.cc:470
+#: dynobj.cc:483
 #, c-format
 msgid "verdef vd_aux field out of range: %u"
 msgstr ""
 
-#: dynobj.cc:480
+#: dynobj.cc:493
 #, c-format
 msgid "verdaux vda_name field out of range: %u"
 msgstr ""
 
-#: dynobj.cc:489
+#: dynobj.cc:502
 #, c-format
 msgid "verdef vd_next field out of range: %u"
 msgstr ""
 
-#: dynobj.cc:522
+#: dynobj.cc:535
 #, c-format
 msgid "unexpected verneed version %u"
 msgstr ""
 
-#: dynobj.cc:531
+#: dynobj.cc:544
 #, c-format
 msgid "verneed vn_aux field out of range: %u"
 msgstr ""
 
-#: dynobj.cc:544
+#: dynobj.cc:557
 #, c-format
 msgid "vernaux vna_name field out of range: %u"
 msgstr ""
 
-#: dynobj.cc:555
+#: dynobj.cc:568
 #, c-format
 msgid "verneed vna_next field out of range: %u"
 msgstr ""
 
-#: dynobj.cc:566
+#: dynobj.cc:579
 #, c-format
 msgid "verneed vn_next field out of range: %u"
 msgstr ""
 
-#: dynobj.cc:613
+#: dynobj.cc:626
 msgid "size of dynamic symbols is not multiple of symbol size"
 msgstr ""
 
-#: dynobj.cc:1290
+#: dynobj.cc:1303
 #, c-format
 msgid "symbol %s has undefined version %s"
 msgstr ""
@@ -189,6 +194,11 @@ msgstr ""
 msgid "%s: %s: undefined reference to '%s'\n"
 msgstr ""
 
+#: errors.cc:146
+#, c-format
+msgid "%s: "
+msgstr ""
+
 #: fileread.cc:49
 #, c-format
 msgid "munmap failed: %s"
@@ -251,12 +261,12 @@ msgstr ""
 
 #. We had some input files, but we weren't able to open any of
 #. them.
-#: gold.cc:118 gold.cc:164
+#: gold.cc:118 gold.cc:165
 msgid "no input files"
 msgstr ""
 
 #. We print out just the first .so we see; there may be others.
-#: gold.cc:179
+#: gold.cc:180
 #, c-format
 msgid "cannot mix -static with dynamic object %s"
 msgstr ""
@@ -266,97 +276,98 @@ msgstr ""
 msgid "pthead_mutextattr_init failed: %s"
 msgstr ""
 
-#: gold-threads.cc:72
+#: gold-threads.cc:73
 #, c-format
 msgid "pthread_mutextattr_settype failed: %s"
 msgstr ""
 
-#: gold-threads.cc:76
+#: gold-threads.cc:78
 #, c-format
 msgid "pthread_mutex_init failed: %s"
 msgstr ""
 
-#: gold-threads.cc:79
+#: gold-threads.cc:82
 #, c-format
 msgid "pthread_mutexattr_destroy failed: %s"
 msgstr ""
 
-#: gold-threads.cc:85
+#: gold-threads.cc:89
 #, c-format
 msgid "pthread_mutex_destroy failed: %s"
 msgstr ""
 
-#: gold-threads.cc:92
+#: gold-threads.cc:97
 #, c-format
 msgid "pthread_mutex_lock failed: %s"
 msgstr ""
 
-#: gold-threads.cc:99
+#: gold-threads.cc:105
 #, c-format
 msgid "pthread_mutex_unlock failed: %s"
 msgstr ""
 
-#: gold-threads.cc:180
+#: gold-threads.cc:193
 #, c-format
 msgid "pthread_cond_init failed: %s"
 msgstr ""
 
-#: gold-threads.cc:186
+#: gold-threads.cc:200
 #, c-format
 msgid "pthread_cond_destroy failed: %s"
 msgstr ""
 
-#: gold-threads.cc:193
+#: gold-threads.cc:208
 #, c-format
 msgid "pthread_cond_wait failed: %s"
 msgstr ""
 
-#: gold-threads.cc:200
+#: gold-threads.cc:216
 #, c-format
 msgid "pthread_cond_signal failed: %s"
 msgstr ""
 
+#: gold-threads.cc:224
+#, c-format
+msgid "pthread_cond_broadcast failed: %s"
+msgstr ""
+
 #. FIXME: This needs to specify the location somehow.
-#: i386.cc:153 i386.cc:1310 x86_64.cc:165 x86_64.cc:1254
+#: i386.cc:160 i386.cc:1439 x86_64.cc:172 x86_64.cc:1269
 msgid "missing expected TLS relocation"
 msgstr ""
 
-#: i386.cc:761 x86_64.cc:723 x86_64.cc:898
+#: i386.cc:779 x86_64.cc:732 x86_64.cc:910
 #, c-format
 msgid "%s: unsupported reloc %u against local symbol"
 msgstr ""
 
-#: i386.cc:862 i386.cc:1096 x86_64.cc:839 x86_64.cc:1079
+#: i386.cc:882 i386.cc:1169 x86_64.cc:851 x86_64.cc:1093
 #, c-format
 msgid "%s: unexpected reloc %u in object file"
 msgstr ""
 
-#: i386.cc:948 x86_64.cc:912 x86_64.cc:1138
+#: i386.cc:1018 x86_64.cc:924 x86_64.cc:1152
 #, c-format
 msgid "%s: unsupported reloc %u against global symbol %s"
 msgstr ""
 
-#: i386.cc:1193
+#: i386.cc:1322
 #, c-format
 msgid "%s: unsupported RELA reloc section"
 msgstr ""
 
-#: i386.cc:1449 x86_64.cc:1452
+#: i386.cc:1579 x86_64.cc:1467
 #, c-format
 msgid "unexpected reloc %u in object file"
 msgstr ""
 
-#: i386.cc:1481 i386.cc:1528 i386.cc:1535 i386.cc:1555 i386.cc:1584
-#: x86_64.cc:1473 x86_64.cc:1522 x86_64.cc:1533
+#: i386.cc:1611 i386.cc:1687 i386.cc:1694 i386.cc:1735 i386.cc:1791
+#: x86_64.cc:1488 x86_64.cc:1537 x86_64.cc:1548
 #, c-format
 msgid "unsupported reloc %u"
 msgstr ""
 
-#: i386.cc:1506 x86_64.cc:1498
-msgid "TLS reloc but no TLS segment"
-msgstr ""
-
-#: i386.cc:1543
+#: i386.cc:1702
 msgid "both SUN and GNU model TLS relocations"
 msgstr ""
 
@@ -368,550 +379,602 @@ msgstr ""
 msgid "entry in mergeable string section not null terminated"
 msgstr ""
 
-#: object.cc:51
+#: object.cc:53
 #, c-format
 msgid "%s: unsupported ELF machine number %d"
 msgstr ""
 
-#: object.cc:69 script.cc:1222
+#: object.cc:71 script.cc:1226
 #, c-format
 msgid "%s: %s"
 msgstr ""
 
-#: object.cc:104
+#: object.cc:106
 #, c-format
 msgid "section name section has wrong type: %u"
 msgstr ""
 
-#: object.cc:306
+#: object.cc:308
 #, c-format
 msgid "invalid symbol table name index: %u"
 msgstr ""
 
-#: object.cc:312
+#: object.cc:314
 #, c-format
 msgid "symbol table name section has wrong type: %u"
 msgstr ""
 
-#: object.cc:392
+#: object.cc:394
 #, c-format
 msgid "section group %u info %u out of range"
 msgstr ""
 
-#: object.cc:410
+#: object.cc:412
 #, c-format
 msgid "symbol %u name offset %u out of range"
 msgstr ""
 
-#: object.cc:442
+#: object.cc:444
 #, c-format
 msgid "section %u in section group %u out of range"
 msgstr ""
 
-#: object.cc:532 reloc.cc:202 reloc.cc:469
+#: object.cc:534 reloc.cc:226 reloc.cc:493
 #, c-format
 msgid "relocation section %u has bad info %u"
 msgstr ""
 
-#: object.cc:704
+#: object.cc:706
 msgid "size of symbols is not multiple of symbol size"
 msgstr ""
 
 #. FIXME: Handle SHN_XINDEX.
-#: object.cc:796
+#: object.cc:798
 #, c-format
 msgid "unknown section index %u for local symbol %u"
 msgstr ""
 
-#: object.cc:805
+#: object.cc:807
 #, c-format
 msgid "local symbol %u section index %u out of range"
 msgstr ""
 
-#: object.cc:837
+#: object.cc:839
 #, c-format
 msgid "local symbol %u section name out of range: %u >= %u"
 msgstr ""
 
-#: object.cc:1055
+#: object.cc:1070
 #, c-format
 msgid "%s: incompatible target"
 msgstr ""
 
-#: object.cc:1213
+#: object.cc:1226
 #, c-format
 msgid "%s: unsupported ELF file type %d"
 msgstr ""
 
-#: object.cc:1232 object.cc:1278 object.cc:1312
+#: object.cc:1245 object.cc:1291 object.cc:1325
 #, c-format
 msgid "%s: ELF file too short"
 msgstr ""
 
-#: object.cc:1240
+#: object.cc:1253
 #, c-format
 msgid "%s: invalid ELF version 0"
 msgstr ""
 
-#: object.cc:1242
+#: object.cc:1255
 #, c-format
 msgid "%s: unsupported ELF version %d"
 msgstr ""
 
-#: object.cc:1249
+#: object.cc:1262
 #, c-format
 msgid "%s: invalid ELF class 0"
 msgstr ""
 
-#: object.cc:1255
+#: object.cc:1268
 #, c-format
 msgid "%s: unsupported ELF class %d"
 msgstr ""
 
-#: object.cc:1262
+#: object.cc:1275
 #, c-format
 msgid "%s: invalid ELF data encoding"
 msgstr ""
 
-#: object.cc:1268
+#: object.cc:1281
 #, c-format
 msgid "%s: unsupported ELF data encoding %d"
 msgstr ""
 
-#: object.cc:1288
+#: object.cc:1301
 #, c-format
 msgid "%s: not configured to support 32-bit big-endian object"
 msgstr ""
 
-#: object.cc:1301
+#: object.cc:1314
 #, c-format
 msgid "%s: not configured to support 32-bit little-endian object"
 msgstr ""
 
-#: object.cc:1322
+#: object.cc:1335
 #, c-format
 msgid "%s: not configured to support 64-bit big-endian object"
 msgstr ""
 
-#: object.cc:1335
+#: object.cc:1348
 #, c-format
 msgid "%s: not configured to support 64-bit little-endian object"
 msgstr ""
 
-#: options.cc:142
+#: options.cc:157
 #, c-format
 msgid "%s: unable to parse script file %s\n"
 msgstr ""
 
-#: options.cc:170
+#: options.cc:185
 #, c-format
 msgid ""
 "Usage: %s [options] file...\n"
 "Options:\n"
 msgstr ""
 
-#: options.cc:341
+#: options.cc:356
+msgid "Allow unresolved references in shared libraries"
+msgstr ""
+
+#: options.cc:360
+msgid "Do not allow unresolved references in shared libraries"
+msgstr ""
+
+#: options.cc:364
 msgid "Only set DT_NEEDED for dynamic libs if used"
 msgstr ""
 
-#: options.cc:344
+#: options.cc:367
 msgid "Always DT_NEEDED for dynamic libs (default)"
 msgstr ""
 
-#: options.cc:347
+#: options.cc:370
 msgid "-l searches for shared libraries"
 msgstr ""
 
-#: options.cc:351
+#: options.cc:374
 msgid "-l does not search for shared libraries"
 msgstr ""
 
-#: options.cc:354
+#: options.cc:377
 msgid "Bind defined symbols locally"
 msgstr ""
 
-#: options.cc:356
+#: options.cc:379
+msgid "Demangle C++ symbols in log messages"
+msgstr ""
+
+#: options.cc:382
+msgid "Do not demangle C++ symbols in log messages"
+msgstr ""
+
+#: options.cc:385
+msgid "Try to detect violations of the One Definition Rule"
+msgstr ""
+
+#: options.cc:387
 msgid "Export all dynamic symbols"
 msgstr ""
 
-#: options.cc:358
+#: options.cc:389
 msgid "Create exception frame header"
 msgstr ""
 
-#: options.cc:360
+#: options.cc:391
 msgid "Set dynamic linker path"
 msgstr ""
 
-#: options.cc:361
+#: options.cc:392
 msgid "-I PROGRAM, --dynamic-linker PROGRAM"
 msgstr ""
 
-#: options.cc:363
+#: options.cc:394
 msgid "Search for library LIBNAME"
 msgstr ""
 
-#: options.cc:364
+#: options.cc:395
 msgid "-lLIBNAME, --library LIBNAME"
 msgstr ""
 
-#: options.cc:366
+#: options.cc:397
 msgid "Add directory to search path"
 msgstr ""
 
-#: options.cc:367
+#: options.cc:398
 msgid "-L DIR, --library-path DIR"
 msgstr ""
 
-#: options.cc:369
+#: options.cc:400
 msgid "Ignored for compatibility"
 msgstr ""
 
-#: options.cc:371
+#: options.cc:402
 msgid "Set output file name"
 msgstr ""
 
-#: options.cc:372
+#: options.cc:403
 msgid "-o FILE, --output FILE"
 msgstr ""
 
-#: options.cc:374
+#: options.cc:405
 msgid "Optimize output file size"
 msgstr ""
 
-#: options.cc:375
+#: options.cc:406
 msgid "-O level"
 msgstr ""
 
-#: options.cc:377
+#: options.cc:408
 msgid "Generate relocatable output"
 msgstr ""
 
-#: options.cc:379
+#: options.cc:410
 msgid "Add DIR to runtime search path"
 msgstr ""
 
-#: options.cc:380
+#: options.cc:411
 msgid "-R DIR, -rpath DIR"
 msgstr ""
 
-#: options.cc:383
+#: options.cc:414
 msgid "Add DIR to link time shared library search path"
 msgstr ""
 
-#: options.cc:384
+#: options.cc:415
 msgid "--rpath-link DIR"
 msgstr ""
 
-#: options.cc:386
+#: options.cc:417
 msgid "Strip all symbols"
 msgstr ""
 
-#: options.cc:388
+#: options.cc:420
+msgid "Strip debug symbols that are unused by gdb (at least versions <= 6.7)"
+msgstr ""
+
+#. This must come after -Sdebug since it's a prefix of it.
+#: options.cc:424
 msgid "Strip debugging information"
 msgstr ""
 
-#: options.cc:390
+#: options.cc:426
 msgid "Generate shared library"
 msgstr ""
 
-#: options.cc:392
+#: options.cc:428
 msgid "Do not link against shared libraries"
 msgstr ""
 
-#: options.cc:394
+#: options.cc:430
 msgid "Print resource usage statistics"
 msgstr ""
 
-#: options.cc:396
+#: options.cc:432
 msgid "Set target system root directory"
 msgstr ""
 
-#: options.cc:397
+#: options.cc:433
 msgid "--sysroot DIR"
 msgstr ""
 
-#: options.cc:398
+#: options.cc:434
 msgid "Set the address of the .text section"
 msgstr ""
 
-#: options.cc:399
+#: options.cc:435
 msgid "-Ttext ADDRESS"
 msgstr ""
 
 #. This must come after -Ttext since it's a prefix of it.
-#: options.cc:402
+#: options.cc:438
 msgid "Read linker script"
 msgstr ""
 
-#: options.cc:403
+#: options.cc:439
 msgid "-T FILE, --script FILE"
 msgstr ""
 
-#: options.cc:405
+#: options.cc:441
 msgid "Run the linker multi-threaded"
 msgstr ""
 
-#: options.cc:407
+#: options.cc:443
 msgid "Do not run the linker multi-threaded"
 msgstr ""
 
-#: options.cc:409
+#: options.cc:445
 msgid "Number of threads to use"
 msgstr ""
 
-#: options.cc:410
+#: options.cc:446
 msgid "--thread-count COUNT"
 msgstr ""
 
-#: options.cc:413
+#: options.cc:449
 msgid "Number of threads to use in initial pass"
 msgstr ""
 
-#: options.cc:414
+#: options.cc:450
 msgid "--thread-count-initial COUNT"
 msgstr ""
 
-#: options.cc:417
+#: options.cc:453
 msgid "Number of threads to use in middle pass"
 msgstr ""
 
-#: options.cc:418
+#: options.cc:454
 msgid "--thread-count-middle COUNT"
 msgstr ""
 
-#: options.cc:421
+#: options.cc:457
 msgid "Number of threads to use in final pass"
 msgstr ""
 
-#: options.cc:422
+#: options.cc:458
 msgid "--thread-count-final COUNT"
 msgstr ""
 
-#: options.cc:425
+#: options.cc:461
 msgid "Include all archive contents"
 msgstr ""
 
-#: options.cc:429
+#: options.cc:465
 msgid "Include only needed archive contents"
 msgstr ""
 
-#: options.cc:434
+#: options.cc:470
 msgid ""
 "Subcommands as follows:\n"
 "    -z execstack              Mark output as requiring executable stack\n"
 "    -z noexecstack            Mark output as not requiring executable stack"
 msgstr ""
 
-#: options.cc:437
+#: options.cc:473
 msgid "-z SUBCOMMAND"
 msgstr ""
 
-#: options.cc:440
+#: options.cc:476
 msgid "Start a library search group"
 msgstr ""
 
-#: options.cc:442
+#: options.cc:478
 msgid "End a library search group"
 msgstr ""
 
-#: options.cc:444
+#: options.cc:480
 msgid "Report usage information"
 msgstr ""
 
-#: options.cc:446
+#: options.cc:482
 msgid "Report version information"
 msgstr ""
 
-#: options.cc:518
+#: options.cc:484
+msgid "Turn on debugging (all,task)"
+msgstr ""
+
+#: options.cc:485
+msgid "--debug=TYPE"
+msgstr ""
+
+#: options.cc:578
 #, c-format
 msgid "%s: unrecognized -z subcommand: %s\n"
 msgstr ""
 
-#: options.cc:698
+#: options.cc:601
+#, c-format
+msgid "%s: unrecognized --debug subcommand: %s\n"
+msgstr ""
+
+#: options.cc:781
 msgid "unexpected argument"
 msgstr ""
 
-#: options.cc:705 options.cc:757 options.cc:838
+#: options.cc:788 options.cc:840 options.cc:921
 msgid "missing argument"
 msgstr ""
 
-#: options.cc:718 options.cc:766
+#: options.cc:801 options.cc:849
 msgid "unknown option"
 msgstr ""
 
-#: options.cc:784
+#: options.cc:867
 #, c-format
 msgid "%s: missing group end\n"
 msgstr ""
 
-#: options.cc:912
+#: options.cc:995
 msgid "may not nest groups"
 msgstr ""
 
-#: options.cc:922
+#: options.cc:1005
 msgid "group end without group start"
 msgstr ""
 
-#: options.cc:932
+#: options.cc:1015
 #, c-format
 msgid "%s: use the --help option for usage information\n"
 msgstr ""
 
-#: options.cc:941
+#: options.cc:1024
 #, c-format
 msgid "%s: %s: %s\n"
 msgstr ""
 
-#: options.cc:950
+#: options.cc:1033
 #, c-format
 msgid "%s: -%c: %s\n"
 msgstr ""
 
-#: options.h:338
+#: options.h:393
 #, c-format
 msgid "%s: invalid argument to -Ttext: %s\n"
 msgstr ""
 
-#: options.h:351
+#: options.h:406
 #, c-format
 msgid "%s: invalid thread count: %s\n"
 msgstr ""
 
-#: output.cc:1061
+#: output.cc:1108
 #, c-format
 msgid "invalid alignment %lu for section \"%s\""
 msgstr ""
 
-#: output.cc:1787
+#: output.cc:1870
 #, c-format
 msgid "%s: open: %s"
 msgstr ""
 
-#: output.cc:1792
+#: output.cc:1875
 #, c-format
 msgid "%s: lseek: %s"
 msgstr ""
 
-#: output.cc:1795
+#: output.cc:1878
 #, c-format
 msgid "%s: write: %s"
 msgstr ""
 
-#: output.cc:1801
+#: output.cc:1884
 #, c-format
 msgid "%s: mmap: %s"
 msgstr ""
 
-#: output.cc:1811
+#: output.cc:1894
 #, c-format
 msgid "%s: munmap: %s"
 msgstr ""
 
-#: output.cc:1815
+#: output.cc:1898
 #, c-format
 msgid "%s: close: %s"
 msgstr ""
 
-#: readsyms.cc:147
+#: readsyms.cc:151
 #, c-format
 msgid "%s: file is empty"
 msgstr ""
 
-#: readsyms.cc:182
+#: readsyms.cc:186
 #, c-format
 msgid "%s: ordinary object found in input group"
 msgstr ""
 
 #. Here we have to handle any other input file types we need.
-#: readsyms.cc:230
+#: readsyms.cc:234
 #, c-format
 msgid "%s: not an object or archive"
 msgstr ""
 
-#: reloc.cc:221 reloc.cc:487
+#: reloc.cc:245 reloc.cc:511
 #, c-format
 msgid "relocation section %u uses unexpected symbol table %u"
 msgstr ""
 
-#: reloc.cc:236 reloc.cc:505
+#: reloc.cc:260 reloc.cc:529
 #, c-format
 msgid "unexpected entsize for reloc section %u: %lu != %u"
 msgstr ""
 
-#: reloc.cc:245 reloc.cc:514
+#: reloc.cc:269 reloc.cc:538
 #, c-format
 msgid "reloc section %u size %lu uneven"
 msgstr ""
 
-#: reloc.cc:702
+#: reloc.cc:729
 #, c-format
 msgid "reloc section size %zu is not a multiple of reloc size %d\n"
 msgstr ""
 
-#: resolve.cc:165
-#, c-format
-msgid "%s: invalid STB_LOCAL symbol %s in external symbols"
+#. We should only see externally visible symbols in the symbol
+#. table.
+#: resolve.cc:144
+msgid "invalid STB_LOCAL symbol in external symbols"
 msgstr ""
 
-#: resolve.cc:171
-#, c-format
-msgid "%s: unsupported symbol binding %d for symbol %s"
+#. Any target which wants to handle STB_LOOS, etc., needs to
+#. define a resolve method.
+#: resolve.cc:150
+msgid "unsupported symbol binding"
 msgstr ""
 
 #. Two definitions of the same symbol.
 #. FIXME: Do a better job of reporting locations.
-#: resolve.cc:310
+#: resolve.cc:318
 #, c-format
 msgid "%s: multiple definition of %s"
 msgstr ""
 
-#: resolve.cc:311 resolve.cc:316
+#: resolve.cc:319 resolve.cc:324
 msgid "command line"
 msgstr ""
 
-#: resolve.cc:313
+#: resolve.cc:321
 #, c-format
 msgid "%s: previous definition here"
 msgstr ""
 
 #. There are some options that we could handle here--e.g.,
 #. -lLIBRARY.  Should we bother?
-#: script.cc:1326
+#: script.cc:1330
 #, c-format
 msgid ""
 "%s: Ignoring command OPTION; OPTION is only valid for scripts specified via -"
 "T"
 msgstr ""
 
-#: symtab.cc:541
+#: symtab.cc:576
 #, c-format
 msgid "bad global symbol name offset %u at %zu"
 msgstr ""
 
-#: symtab.cc:619
+#: symtab.cc:654
 msgid "too few symbol versions"
 msgstr ""
 
-#: symtab.cc:648
+#: symtab.cc:683
 #, c-format
 msgid "bad symbol name offset %u at %zu"
 msgstr ""
 
-#: symtab.cc:702
+#: symtab.cc:737
 #, c-format
 msgid "versym for symbol %zu out of range: %u"
 msgstr ""
 
-#: symtab.cc:710
+#: symtab.cc:745
 #, c-format
 msgid "versym for symbol %zu has no name: %u"
 msgstr ""
 
-#: symtab.cc:1428 symtab.cc:1631
+#: symtab.cc:1463 symtab.cc:1676
 #, c-format
 msgid "%s: unsupported symbol section 0x%x"
 msgstr ""
 
+#: symtab.cc:1800
+#, c-format
+msgid "%s: undefined reference to '%s'"
+msgstr ""
+
+#: symtab.cc:1941
+#, c-format
+msgid ""
+"while linking %s: symbol '%s' defined in multiple places (possible ODR "
+"violation):"
+msgstr ""
+
 #: target-reloc.h:211
 #, c-format
 msgid "reloc has bad offset %zu"
@@ -940,12 +1003,21 @@ msgid ""
 "This program has absolutely no warranty.\n"
 msgstr ""
 
-#: x86_64.cc:1162
+#: workqueue-threads.cc:106
+#, c-format
+msgid "%s failed: %s"
+msgstr ""
+
+#: x86_64.cc:1177
 #, c-format
 msgid "%s: unsupported REL reloc section"
 msgstr ""
 
-#: x86_64.cc:1561
+#: x86_64.cc:1513
+msgid "TLS reloc but no TLS segment"
+msgstr ""
+
+#: x86_64.cc:1576
 #, c-format
 msgid "unsupported reloc type %u"
 msgstr ""
index 39d33767033b7a0789d552d9d7fecc5e6de2a80d..5625f59f0e6a3991f154ceae299abe0596170cf6 100644 (file)
@@ -72,6 +72,10 @@ class Unblock_token : public Task
   run(Workqueue*)
   { }
 
+  std::string
+  get_name() const
+  { return "Unblock_token"; }
+
  private:
   Task_token* this_blocker_;
   Task_token* next_blocker_;
@@ -273,6 +277,35 @@ Read_symbols::do_group(Workqueue* workqueue)
                                    this->next_blocker_));
 }
 
+// Return a debugging name for a Read_symbols task.
+
+std::string
+Read_symbols::get_name() const
+{
+  if (!this->input_argument_->is_group())
+    {
+      std::string ret("Read_symbols ");
+      if (this->input_argument_->file().is_lib())
+       ret += "-l";
+      ret += this->input_argument_->file().name();
+      return ret;
+    }
+
+  std::string ret("Read_symbols group (");
+  bool add_space = false;
+  const Input_file_group* group = this->input_argument_->group();
+  for (Input_file_group::const_iterator p = group->begin();
+       p != group->end();
+       ++p)
+    {
+      if (add_space)
+       ret += ' ';
+      ret += p->file().name();
+      add_space = true;
+    }
+  return ret + ')';
+}
+
 // Class Add_symbols.
 
 Add_symbols::~Add_symbols()
index d88446309dc208f2c046b495158b4f54479e96ae..c02a0ee4672952f140a14bfe08c84614ad0c8944 100644 (file)
@@ -77,6 +77,9 @@ class Read_symbols : public Task
   void
   run(Workqueue*);
 
+  std::string
+  get_name() const;
+
  private:
   // Handle an archive group.
   void
@@ -129,6 +132,10 @@ class Add_symbols : public Task
   void
   run(Workqueue*);
 
+  std::string
+  get_name() const
+  { return "Add_symbols " + this->object_->name(); }
+
 private:
   class Add_symbols_locker;
 
@@ -201,6 +208,10 @@ class Finish_group : public Task
   void
   run(Workqueue*);
 
+  std::string
+  get_name() const
+  { return "Finish_group"; }
+
  private:
   Input_objects* input_objects_;
   Symbol_table* symtab_;
index ab74498d244f2d6e3198cecb61c1fc70ad8c9e80..d50674f6d77159349b2f6c23038d80cd137802f8 100644 (file)
@@ -63,6 +63,14 @@ Read_relocs::run(Workqueue* workqueue)
                                         this->symtab_lock_, this->blocker_));
 }
 
+// Return a debugging name for the task.
+
+std::string
+Read_relocs::get_name() const
+{
+  return "Read_relocs " + this->object_->name();
+}
+
 // Scan_relocs methods.
 
 // These tasks scan the relocations read by Read_relocs and mark up
@@ -114,6 +122,14 @@ Scan_relocs::run(Workqueue*)
   this->rd_ = NULL;
 }
 
+// Return a debugging name for the task.
+
+std::string
+Scan_relocs::get_name() const
+{
+  return "Scan_relocs " + this->object_->name();
+}
+
 // Relocate_task methods.
 
 // We may have to wait for the output sections to be written.
@@ -125,6 +141,9 @@ Relocate_task::is_runnable(Workqueue*)
       && this->output_sections_blocker_->is_blocked())
     return IS_BLOCKED;
 
+  if (this->object_->is_locked())
+    return IS_LOCKED;
+
   return IS_RUNNABLE;
 }
 
@@ -166,6 +185,14 @@ Relocate_task::run(Workqueue*)
                          this->of_);
 }
 
+// Return a debugging name for the task.
+
+std::string
+Relocate_task::get_name() const
+{
+  return "Relocate_task " + this->object_->name();
+}
+
 // Read the relocs and local symbols from the object file and store
 // the information in RD.
 
index 2ff49d84bf0cc6c69f5bdbb26249c859a91ac8e5..d84dc88828b35ff69a1be6633b5dc5f41ede8611 100644 (file)
@@ -78,6 +78,9 @@ class Read_relocs : public Task
   void
   run(Workqueue*);
 
+  std::string
+  get_name() const;
+
  private:
   const General_options& options_;
   Symbol_table* symtab_;
@@ -113,6 +116,9 @@ class Scan_relocs : public Task
   void
   run(Workqueue*);
 
+  std::string
+  get_name() const;
+
  private:
   class Scan_relocs_locker;
 
@@ -151,6 +157,9 @@ class Relocate_task : public Task
   void
   run(Workqueue*);
 
+  std::string
+  get_name() const;
+
  private:
   class Relocate_locker;
 
index 83e490c2fcb2572b5f86a0326d1a519380761abd..1ebd100b932714aa599da76fd55681f87c77031e 100644 (file)
@@ -815,6 +815,10 @@ class Script_unblock : public Task
   run(Workqueue*)
   { }
 
+  std::string
+  get_name() const
+  { return "Script_unblock"; }
+
  private:
   Task_token* this_blocker_;
   Task_token* next_blocker_;
index f0c09f9924dba4f204ab5f27990415dcb89bc19c..b2901ab9faa617eb8b231b10e4485d0fd05ebdf8 100644 (file)
@@ -159,6 +159,17 @@ Symbol::init_base(const char* name, elfcpp::STT type,
   this->in_reg_ = true;
 }
 
+// Allocate a common symbol in the base.
+
+void
+Symbol::allocate_base_common(Output_data* od)
+{
+  gold_assert(this->is_common());
+  this->source_ = IN_OUTPUT_DATA;
+  this->u_.in_output_data.output_data = od;
+  this->u_.in_output_data.offset_is_from_end = false;
+}
+
 // Initialize the fields in Sized_symbol for SYM in OBJECT.
 
 template<int size>
@@ -219,6 +230,16 @@ Sized_symbol<size>::init(const char* name, Value_type value, Size_type symsize,
   this->symsize_ = symsize;
 }
 
+// Allocate a common symbol.
+
+template<int size>
+void
+Sized_symbol<size>::allocate_common(Output_data* od, Value_type value)
+{
+  this->allocate_base_common(od);
+  this->value_ = value;
+}
+
 // Return true if this symbol should be added to the dynamic symbol
 // table.
 
@@ -2017,6 +2038,18 @@ Warnings::issue_warning(const Symbol* sym,
 // script to restrict this to only the ones needed for implemented
 // targets.
 
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+template
+void
+Sized_symbol<32>::allocate_common(Output_data*, Value_type);
+#endif
+
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+template
+void
+Sized_symbol<64>::allocate_common(Output_data*, Value_type);
+#endif
+
 #ifdef HAVE_TARGET_32_LITTLE
 template
 void
index b6e550463ee0551e9d011141508997d168ebd70d..9c7fb0935c747bb921a68a25eb0dcfd8bfd65036 100644 (file)
@@ -598,6 +598,11 @@ class Symbol
   void
   override_base_with_special(const Symbol* from);
 
+  // Allocate a common symbol by giving it a location in the output
+  // file.
+  void
+  allocate_base_common(Output_data*);
+
  private:
   Symbol(const Symbol&);
   Symbol& operator=(const Symbol&);
@@ -798,6 +803,11 @@ class Sized_symbol : public Symbol
   set_value(Value_type value)
   { this->value_ = value; }
 
+  // Allocate a common symbol by giving it a location in the output
+  // file.
+  void
+  allocate_common(Output_data*, Value_type value);
+
  private:
   Sized_symbol(const Sized_symbol&);
   Sized_symbol& operator=(const Sized_symbol&);
diff --git a/gold/workqueue-internal.h b/gold/workqueue-internal.h
new file mode 100644 (file)
index 0000000..d9fd160
--- /dev/null
@@ -0,0 +1,129 @@
+// workqueue-internal.h -- internal work queue header for gold   -*- C++ -*-
+
+// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#ifndef GOLD_WORKQUEUE_INTERNAL_H
+#define GOLD_WORKQUEUE_INTERNAL_H
+
+#include <queue>
+
+#include "gold-threads.h"
+#include "workqueue.h"
+
+// This is an internal header file for different gold workqueue
+// implementations.
+
+namespace gold
+{
+
+class Workqueue_thread;
+
+// The Workqueue_runner abstract class.  This is the interface used by
+// the general workqueue code to actually run a task.
+
+class Workqueue_runner
+{
+ public:
+  Workqueue_runner(Workqueue* workqueue)
+    : workqueue_(workqueue)
+  { }
+  virtual ~Workqueue_runner()
+  { }
+
+  // Run a task.  This is always called in the main thread.
+  virtual void
+  run(Task*, Task_locker*) = 0;
+
+  // Set the number of threads to use.  This is ignored when not using
+  // threads.
+  virtual void
+  set_thread_count(int) = 0;
+
+ protected:
+  // This is called by an implementation when a task is completed.
+  void completed(Task* t, Task_locker* tl)
+  { this->workqueue_->completed(t, tl); }
+
+  Workqueue* get_workqueue() const
+  { return this->workqueue_; }
+
+ private:
+  Workqueue* workqueue_;
+};
+
+// The threaded instantiation of Workqueue_runner.
+
+class Workqueue_runner_threadpool : public Workqueue_runner
+{
+ public:
+  Workqueue_runner_threadpool(Workqueue* workqueue);
+
+  ~Workqueue_runner_threadpool();
+
+  void
+  run(Task*, Task_locker*);
+
+  void
+  set_thread_count(int);
+
+ private:
+  // This class can not be copied.
+  Workqueue_runner_threadpool(const Workqueue_runner_threadpool&);
+  Workqueue_runner_threadpool& operator=(const Workqueue_runner_threadpool&);
+
+  // Return the next Task and Task_locker to run.  This returns false
+  // if the calling thread should simply exit.
+  bool
+  get_next(Task**, Task_locker**);
+
+  // This is called when the thread completes a task.
+  void
+  thread_completed(Task*, Task_locker*);
+
+  // The Workqueue_thread class calls functions from this and from the
+  // parent Workqueue_runner.
+  friend class Workqueue_thread;
+
+  // An entry on the queue of tasks to run.
+  typedef std::pair<Task*, Task_locker*> Task_queue_entry;
+
+  // A queue of tasks to run.
+  typedef std::queue<Task_queue_entry> Task_queue;
+
+  // The number of threads we want to create.  This is only changed in
+  // the main thread or when only one thread is running.  This is set
+  // to zero when all threads should exit.
+  int desired_thread_count_;
+  // A lock controlling access to the remaining fields.
+  Lock lock_;
+  // The number of threads we have created.
+  int actual_thread_count_;
+  // The number of threads which are running a task.
+  int running_thread_count_;
+  // A queue of tasks to run.
+  Task_queue task_queue_;
+  // A condition variable which signals when the task_queue_ changed.
+  Condvar task_queue_condvar_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_WORKQUEUE_INTERNAL_H)
diff --git a/gold/workqueue-threads.cc b/gold/workqueue-threads.cc
new file mode 100644 (file)
index 0000000..a4f347d
--- /dev/null
@@ -0,0 +1,266 @@
+// workqueue-threads.cc -- the threaded workqueue for gold
+
+// Copyright 2007 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+// This file holds the workqueue implementation which may be used when
+// using threads.
+
+#include "gold.h"
+
+#ifdef ENABLE_THREADS
+
+#include <cstring>
+#include <pthread.h>
+
+#include "debug.h"
+#include "gold-threads.h"
+#include "workqueue.h"
+#include "workqueue-internal.h"
+
+namespace gold
+{
+
+// Class Workqueue_thread represents a single thread.  Creating an
+// instance of this spawns a new thread.
+
+class Workqueue_thread
+{
+ public:
+  Workqueue_thread(Workqueue_runner_threadpool*);
+
+  ~Workqueue_thread();
+
+ private:
+  // This class can not be copied.
+  Workqueue_thread(const Workqueue_thread&);
+  Workqueue_thread& operator=(const Workqueue_thread&);
+
+  // Check for error from a pthread function.
+  void
+  check(const char* function, int err) const;
+
+  // A function to pass to pthread_create.  This is called with a
+  // pointer to an instance of this object.
+  static void*
+  thread_body(void*);
+
+  // The main loop of the thread.
+  void
+  run();
+
+  // A pointer to the threadpool that this thread is part of.
+  Workqueue_runner_threadpool* threadpool_;
+  // The thread ID.
+  pthread_t tid_;
+};
+
+// Create the thread in the constructor.
+
+Workqueue_thread::Workqueue_thread(Workqueue_runner_threadpool* threadpool)
+  : threadpool_(threadpool)
+{
+  pthread_attr_t attr;
+  int err = pthread_attr_init(&attr);
+  this->check("pthread_attr_init", err);
+
+  err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+  this->check("pthread_attr_setdetachstate", err);
+
+  err = pthread_create(&this->tid_, &attr, &Workqueue_thread::thread_body,
+                      reinterpret_cast<void*>(this));
+  this->check("pthread_create", err);
+
+  err = pthread_attr_destroy(&attr);
+  this->check("pthread_attr_destroy", err);
+}
+
+// The destructor will be called when the thread is exiting.
+
+Workqueue_thread::~Workqueue_thread()
+{
+}
+
+// Check for an error.
+
+void
+Workqueue_thread::check(const char* function, int err) const
+{
+  if (err != 0)
+    gold_fatal(_("%s failed: %s"), function, strerror(err));
+}
+
+// Passed to pthread_create.
+
+extern "C"
+void*
+Workqueue_thread::thread_body(void* arg)
+{
+  Workqueue_thread* pwt = reinterpret_cast<Workqueue_thread*>(arg);
+  pwt->run();
+
+  // Delete the thread object as we exit.
+  delete pwt;
+
+  return NULL;
+}
+
+// This is the main loop of a worker thread.  It picks up a new Task
+// and runs it.
+
+void
+Workqueue_thread::run()
+{
+  Workqueue_runner_threadpool* threadpool = this->threadpool_;
+  Workqueue* workqueue = threadpool->get_workqueue();
+
+  while (true)
+    {
+      Task* t;
+      Task_locker* tl;
+      if (!threadpool->get_next(&t, &tl))
+       return;
+
+      gold_debug(DEBUG_TASK, "running   task %s", t->name().c_str());
+
+      t->run(workqueue);
+      threadpool->thread_completed(t, tl);
+    }
+}
+
+// Class Workqueue_runner_threadpool.
+
+// Constructor.
+
+Workqueue_runner_threadpool::Workqueue_runner_threadpool(Workqueue* workqueue)
+  : Workqueue_runner(workqueue),
+    desired_thread_count_(0),
+    lock_(),
+    actual_thread_count_(0),
+    running_thread_count_(0),
+    task_queue_(),
+    task_queue_condvar_(this->lock_)
+{
+}
+
+// Destructor.
+
+Workqueue_runner_threadpool::~Workqueue_runner_threadpool()
+{
+  // Tell the threads to exit.
+  Hold_lock hl(this->lock_);
+  this->desired_thread_count_ = 0;
+  this->task_queue_condvar_.broadcast();
+}
+
+// Run a task.  This doesn't actually run the task: it pushes on the
+// queue of tasks to run.  This is always called in the main thread.
+
+void
+Workqueue_runner_threadpool::run(Task* t, Task_locker* tl)
+{
+  Hold_lock hl(this->lock_);
+
+  // This is where we create threads as needed, subject to the limit
+  // of the desired thread count.
+  gold_assert(this->desired_thread_count_ > 0);
+  gold_assert(this->actual_thread_count_ >= this->running_thread_count_);
+  if (this->actual_thread_count_ == this->running_thread_count_
+      && this->actual_thread_count_ < this->desired_thread_count_)
+    {
+      // Note that threads delete themselves when they exit, so we
+      // don't keep pointers to them.
+      new Workqueue_thread(this);
+      ++this->actual_thread_count_;
+    }
+
+  this->task_queue_.push(std::make_pair(t, tl));
+  this->task_queue_condvar_.signal();
+}
+
+// Set the thread count.  This is only called in the main thread, and
+// is only called when there are no threads running.
+
+void
+Workqueue_runner_threadpool::set_thread_count(int thread_count)
+{
+  gold_assert(this->running_thread_count_ <= 1);
+  gold_assert(thread_count > 0);
+  this->desired_thread_count_ = thread_count;
+}
+
+// Get the next task to run.  This is always called by an instance of
+// Workqueue_thread, and is never called in the main thread.  It
+// returns false if the calling thread should exit.
+
+bool
+Workqueue_runner_threadpool::get_next(Task** pt, Task_locker** ptl)
+{
+  Hold_lock hl(this->lock_);
+
+  // This is where we destroy threads, by telling them to exit.
+  gold_assert(this->actual_thread_count_ > this->running_thread_count_);
+  if (this->actual_thread_count_ > this->desired_thread_count_)
+    {
+      --this->actual_thread_count_;
+      return false;
+    }
+
+  while (this->task_queue_.empty() && this->desired_thread_count_ > 0)
+    {
+      // Wait for a new task to become available.
+      this->task_queue_condvar_.wait();
+    }
+
+  // Check whether we are exiting.
+  if (this->desired_thread_count_ == 0)
+    {
+      gold_assert(this->actual_thread_count_ > 0);
+      --this->actual_thread_count_;
+      return false;
+    }
+
+  *pt = this->task_queue_.front().first;
+  *ptl = this->task_queue_.front().second;
+  this->task_queue_.pop();
+
+  ++this->running_thread_count_;
+
+  return true;
+}
+
+// This is called when a thread completes its task.
+
+void
+Workqueue_runner_threadpool::thread_completed(Task* t, Task_locker* tl)
+{
+  {
+    Hold_lock hl(this->lock_);
+    gold_assert(this->actual_thread_count_ > 0);
+    gold_assert(this->running_thread_count_ > 0);
+    --this->running_thread_count_;
+  }
+
+  this->completed(t, tl);
+}
+
+} // End namespace gold.
+
+#endif // defined(ENABLE_THREADS)
index 95c14ce5a8594dd970fa35054f872c1dfb3bef4a..018c96bdbd299d17fd7f41e6180a993ce3a0dd19 100644 (file)
 
 #include "gold.h"
 
-#ifdef ENABLE_THREADS
-#include <pthread.h>
-#endif
-
+#include "debug.h"
 #include "workqueue.h"
+#include "workqueue-internal.h"
 
 namespace gold
 {
@@ -145,38 +143,6 @@ Task_block_token::~Task_block_token()
     }
 }
 
-// The Workqueue_runner abstract class.
-
-class Workqueue_runner
-{
- public:
-  Workqueue_runner(Workqueue* workqueue)
-    : workqueue_(workqueue)
-  { }
-  virtual ~Workqueue_runner()
-  { }
-
-  // Run a task.  This is always called in the main thread.
-  virtual void
-  run(Task*, Task_locker*) = 0;
-
-  // Set the number of threads to use.  This is ignored when not using
-  // threads.
-  virtual void
-  set_thread_count(int) = 0;
-
- protected:
-  // This is called by an implementation when a task is completed.
-  void completed(Task* t, Task_locker* tl)
-  { this->workqueue_->completed(t, tl); }
-
-  Workqueue* get_workqueue() const
-  { return this->workqueue_; }
-
- private:
-  Workqueue* workqueue_;
-};
-
 // The simple single-threaded implementation of Workqueue_runner.
 
 class Workqueue_runner_single : public Workqueue_runner
@@ -212,12 +178,15 @@ Workqueue_runner_single::set_thread_count(int thread_count)
 
 Workqueue::Workqueue(const General_options& options)
   : tasks_lock_(),
+    first_tasks_(),
     tasks_(),
     completed_lock_(),
     completed_(),
     running_(0),
+    queued_(0),
     completed_condvar_(this->completed_lock_),
-    cleared_blockers_(0)
+    cleared_blockers_(0),
+    desired_thread_count_(1)
 {
   bool threads = options.threads();
 #ifndef ENABLE_THREADS
@@ -226,11 +195,18 @@ Workqueue::Workqueue(const General_options& options)
   if (!threads)
     this->runner_ = new Workqueue_runner_single(this);
   else
-    gold_unreachable();
+    {
+#ifdef ENABLE_THREADS
+      this->runner_ = new Workqueue_runner_threadpool(this);
+#else
+      gold_unreachable();
+#endif
+    }
 }
 
 Workqueue::~Workqueue()
 {
+  gold_assert(this->first_tasks_.empty());
   gold_assert(this->tasks_.empty());
   gold_assert(this->completed_.empty());
   gold_assert(this->running_ == 0);
@@ -241,8 +217,14 @@ Workqueue::~Workqueue()
 void
 Workqueue::queue(Task* t)
 {
-  Hold_lock hl(this->tasks_lock_);
-  this->tasks_.push_back(t);
+  {
+    Hold_lock hl(this->tasks_lock_);
+    this->tasks_.push_back(t);
+  }
+  {
+    Hold_lock hl(this->completed_lock_);
+    ++this->queued_;
+  }
 }
 
 // Add a task to the front of the queue.
@@ -250,8 +232,14 @@ Workqueue::queue(Task* t)
 void
 Workqueue::queue_front(Task* t)
 {
-  Hold_lock hl(this->tasks_lock_);
-  this->tasks_.push_front(t);
+  {
+    Hold_lock hl(this->tasks_lock_);
+    this->first_tasks_.push_front(t);
+  }
+  {
+    Hold_lock hl(this->completed_lock_);
+    ++this->queued_;
+  }
 }
 
 // Clear the list of completed tasks.  Return whether we cleared
@@ -277,48 +265,36 @@ Workqueue::clear_completed()
 // a blocker.
 
 Task*
-Workqueue::find_runnable(Task_list& tasks, bool* all_blocked)
+Workqueue::find_runnable(Task_list* tasks, bool* all_blocked)
 {
-  Task* tlast = tasks.back();
+  Task* tlast = tasks->back();
   *all_blocked = true;
-  while (true)
+  Task* t;
+  do
     {
-      Task* t = tasks.front();
-      tasks.pop_front();
+      t = tasks->front();
+      tasks->pop_front();
 
       Task::Is_runnable_type is_runnable = t->is_runnable(this);
       if (is_runnable == Task::IS_RUNNABLE)
-       return t;
-
-      if (is_runnable != Task::IS_BLOCKED)
-       *all_blocked = false;
-
-      tasks.push_back(t);
-
-      if (t == tlast)
        {
-         // We couldn't find any runnable task.  If there are any
-         // completed tasks, free their locks and try again.
-
          {
-           Hold_lock hl2(this->completed_lock_);
-
-           if (!this->clear_completed())
-             {
-               // There had better be some tasks running, or we will
-               // never find a runnable task.
-               gold_assert(this->running_ > 0);
-
-               // We couldn't find any runnable tasks, and we
-               // couldn't release any locks.
-               return NULL;
-             }
+           Hold_lock hl(this->completed_lock_);
+           --this->queued_;
          }
 
-         // We're going around again, so recompute ALL_BLOCKED.
-         *all_blocked = true;
+         return t;
        }
+
+      if (is_runnable != Task::IS_BLOCKED)
+       *all_blocked = false;
+
+      tasks->push_back(t);
     }
+  while (t != tlast);
+
+  // We couldn't find any runnable task.
+  return NULL;
 }
 
 // Process all the tasks on the workqueue.  This is the main loop in
@@ -334,28 +310,56 @@ Workqueue::process()
       bool empty;
       bool all_blocked;
 
+      // Don't start more tasks than desired.
+      {
+       Hold_lock hl(this->completed_lock_);
+
+       this->clear_completed();
+       while (this->running_ >= this->desired_thread_count_)
+         {
+           this->completed_condvar_.wait();
+           this->clear_completed();
+         }
+      }
+
       {
        Hold_lock hl(this->tasks_lock_);
 
-       if (this->tasks_.empty())
+       bool first_empty;
+       bool all_blocked_first;
+       if (this->first_tasks_.empty())
          {
            t = NULL;
            empty = true;
-           all_blocked = false;
+           first_empty = true;
+           all_blocked_first = false;
          }
        else
          {
-           t = this->find_runnable(this->tasks_, &all_blocked);
+           t = this->find_runnable(&this->first_tasks_, &all_blocked_first);
            empty = false;
+           first_empty = false;
+         }
+
+       if (t == NULL)
+         {
+           if (this->tasks_.empty())
+             all_blocked = false;
+           else
+             {
+               t = this->find_runnable(&this->tasks_, &all_blocked);
+               if (!first_empty && !all_blocked_first)
+                 all_blocked = false;
+               empty = false;
+             }
          }
       }
 
       // If T != NULL, it is a task we can run.
       // If T == NULL && empty, then there are no tasks waiting to
-      // be run at this level.
+      // be run.
       // If T == NULL && !empty, then there tasks waiting to be
-      // run at this level, but they are waiting for something to
-      // unlock.
+      // run, but they are waiting for something to unlock.
 
       if (t != NULL)
        this->run(t);
@@ -371,10 +375,16 @@ Workqueue::process()
            if (all_blocked)
              {
                this->cleared_blockers_ = 0;
+               int queued = this->queued_;
                this->clear_completed();
-               while (this->cleared_blockers_ == 0)
+               while (this->cleared_blockers_ == 0
+                      && queued == this->queued_)
                  {
-                   gold_assert(this->running_ > 0);
+                   if (this->running_ <= 0)
+                     {
+                       this->show_queued_tasks();
+                       gold_unreachable();
+                     }
                    this->completed_condvar_.wait();
                    this->clear_completed();
                  }
@@ -416,7 +426,12 @@ Workqueue::process()
 void
 Workqueue::run(Task* t)
 {
-  ++this->running_;
+  gold_debug(DEBUG_TASK, "starting  task %s", t->name().c_str());
+
+  {
+    Hold_lock hl(this->completed_lock_);
+    ++this->running_;
+  }
   this->runner_->run(t, t->locks(this));
 }
 
@@ -427,6 +442,8 @@ Workqueue::run(Task* t)
 void
 Workqueue::completed(Task* t, Task_locker* tl)
 {
+  gold_debug(DEBUG_TASK, "completed task %s", t->name().c_str());
+
   {
     Hold_lock hl(this->completed_lock_);
     gold_assert(this->running_ > 0);
@@ -434,6 +451,7 @@ Workqueue::completed(Task* t, Task_locker* tl)
     this->completed_.push_back(tl);
     this->completed_condvar_.signal();
   }
+
   delete t;
 }
 
@@ -452,7 +470,40 @@ Workqueue::cleared_blocker()
 void
 Workqueue::set_thread_count(int threads)
 {
+  gold_assert(threads > 0);
+  this->desired_thread_count_ = threads;
   this->runner_->set_thread_count(threads);
 }
 
+// Dump the list of queued tasks and their current state, for
+// debugging purposes.
+
+void
+Workqueue::show_queued_tasks()
+{
+  fprintf(stderr, _("gold task queue:\n"));
+  Hold_lock hl(this->tasks_lock_);
+  for (Task_list::const_iterator p = this->tasks_.begin();
+       p != this->tasks_.end();
+       ++p)
+    {
+      fprintf(stderr, "  %s ", (*p)->name().c_str());
+      switch ((*p)->is_runnable(this))
+       {
+       case Task::IS_RUNNABLE:
+         fprintf(stderr, "runnable");
+         break;
+       case Task::IS_BLOCKED:
+         fprintf(stderr, "blocked");
+         break;
+       case Task::IS_LOCKED:
+         fprintf(stderr, "locked");
+         break;
+       default:
+         gold_unreachable();
+       }
+      putc('\n', stderr);
+    }
+}
+
 } // End namespace gold.
index 777b3aa091817123245310846ffcc96539309665..e435739c4ad0613974c82ca4c1a1f9717f03845a 100644 (file)
@@ -275,6 +275,7 @@ class Task
 {
  public:
   Task()
+    : name_()
   { }
   virtual ~Task()
   { }
@@ -307,9 +308,29 @@ class Task
   virtual void
   run(Workqueue*) = 0;
 
+  // Return the name of the Task.  This is only used for debugging
+  // purposes.
+  const std::string&
+  name()
+  {
+    if (this->name_.empty())
+      this->name_ = this->get_name();
+    return this->name_;
+  }
+
+ protected:
+  // Get the name of the task.  This must be implemented by the child
+  // class.
+  virtual std::string
+  get_name() const = 0;
+
  private:
+  // This task may not be copied.
   Task(const Task&);
   Task& operator=(const Task&);
+
+  // Task name, for debugging purposes.
+  std::string name_;
 };
 
 // A simple task which waits for a blocker and then runs a function.
@@ -329,8 +350,9 @@ class Task_function : public Task
  public:
   // Both points should be allocated using new, and will be deleted
   // after the task runs.
-  Task_function(Task_function_runner* runner, Task_token* blocker)
-    : runner_(runner), blocker_(blocker)
+  Task_function(Task_function_runner* runner, Task_token* blocker,
+               const char* name)
+    : runner_(runner), blocker_(blocker), name_(name)
   { }
 
   ~Task_function()
@@ -356,12 +378,18 @@ class Task_function : public Task
   run(Workqueue* workqueue)
   { this->runner_->run(workqueue); }
 
+  // The debugging name.
+  std::string
+  get_name() const
+  { return this->name_; }
+
  private:
   Task_function(const Task_function&);
   Task_function& operator=(const Task_function&);
 
   Task_function_runner* runner_;
   Task_token* blocker_;
+  const char* name_;
 };
 
 // The workqueue
@@ -403,39 +431,56 @@ class Workqueue
   typedef std::list<Task*> Task_list;
 
   // Run a task.
-  void run(Task*);
+  void
+  run(Task*);
 
   friend class Workqueue_runner;
 
   // Find a runnable task.
-  Task* find_runnable(Task_list&, bool*);
+  Task*
+  find_runnable(Task_list*, bool*);
 
   // Add a lock to the completed queue.
-  void completed(Task*, Task_locker*);
+  void
+  completed(Task*, Task_locker*);
 
   // Clear the completed queue.
-  bool clear_completed();
+  bool
+  clear_completed();
+
+  // Print the list of queued tasks.
+  void
+  show_queued_tasks();
 
   // How to run a task.  Only accessed from main thread.
   Workqueue_runner* runner_;
 
   // Lock for access to tasks_ members.
   Lock tasks_lock_;
-  // List of tasks to execute at each link level.
+  // List of tasks to execute soon.
+  Task_list first_tasks_;
+  // List of tasks to execute after the ones in first_tasks_.
   Task_list tasks_;
 
-  // Lock for access to completed_ and running_ members.
+  // Lock for access to completed_, running_, and queued_.
   Lock completed_lock_;
   // List of Task_locker objects for main thread to free.
   std::list<Task_locker*> completed_;
   // Number of tasks currently running.
   int running_;
+  // Number of tasks currently on queue (both first_tasks_ and
+  // tasks_).
+  int queued_;
   // Condition variable signalled when a new entry is added to completed_.
   Condvar completed_condvar_;
 
   // Number of blocker tokens which were fully cleared.  Only accessed
   // from main thread.
   int cleared_blockers_;
+
+  // The desired thread count.  Only set by the main thread or by a
+  // singleton thread.  Only accessed from the main thread.
+  int desired_thread_count_;
 };
 
 } // End namespace gold.