LIBIBERTY = ../libiberty/libiberty.a
+if THREADS
+THREADSLIB = -lpthread
+endif
+
AM_YFLAGS = -d
noinst_PROGRAMS = ld-new
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)
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)
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@
@INCINTL@
LIBIBERTY = ../libiberty/libiberty.a
+@THREADS_TRUE@THREADSLIB = -lpthread
AM_YFLAGS = -d
noinst_LIBRARIES = libgold.a
CCFILES = \
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)
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
# 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.
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
_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"
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
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
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
#include "gold.h"
+#include <cerrno>
+#include <cstring>
+
#ifdef ENABLE_THREADS
#include <pthread.h>
#endif
{
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)
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)
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"));
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());
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();
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&);
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,
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)
{
}
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&);
}
}
+ 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*)
{ }
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.
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
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
-DLOCALEDIR="\"$(datadir)/locale\"" \
@INCINTL@
+if THREADS
+THREADSLIB = -lpthread
+endif
+
TESTS = object_unittest
check_SCRIPTS =
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)
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 =
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)
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
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@
-DLOCALEDIR="\"$(datadir)/locale\"" \
@INCINTL@
+@THREADS_TRUE@THREADSLIB = -lpthread
TESTS = object_unittest $(NATIVE_TESTING)
check_SCRIPTS =
@GCC_TRUE@@NATIVE_LINKER_TRUE@NATIVE_PROGS = constructor_test \
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
#include "gold.h"
+#ifdef ENABLE_THREADS
+#include <pthread.h>
+#endif
+
#include "workqueue.h"
namespace gold
{ }
// 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.
~Workqueue_runner_single()
{ }
- void run(Task*, Task_locker*);
+ void
+ run(Task*, Task_locker*);
+
+ void
+ set_thread_count(int);
};
void
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_(),
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()
++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.
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.
void
cleared_blocker();
+ // Set the thread count.
+ void
+ set_thread_count(int);
+
private:
// This class can not be copied.
Workqueue(const Workqueue&);