Add infrastructure for threading support.
authorIan Lance Taylor <iant@google.com>
Wed, 17 Oct 2007 06:24:50 +0000 (06:24 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 17 Oct 2007 06:24:50 +0000 (06:24 +0000)
14 files changed:
gold/Makefile.am
gold/Makefile.in
gold/config.in
gold/configure
gold/configure.ac
gold/gold-threads.cc
gold/gold.cc
gold/object.h
gold/options.cc
gold/options.h
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/workqueue.cc
gold/workqueue.h

index 1c5498678118422cbe1256a5332bc8a272eaff42..d05979e3cff82a0977ea1b53736073e0a03ad2be 100644 (file)
@@ -18,6 +18,10 @@ INCLUDES = -D_GNU_SOURCE \
 
 LIBIBERTY = ../libiberty/libiberty.a
 
+if THREADS
+THREADSLIB = -lpthread
+endif
+
 AM_YFLAGS = -d
 
 noinst_PROGRAMS = ld-new
@@ -95,7 +99,7 @@ libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES)
 
 sources_var = main.cc
 deps_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL_DEP)
-ldadd_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL)
+ldadd_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL) $(THREADSLIB)
 
 ld_new_SOURCES = $(sources_var)
 ld_new_DEPENDENCIES = $(deps_var) $(LIBOBJS)
index 5f0bac3b05c784b267e3096d0464d7bcad5cf8ed..4b1b9e2a96905b98bdefb8f354d8fdd59adb5891 100644 (file)
@@ -91,7 +91,8 @@ ld_new_OBJECTS = $(am_ld_new_OBJECTS)
 am__DEPENDENCIES_1 =
 am__DEPENDENCIES_2 = ../libiberty/libiberty.a
 am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) libgold.a \
-       $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1)
+       $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
+       $(am__DEPENDENCIES_1)
 am__DEPENDENCIES_4 = @LIBOBJS@
 am__ld1_SOURCES_DIST = main.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am_ld1_OBJECTS = $(am__objects_4)
@@ -210,6 +211,8 @@ STATIC_TLS_FALSE = @STATIC_TLS_FALSE@
 STATIC_TLS_TRUE = @STATIC_TLS_TRUE@
 STRIP = @STRIP@
 TARGETOBJS = @TARGETOBJS@
+THREADS_FALSE = @THREADS_FALSE@
+THREADS_TRUE = @THREADS_TRUE@
 TLS_FALSE = @TLS_FALSE@
 TLS_TRUE = @TLS_TRUE@
 USE_NLS = @USE_NLS@
@@ -275,6 +278,7 @@ INCLUDES = -D_GNU_SOURCE \
        @INCINTL@
 
 LIBIBERTY = ../libiberty/libiberty.a
+@THREADS_TRUE@THREADSLIB = -lpthread
 AM_YFLAGS = -d
 noinst_LIBRARIES = libgold.a
 CCFILES = \
@@ -347,7 +351,7 @@ ALL_TARGETOBJS = \
 libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES)
 sources_var = main.cc
 deps_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL_DEP)
-ldadd_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL)
+ldadd_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL) $(THREADSLIB)
 ld_new_SOURCES = $(sources_var)
 ld_new_DEPENDENCIES = $(deps_var) $(LIBOBJS)
 ld_new_LDADD = $(ldadd_var) $(LIBOBJS)
index 9d1eba2e4b99a5b620cce6d7a14d5850b90e4fae..f46745d20d09358a2a114ddda3d26834f2fb7f3b 100644 (file)
@@ -4,6 +4,9 @@
    language is requested. */
 #undef ENABLE_NLS
 
+/* Define to do multi-threaded linking */
+#undef ENABLE_THREADS
+
 /* Define to 1 if you have the <ext/hash_map> header file. */
 #undef HAVE_EXT_HASH_MAP
 
index 1da2adf6c11123cb45a68c70f0fc7fc0a783c7e5..2490e255f2e7f63a2497c01d3d4d77141a628d50 100755 (executable)
@@ -309,7 +309,7 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar TARGETOBJS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC RANLIB ac_ct_RANLIB LN_S USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE NATIVE_LINKER_TRUE NATIVE_LINKER_FALSE GCC_TRUE GCC_FALSE FN_PTRS_IN_SO_WITHOUT_PIC_TRUE FN_PTRS_IN_SO_WITHOUT_PIC_FALSE TLS_TRUE TLS_FALSE STATIC_TLS_TRUE STATIC_TLS_FALSE WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CXXFLAGS LIBOBJS CXXCPP EGREP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar THREADS_TRUE THREADS_FALSE TARGETOBJS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC RANLIB ac_ct_RANLIB LN_S USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE NATIVE_LINKER_TRUE NATIVE_LINKER_FALSE GCC_TRUE GCC_FALSE FN_PTRS_IN_SO_WITHOUT_PIC_TRUE FN_PTRS_IN_SO_WITHOUT_PIC_FALSE TLS_TRUE TLS_FALSE STATIC_TLS_TRUE STATIC_TLS_FALSE WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CXXFLAGS LIBOBJS CXXCPP EGREP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -860,6 +860,7 @@ if test -n "$ac_init_help"; then
 Optional Features:
   --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
   --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-threads        multi-threaded linking
   --enable-targets        alternative target configurations
   --disable-dependency-tracking  speeds up one-time build
   --enable-dependency-tracking   do not reject slow dependency extractors
@@ -1897,6 +1898,35 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+# Check whether --enable-threads or --disable-threads was given.
+if test "${enable_threads+set}" = set; then
+  enableval="$enable_threads"
+  case "${enableval}" in
+  yes | "") threads=yes ;;
+  no) threads=no ;;
+  *) threads=yes ;;
+ esac
+else
+  threads=no
+fi;
+if test "$threads" = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define ENABLE_THREADS 1
+_ACEOF
+
+fi
+
+
+if test "$threads" = "yes"; then
+  THREADS_TRUE=
+  THREADS_FALSE='#'
+else
+  THREADS_TRUE='#'
+  THREADS_FALSE=
+fi
+
+
 # Check whether --enable-targets or --disable-targets was given.
 if test "${enable_targets+set}" = set; then
   enableval="$enable_targets"
@@ -5791,6 +5821,13 @@ LIBOBJS=$ac_libobjs
 LTLIBOBJS=$ac_ltlibobjs
 
 
+if test -z "${THREADS_TRUE}" && test -z "${THREADS_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"THREADS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"THREADS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
 if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
   { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
 Usually this means the macro was only invoked conditionally." >&5
@@ -6430,6 +6467,8 @@ s,@am__leading_dot@,$am__leading_dot,;t t
 s,@AMTAR@,$AMTAR,;t t
 s,@am__tar@,$am__tar,;t t
 s,@am__untar@,$am__untar,;t t
+s,@THREADS_TRUE@,$THREADS_TRUE,;t t
+s,@THREADS_FALSE@,$THREADS_FALSE,;t t
 s,@TARGETOBJS@,$TARGETOBJS,;t t
 s,@CC@,$CC,;t t
 s,@CFLAGS@,$CFLAGS,;t t
index aefd617470a03ba1069bfc934da779a6b458123a..d8f71dfcb65a2f52286a679ea021982873df5739 100644 (file)
@@ -38,6 +38,21 @@ AC_DEFINE_UNQUOTED(TARGET_SYSTEM_ROOT, "$sysroot",
 AC_DEFINE_UNQUOTED(TARGET_SYSTEM_ROOT_RELOCATABLE, $sysroot_relocatable,
   [Whether the system root can be relocated])
 
+dnl For now threads are a configure time option.
+AC_ARG_ENABLE([threads],
+[  --enable-threads        multi-threaded linking],
+[case "${enableval}" in
+  yes | "") threads=yes ;;
+  no) threads=no ;;
+  *) threads=yes ;;
+ esac],
+[threads=no])
+if test "$threads" = "yes"; then
+  AC_DEFINE(ENABLE_THREADS, 1,
+           [Define to do multi-threaded linking])
+fi
+AM_CONDITIONAL(THREADS, test "$threads" = "yes")
+
 AC_ARG_ENABLE([targets],
 [  --enable-targets        alternative target configurations],
 [case "${enableval}" in
index ad9506cc9947f65a1c406139907a8603c329a291..396e6c10631ae7df124a1aa1cfedcb59d09db3a8 100644 (file)
@@ -22,6 +22,9 @@
 
 #include "gold.h"
 
+#include <cerrno>
+#include <cstring>
+
 #ifdef ENABLE_THREADS
 #include <pthread.h>
 #endif
@@ -63,37 +66,37 @@ Lock_impl::Lock_impl()
 {
   pthread_mutexattr_t attr;
   if (pthread_mutexattr_init(&attr) != 0)
-    gold_fatal(_("pthead_mutextattr_init failed"), true);
+    gold_fatal(_("pthead_mutextattr_init failed: %s"), strerror(errno));
 #ifdef PTHREAD_MUTEXT_ADAPTIVE_NP
   if (pthread_mutextattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP) != 0)
-    gold_fatal(_("pthread_mutextattr_settype failed"), true);
+    gold_fatal(_("pthread_mutextattr_settype failed: %s"), strerror(errno));
 #endif
 
   if (pthread_mutex_init (&this->mutex_, &attr) != 0)
-    gold_fatal(_("pthread_mutex_init failed"), true);
+    gold_fatal(_("pthread_mutex_init failed: %s"), strerror(errno));
 
   if (pthread_mutexattr_destroy(&attr) != 0)
-    gold_fatal(_("pthread_mutexattr_destroy failed"), true);
+    gold_fatal(_("pthread_mutexattr_destroy failed: %s"), strerror(errno));
 }
 
 Lock_impl::~Lock_impl()
 {
   if (pthread_mutex_destroy(&this->mutex_) != 0)
-    gold_fatal(_("pthread_mutex_destroy failed"), true);
+    gold_fatal(_("pthread_mutex_destroy failed: %s"), strerror(errno));
 }
 
 void
 Lock_impl::acquire()
 {
   if (pthread_mutex_lock(&this->mutex_) != 0)
-    gold_fatal(_("pthread_mutex_lock failed"), true);
+    gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(errno));
 }
 
 void
 Lock_impl::release()
 {
   if (pthread_mutex_unlock(&this->mutex_) != 0)
-    gold_fatal(_("pthread_mutex_unlock failed"), true);
+    gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(errno));
 }
 
 #else // !defined(ENABLE_THREADS)
@@ -174,27 +177,27 @@ class Condvar_impl
 Condvar_impl::Condvar_impl()
 {
   if (pthread_cond_init(&this->cond_, NULL) != 0)
-    gold_fatal(_("pthread_cond_init failed"), true);
+    gold_fatal(_("pthread_cond_init failed: %s"), strerror(errno));
 }
 
 Condvar_impl::~Condvar_impl()
 {
   if (pthread_cond_destroy(&this->cond_) != 0)
-    gold_fatal(_("pthread_cond_destroy failed"), true);
+    gold_fatal(_("pthread_cond_destroy failed: %s"), strerror(errno));
 }
 
 void
 Condvar_impl::wait(Lock_impl* li)
 {
   if (pthread_cond_wait(&this->cond_, &li->mutex_) != 0)
-    gold_fatal(_("pthread_cond_wait failed"), true);
+    gold_fatal(_("pthread_cond_wait failed: %s"), strerror(errno));
 }
 
 void
 Condvar_impl::signal()
 {
   if (pthread_cond_signal(&this->cond_) != 0)
-    gold_fatal(_("pthread_cond_signal failed"), true);
+    gold_fatal(_("pthread_cond_signal failed: %s"), strerror(errno));
 }
 
 #else // !defined(ENABLE_THREADS)
index 8c86b9ed72ef22ca265c3944d0ea9f7b46537e3b..86fc8e6847c72722965a9c29748b03cef2fd2279 100644 (file)
@@ -114,6 +114,15 @@ queue_initial_tasks(const General_options& options,
                    Workqueue* workqueue, Input_objects* input_objects,
                    Symbol_table* symtab, Layout* layout)
 {
+  int thread_count = options.thread_count_initial();
+  if (thread_count == 0)
+    {
+      thread_count = cmdline.number_of_input_files();
+      if (thread_count == 0)
+       thread_count = 1;
+    }
+  workqueue->set_thread_count(thread_count);
+
   if (cmdline.begin() == cmdline.end())
     gold_fatal(_("no input files"));
 
@@ -152,6 +161,15 @@ queue_middle_tasks(const General_options& options,
                   Layout* layout,
                   Workqueue* workqueue)
 {
+  int thread_count = options.thread_count_middle();
+  if (thread_count == 0)
+    {
+      thread_count = input_objects->number_of_input_objects();
+      if (thread_count == 0)
+       thread_count = 1;
+    }
+  workqueue->set_thread_count(thread_count);
+
   // Now we have seen all the input files.
   const bool doing_static_link = (!input_objects->any_dynamic()
                                  && !parameters->output_is_shared());
@@ -228,6 +246,15 @@ queue_final_tasks(const General_options& options,
                  Workqueue* workqueue,
                  Output_file* of)
 {
+  int thread_count = options.thread_count_final();
+  if (thread_count == 0)
+    {
+      thread_count = input_objects->number_of_input_objects();
+      if (thread_count == 0)
+       thread_count = 1;
+    }
+  workqueue->set_thread_count(thread_count);
+
   // Use a blocker to block the final cleanup task.
   Task_token* final_blocker = new Task_token();
 
index 1b8c1e2440d7157151e046e1afd518e8c82ca103..46e332f5051d1202019b63a34374d21559efb167 100644 (file)
@@ -828,6 +828,11 @@ class Input_objects
   any_dynamic() const
   { return !this->dynobj_list_.empty(); }
 
+  // Return the number of input objects.
+  int
+  number_of_input_objects() const
+  { return this->relobj_list_.size() + this->dynobj_list_.size(); }
+
  private:
   Input_objects(const Input_objects&);
   Input_objects& operator=(const Input_objects&);
index c01d947de53f914a71a3f8a4860f912589ce6740..6911e032a3333f85ab1eecde7623e6945fdc41a0 100644 (file)
@@ -357,6 +357,25 @@ options::Command_line_options::options[] =
   GENERAL_ARG('\0', "Ttext", N_("Set the address of the .text section"),
               N_("-Ttext ADDRESS"), ONE_DASH,
               &General_options::set_text_segment_address),
+  GENERAL_NOARG('\0', "threads", N_("Run the linker multi-threaded"),
+               NULL, TWO_DASHES, &General_options::set_threads),
+  GENERAL_NOARG('\0', "no-threads", N_("Do not run the linker multi-threaded"),
+               NULL, TWO_DASHES, &General_options::clear_threads),
+  GENERAL_ARG('\0', "thread-count", N_("Number of threads to use"),
+             N_("--thread-count COUNT"), TWO_DASHES,
+             &General_options::set_thread_count),
+  GENERAL_ARG('\0', "thread-count-initial",
+             N_("Number of threads to use in initial pass"),
+             N_("--thread-count-initial COUNT"), TWO_DASHES,
+             &General_options::set_thread_count_initial),
+  GENERAL_ARG('\0', "thread-count-middle",
+             N_("Number of threads to use in middle pass"),
+             N_("--thread-count-middle COUNT"), TWO_DASHES,
+             &General_options::set_thread_count_middle),
+  GENERAL_ARG('\0', "thread-count-final",
+             N_("Number of threads to use in final pass"),
+             N_("--thread-count-final COUNT"), TWO_DASHES,
+             &General_options::set_thread_count_final),
   POSDEP_NOARG('\0', "whole-archive",
                N_("Include all archive contents"),
                NULL, TWO_DASHES,
@@ -395,7 +414,11 @@ General_options::General_options()
     is_static_(false),
     print_stats_(false),
     sysroot_(),
-    text_segment_address_(-1U)   // -1 indicates value not set by user
+    text_segment_address_(-1U),   // -1 indicates value not set by user
+    threads_(false),
+    thread_count_initial_(0),
+    thread_count_middle_(0),
+    thread_count_final_(0)
 {
 }
 
index d32dd4a5354e932a948ac367891e6f07028c08c9..fd43de3daab94249c07bd20bb5dc525582697313 100644 (file)
@@ -189,6 +189,26 @@ class General_options
   user_set_text_segment_address() const
   { return this->text_segment_address_ != -1U; }
 
+  // --threads: Whether to use threads.
+  bool
+  threads() const
+  { return this->threads_; }
+
+  // --thread-count-initial: Threads to use in initial pass.
+  int
+  thread_count_initial() const
+  { return this->thread_count_initial_; }
+
+  // --thread-count-middle: Threads to use in middle pass.
+  int
+  thread_count_middle() const
+  { return this->thread_count_middle_; }
+
+  // --thread-count-final: Threads to use in final pass.
+  int
+  thread_count_final() const
+  { return this->thread_count_final_; }
+
  private:
   // Don't copy this structure.
   General_options(const General_options&);
@@ -288,6 +308,49 @@ class General_options
       }
   }
 
+  int
+  parse_thread_count(const char* arg)
+  {
+    char* endptr;
+    int count = strtol(arg, &endptr, 0);
+    if (*endptr != '\0' || count < 0)
+      {
+       fprintf(stderr, _("%s: invalid thread count: %s\n"),
+               program_name, arg);
+       ::exit(1);
+      }
+    return count;
+  }
+
+  void
+  set_threads()
+  { this->threads_ = true; }
+
+  void
+  clear_threads()
+  { this->threads_ = false; }
+
+  void
+  set_thread_count(const char* arg)
+  {
+    int count = this->parse_thread_count(arg);
+    this->thread_count_initial_ = count;
+    this->thread_count_middle_ = count;
+    this->thread_count_final_ = count;
+  }
+
+  void
+  set_thread_count_initial(const char* arg)
+  { this->thread_count_initial_ = this->parse_thread_count(arg); }
+
+  void
+  set_thread_count_middle(const char* arg)
+  { this->thread_count_initial_ = this->parse_thread_count(arg); }
+
+  void
+  set_thread_count_final(const char* arg)
+  { this->thread_count_initial_ = this->parse_thread_count(arg); }
+
   void
   ignore(const char*)
   { }
@@ -311,6 +374,10 @@ class General_options
   bool print_stats_;
   std::string sysroot_;
   uint64_t text_segment_address_;
+  bool threads_;
+  int thread_count_initial_;
+  int thread_count_middle_;
+  int thread_count_final_;
 };
 
 // The current state of the position dependent options.
@@ -543,6 +610,11 @@ class Input_arguments
   in_group() const
   { return this->in_group_; }
 
+  // The number of entries in the list.
+  int
+  size() const
+  { return this->input_argument_list_.size(); }
+
   // Iterators to iterate over the list of input files.
 
   const_iterator
@@ -594,6 +666,11 @@ class Command_line
   options() const
   { return this->options_; }
 
+  // The number of input files.
+  int
+  number_of_input_files() const
+  { return this->inputs_.size(); }
+
   // Iterators to iterate over the list of input files.
 
   const_iterator
index cfa2f1c54f7679534f4dd7c6526630da1022b1c6..bcbdcc3401533cf49cf6431d1ed221a33a490059 100644 (file)
@@ -17,6 +17,10 @@ INCLUDES = -D_GNU_SOURCE \
        -DLOCALEDIR="\"$(datadir)/locale\"" \
        @INCINTL@
 
+if THREADS
+THREADSLIB = -lpthread
+endif
+
 TESTS = object_unittest
 check_SCRIPTS = 
 
@@ -95,7 +99,8 @@ libgoldtest_a_SOURCES = test.cc testmain.cc testfile.cc
 
 DEPENDENCIES = \
        libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL_DEP)
-LDADD = libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL)
+LDADD = libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL) \
+       $(THREADSLIB)
 
 check_PROGRAMS = object_unittest $(NATIVE_PROGS)
 
index 302e2030b3c3441cb6dcf492e2317767a73b64ad..b8ab3e5553b1ce7002ec4e443899b9d3e2642bba 100644 (file)
@@ -63,40 +63,49 @@ target_triplet = @target@
 
 check_PROGRAMS = object_unittest$(EXEEXT) $(am__EXEEXT_5)
 @GCC_FALSE@constructor_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
-@GCC_FALSE@    ../../libiberty/libiberty.a $(am__DEPENDENCIES_1)
+@GCC_FALSE@    ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+@GCC_FALSE@    $(am__DEPENDENCIES_1)
 @NATIVE_LINKER_FALSE@constructor_test_DEPENDENCIES = libgoldtest.a \
 @NATIVE_LINKER_FALSE@  ../libgold.a ../../libiberty/libiberty.a \
+@NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1)
 @GCC_FALSE@constructor_static_test_DEPENDENCIES = libgoldtest.a \
 @GCC_FALSE@    ../libgold.a ../../libiberty/libiberty.a \
-@GCC_FALSE@    $(am__DEPENDENCIES_1)
+@GCC_FALSE@    $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 @NATIVE_LINKER_FALSE@constructor_static_test_DEPENDENCIES =  \
 @NATIVE_LINKER_FALSE@  libgoldtest.a ../libgold.a \
 @NATIVE_LINKER_FALSE@  ../../libiberty/libiberty.a \
+@NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1)
 @GCC_FALSE@two_file_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
-@GCC_FALSE@    ../../libiberty/libiberty.a $(am__DEPENDENCIES_1)
+@GCC_FALSE@    ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+@GCC_FALSE@    $(am__DEPENDENCIES_1)
 @NATIVE_LINKER_FALSE@two_file_test_DEPENDENCIES = libgoldtest.a \
 @NATIVE_LINKER_FALSE@  ../libgold.a ../../libiberty/libiberty.a \
+@NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1)
 @GCC_FALSE@two_file_static_test_DEPENDENCIES = libgoldtest.a \
 @GCC_FALSE@    ../libgold.a ../../libiberty/libiberty.a \
-@GCC_FALSE@    $(am__DEPENDENCIES_1)
+@GCC_FALSE@    $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 @NATIVE_LINKER_FALSE@two_file_static_test_DEPENDENCIES =  \
 @NATIVE_LINKER_FALSE@  libgoldtest.a ../libgold.a \
 @NATIVE_LINKER_FALSE@  ../../libiberty/libiberty.a \
+@NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1)
 @GCC_FALSE@exception_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
-@GCC_FALSE@    ../../libiberty/libiberty.a $(am__DEPENDENCIES_1)
+@GCC_FALSE@    ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+@GCC_FALSE@    $(am__DEPENDENCIES_1)
 @NATIVE_LINKER_FALSE@exception_test_DEPENDENCIES = libgoldtest.a \
 @NATIVE_LINKER_FALSE@  ../libgold.a ../../libiberty/libiberty.a \
+@NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1)
 @GCC_FALSE@exception_static_test_DEPENDENCIES = libgoldtest.a \
 @GCC_FALSE@    ../libgold.a ../../libiberty/libiberty.a \
-@GCC_FALSE@    $(am__DEPENDENCIES_1)
+@GCC_FALSE@    $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 @NATIVE_LINKER_FALSE@exception_static_test_DEPENDENCIES =  \
 @NATIVE_LINKER_FALSE@  libgoldtest.a ../libgold.a \
 @NATIVE_LINKER_FALSE@  ../../libiberty/libiberty.a \
+@NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1) \
 @NATIVE_LINKER_FALSE@  $(am__DEPENDENCIES_1)
 @GCC_FALSE@tls_test_DEPENDENCIES =
 @NATIVE_LINKER_FALSE@tls_test_DEPENDENCIES =
@@ -221,7 +230,8 @@ am_object_unittest_OBJECTS = object_unittest.$(OBJEXT)
 object_unittest_OBJECTS = $(am_object_unittest_OBJECTS)
 object_unittest_LDADD = $(LDADD)
 object_unittest_DEPENDENCIES = libgoldtest.a ../libgold.a \
-       ../../libiberty/libiberty.a $(am__DEPENDENCIES_1)
+       ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+       $(am__DEPENDENCIES_1)
 am__tls_pic_test_SOURCES_DIST = tls_test_main.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am_tls_pic_test_OBJECTS = tls_test_main.$(OBJEXT)
 tls_pic_test_OBJECTS = $(am_tls_pic_test_OBJECTS)
@@ -330,7 +340,8 @@ am__weak_test_SOURCES_DIST = weak_test.cc
 weak_test_OBJECTS = $(am_weak_test_OBJECTS)
 weak_test_LDADD = $(LDADD)
 weak_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
-       ../../libiberty/libiberty.a $(am__DEPENDENCIES_1)
+       ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
+       $(am__DEPENDENCIES_1)
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/../depcomp
 am__depfiles_maybe = depfiles
@@ -473,6 +484,8 @@ STATIC_TLS_FALSE = @STATIC_TLS_FALSE@
 STATIC_TLS_TRUE = @STATIC_TLS_TRUE@
 STRIP = @STRIP@
 TARGETOBJS = @TARGETOBJS@
+THREADS_FALSE = @THREADS_FALSE@
+THREADS_TRUE = @THREADS_TRUE@
 TLS_FALSE = @TLS_FALSE@
 TLS_TRUE = @TLS_TRUE@
 USE_NLS = @USE_NLS@
@@ -538,6 +551,7 @@ INCLUDES = -D_GNU_SOURCE \
        -DLOCALEDIR="\"$(datadir)/locale\"" \
        @INCINTL@
 
+@THREADS_TRUE@THREADSLIB = -lpthread
 TESTS = object_unittest $(NATIVE_TESTING)
 check_SCRIPTS = 
 @GCC_TRUE@@NATIVE_LINKER_TRUE@NATIVE_PROGS = constructor_test \
@@ -572,7 +586,9 @@ libgoldtest_a_SOURCES = test.cc testmain.cc testfile.cc
 DEPENDENCIES = \
        libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL_DEP)
 
-LDADD = libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL)
+LDADD = libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL) \
+       $(THREADSLIB)
+
 object_unittest_SOURCES = object_unittest.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@constructor_test_SOURCES = constructor_test.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@constructor_test_DEPENDENCIES = gcctestdir/ld
index 2c7e88032073a656cf0259b866001019faa8069b..95c14ce5a8594dd970fa35054f872c1dfb3bef4a 100644 (file)
 
 #include "gold.h"
 
+#ifdef ENABLE_THREADS
+#include <pthread.h>
+#endif
+
 #include "workqueue.h"
 
 namespace gold
@@ -153,7 +157,13 @@ class Workqueue_runner
   { }
 
   // Run a task.  This is always called in the main thread.
-  virtual void run(Task*, Task_locker*) = 0;
+  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.
@@ -178,7 +188,11 @@ class Workqueue_runner_single : public Workqueue_runner
   ~Workqueue_runner_single()
   { }
 
-  void run(Task*, Task_locker*);
+  void
+  run(Task*, Task_locker*);
+
+  void
+  set_thread_count(int);
 };
 
 void
@@ -188,9 +202,15 @@ Workqueue_runner_single::run(Task* t, Task_locker* tl)
   this->completed(t, tl);
 }
 
+void
+Workqueue_runner_single::set_thread_count(int thread_count)
+{
+  gold_assert(thread_count > 0);
+}
+
 // Workqueue methods.
 
-Workqueue::Workqueue(const General_options&)
+Workqueue::Workqueue(const General_options& options)
   : tasks_lock_(),
     tasks_(),
     completed_lock_(),
@@ -199,9 +219,14 @@ Workqueue::Workqueue(const General_options&)
     completed_condvar_(this->completed_lock_),
     cleared_blockers_(0)
 {
-  // At some point we will select the specific implementation of
-  // Workqueue_runner to use based on the command line options.
-  this->runner_ = new Workqueue_runner_single(this);
+  bool threads = options.threads();
+#ifndef ENABLE_THREADS
+  threads = false;
+#endif
+  if (!threads)
+    this->runner_ = new Workqueue_runner_single(this);
+  else
+    gold_unreachable();
 }
 
 Workqueue::~Workqueue()
@@ -421,4 +446,13 @@ Workqueue::cleared_blocker()
   ++this->cleared_blockers_;
 }
 
+// Set the number of threads to use for the workqueue, if we are using
+// threads.
+
+void
+Workqueue::set_thread_count(int threads)
+{
+  this->runner_->set_thread_count(threads);
+}
+
 } // End namespace gold.
index 0b88f9411f0727ba9c434b0ac01dd8e0550fea0b..777b3aa091817123245310846ffcc96539309665 100644 (file)
@@ -47,7 +47,7 @@ class Task;
 class Workqueue;
 
 // Some tasks require access to shared data structures, such as the
-// symbol table.  Some tasks must be executed in a particular error,
+// symbol table.  Some tasks must be executed in a particular order,
 // such as reading input file symbol tables--if we see foo.o -llib, we
 // have to read the symbols for foo.o before we read the ones for
 // -llib.  To implement this safely and efficiently, we use tokens.
@@ -391,6 +391,10 @@ class Workqueue
   void
   cleared_blocker();
 
+  // Set the thread count.
+  void
+  set_thread_count(int);
+
  private:
   // This class can not be copied.
   Workqueue(const Workqueue&);