X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gold%2Fgold-threads.cc;h=f972a8c97d35a2cb17001658e87eb5ca74ef5407;hb=85e290dc1252d77e726c0892b197be449b34bd16;hp=e54d96c6ec7b2c7d507c647450e271cd8c4a566d;hpb=8851eccaec28f25f56fab5ba5d8ae44f71729975;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/gold-threads.cc b/gold/gold-threads.cc index e54d96c6ec..f972a8c97d 100644 --- a/gold/gold-threads.cc +++ b/gold/gold-threads.cc @@ -1,6 +1,6 @@ // gold-threads.cc -- thread support for gold -// Copyright 2006, 2007 Free Software Foundation, Inc. +// Copyright (C) 2006-2020 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -100,14 +100,14 @@ Lock_impl_threads::Lock_impl_threads() pthread_mutexattr_t attr; int err = pthread_mutexattr_init(&attr); if (err != 0) - gold_fatal(_("pthead_mutextattr_init failed: %s"), strerror(err)); -#ifdef PTHREAD_MUTEXT_ADAPTIVE_NP - err = pthread_mutextattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); + gold_fatal(_("pthead_mutexattr_init failed: %s"), strerror(err)); +#ifdef PTHREAD_MUTEX_ADAPTIVE_NP + err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); if (err != 0) - gold_fatal(_("pthread_mutextattr_settype failed: %s"), strerror(err)); + gold_fatal(_("pthread_mutexattr_settype failed: %s"), strerror(err)); #endif - err = pthread_mutex_init (&this->mutex_, &attr); + err = pthread_mutex_init(&this->mutex_, &attr); if (err != 0) gold_fatal(_("pthread_mutex_init failed: %s"), strerror(err)); @@ -276,4 +276,175 @@ Condvar::~Condvar() delete this->condvar_; } +#ifdef ENABLE_THREADS + +// Class Once_initialize. This exists to hold a pthread_once_t +// structure for Once. + +class Once_initialize +{ + public: + Once_initialize() + : once_(PTHREAD_ONCE_INIT) + { } + + // Return a pointer to the pthread_once_t variable. + pthread_once_t* + once_control() + { return &this->once_; } + + private: + pthread_once_t once_; +}; + +#endif // defined(ENABLE_THREADS) + +#ifdef ENABLE_THREADS + +// A single lock which controls access to once_pointer. This is used +// because we can't pass parameters to functions passed to +// pthread_once. + +static pthread_mutex_t once_pointer_control = PTHREAD_MUTEX_INITIALIZER; + +// A pointer to Once structure we want to run. Access to this is +// controlled by once_pointer_control. + +static Once* once_pointer; + +// The argument to pass to the Once structure. Access to this is +// controlled by once_pointer_control. + +static void* once_arg; + +// A routine passed to pthread_once which runs the Once pointer. + +extern "C" +{ + +static void +c_run_once(void) +{ + once_pointer->internal_run(once_arg); +} + +} + +#endif // defined(ENABLE_THREADS) + +// Class Once. + +Once::Once() + : was_run_(false) +#if defined(ENABLE_THREADS) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) + , was_run_lock_(0) +#endif +{ +#ifndef ENABLE_THREADS + this->once_ = NULL; +#else + this->once_ = new Once_initialize(); +#endif +} + +// Run the function once. + +void +Once::run_once(void* arg) +{ +#ifndef ENABLE_THREADS + + // If there is no threads support, we don't need to use pthread_once. + if (!this->was_run_) + this->internal_run(arg); + +#else // defined(ENABLE_THREADS) + + if (parameters->options_valid() && !parameters->options().threads()) + { + // If we are not using threads, we don't need to lock. + if (!this->was_run_) + this->internal_run(arg); + return; + } + + // If we have the sync builtins, use them to skip the lock if the + // value has already been initialized. +#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 + while (true) + { + if (__sync_bool_compare_and_swap(&this->was_run_lock_, 0, 1)) + break; + } + bool was_run = this->was_run_; + while (true) + { + if (__sync_bool_compare_and_swap(&this->was_run_lock_, 1, 0)) + break; + } + if (was_run) + return; +#endif + + // Since we can't pass parameters to routines called by + // pthread_once, we use a static variable: once_pointer. This in + // turns means that we need to use a mutex to control access to + // once_pointer. + + int err = pthread_mutex_lock(&once_pointer_control); + if (err != 0) + gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err)); + + once_pointer = this; + once_arg = arg; + + err = pthread_once(this->once_->once_control(), c_run_once); + if (err != 0) + gold_fatal(_("pthread_once failed: %s"), strerror(err)); + + once_pointer = NULL; + once_arg = NULL; + + err = pthread_mutex_unlock(&once_pointer_control); + if (err != 0) + gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err)); + +#endif // defined(ENABLE_THREADS) +} + +// Actually run the function in the child class. This function will +// be run only once. + +void +Once::internal_run(void* arg) +{ + this->do_run_once(arg); + this->was_run_ = true; +} + +// Class Initialize_lock. + +// Initialize the lock. + +bool +Initialize_lock::initialize() +{ + // We can't initialize the lock until we have read the options. + if (!parameters->options_valid()) + return false; + else + { + this->run_once(NULL); + return true; + } +} + +// Initialize the lock exactly once. + +void +Initialize_lock::do_run_once(void*) +{ + *this->pplock_ = new Lock(); +} + } // End namespace gold.