Home | History | Annotate | Download | only in gold
      1 // gold-threads.cc -- thread support for gold
      2 
      3 // Copyright (C) 2006-2014 Free Software Foundation, Inc.
      4 // Written by Ian Lance Taylor <iant (at) google.com>.
      5 
      6 // This file is part of gold.
      7 
      8 // This program is free software; you can redistribute it and/or modify
      9 // it under the terms of the GNU General Public License as published by
     10 // the Free Software Foundation; either version 3 of the License, or
     11 // (at your option) any later version.
     12 
     13 // This program is distributed in the hope that it will be useful,
     14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16 // GNU General Public License for more details.
     17 
     18 // You should have received a copy of the GNU General Public License
     19 // along with this program; if not, write to the Free Software
     20 // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     21 // MA 02110-1301, USA.
     22 
     23 #include "gold.h"
     24 
     25 #include <cstring>
     26 
     27 #ifdef ENABLE_THREADS
     28 #include <pthread.h>
     29 #endif
     30 
     31 #include "options.h"
     32 #include "parameters.h"
     33 #include "gold-threads.h"
     34 
     35 namespace gold
     36 {
     37 
     38 class Condvar_impl_nothreads;
     39 
     40 // The non-threaded version of Lock_impl.
     41 
     42 class Lock_impl_nothreads : public Lock_impl
     43 {
     44  public:
     45   Lock_impl_nothreads()
     46     : acquired_(false)
     47   { }
     48 
     49   ~Lock_impl_nothreads()
     50   { gold_assert(!this->acquired_); }
     51 
     52   void
     53   acquire()
     54   {
     55     gold_assert(!this->acquired_);
     56     this->acquired_ = true;
     57   }
     58 
     59   void
     60   release()
     61   {
     62     gold_assert(this->acquired_);
     63     this->acquired_ = false;
     64   }
     65 
     66  private:
     67   friend class Condvar_impl_nothreads;
     68 
     69   bool acquired_;
     70 };
     71 
     72 #ifdef ENABLE_THREADS
     73 
     74 class Condvar_impl_threads;
     75 
     76 // The threaded version of Lock_impl.
     77 
     78 class Lock_impl_threads : public Lock_impl
     79 {
     80  public:
     81   Lock_impl_threads();
     82   ~Lock_impl_threads();
     83 
     84   void acquire();
     85 
     86   void release();
     87 
     88 private:
     89   // This class can not be copied.
     90   Lock_impl_threads(const Lock_impl_threads&);
     91   Lock_impl_threads& operator=(const Lock_impl_threads&);
     92 
     93   friend class Condvar_impl_threads;
     94 
     95   pthread_mutex_t mutex_;
     96 };
     97 
     98 Lock_impl_threads::Lock_impl_threads()
     99 {
    100   pthread_mutexattr_t attr;
    101   int err = pthread_mutexattr_init(&attr);
    102   if (err != 0)
    103     gold_fatal(_("pthead_mutextattr_init failed: %s"), strerror(err));
    104 #ifdef PTHREAD_MUTEX_ADAPTIVE_NP
    105   err = pthread_mutextattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
    106   if (err != 0)
    107     gold_fatal(_("pthread_mutextattr_settype failed: %s"), strerror(err));
    108 #endif
    109 
    110   err = pthread_mutex_init(&this->mutex_, &attr);
    111   if (err != 0)
    112     gold_fatal(_("pthread_mutex_init failed: %s"), strerror(err));
    113 
    114   err = pthread_mutexattr_destroy(&attr);
    115   if (err != 0)
    116     gold_fatal(_("pthread_mutexattr_destroy failed: %s"), strerror(err));
    117 }
    118 
    119 Lock_impl_threads::~Lock_impl_threads()
    120 {
    121   int err = pthread_mutex_destroy(&this->mutex_);
    122   if (err != 0)
    123     gold_fatal(_("pthread_mutex_destroy failed: %s"), strerror(err));
    124 }
    125 
    126 void
    127 Lock_impl_threads::acquire()
    128 {
    129   int err = pthread_mutex_lock(&this->mutex_);
    130   if (err != 0)
    131     gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err));
    132 }
    133 
    134 void
    135 Lock_impl_threads::release()
    136 {
    137   int err = pthread_mutex_unlock(&this->mutex_);
    138   if (err != 0)
    139     gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err));
    140 }
    141 
    142 #endif // defined(ENABLE_THREADS)
    143 
    144 // Class Lock.
    145 
    146 Lock::Lock()
    147 {
    148   if (!parameters->options().threads())
    149     this->lock_ = new Lock_impl_nothreads;
    150   else
    151     {
    152 #ifdef ENABLE_THREADS
    153       this->lock_ = new Lock_impl_threads;
    154 #else
    155       gold_unreachable();
    156 #endif
    157     }
    158 }
    159 
    160 Lock::~Lock()
    161 {
    162   delete this->lock_;
    163 }
    164 
    165 // The non-threaded version of Condvar_impl.
    166 
    167 class Condvar_impl_nothreads : public Condvar_impl
    168 {
    169  public:
    170   Condvar_impl_nothreads()
    171   { }
    172 
    173   ~Condvar_impl_nothreads()
    174   { }
    175 
    176   void
    177   wait(Lock_impl* li)
    178   { gold_assert(static_cast<Lock_impl_nothreads*>(li)->acquired_); }
    179 
    180   void
    181   signal()
    182   { }
    183 
    184   void
    185   broadcast()
    186   { }
    187 };
    188 
    189 #ifdef ENABLE_THREADS
    190 
    191 // The threaded version of Condvar_impl.
    192 
    193 class Condvar_impl_threads : public Condvar_impl
    194 {
    195  public:
    196   Condvar_impl_threads();
    197   ~Condvar_impl_threads();
    198 
    199   void
    200   wait(Lock_impl*);
    201 
    202   void
    203   signal();
    204 
    205   void
    206   broadcast();
    207 
    208  private:
    209   // This class can not be copied.
    210   Condvar_impl_threads(const Condvar_impl_threads&);
    211   Condvar_impl_threads& operator=(const Condvar_impl_threads&);
    212 
    213   pthread_cond_t cond_;
    214 };
    215 
    216 Condvar_impl_threads::Condvar_impl_threads()
    217 {
    218   int err = pthread_cond_init(&this->cond_, NULL);
    219   if (err != 0)
    220     gold_fatal(_("pthread_cond_init failed: %s"), strerror(err));
    221 }
    222 
    223 Condvar_impl_threads::~Condvar_impl_threads()
    224 {
    225   int err = pthread_cond_destroy(&this->cond_);
    226   if (err != 0)
    227     gold_fatal(_("pthread_cond_destroy failed: %s"), strerror(err));
    228 }
    229 
    230 void
    231 Condvar_impl_threads::wait(Lock_impl* li)
    232 {
    233   Lock_impl_threads* lit = static_cast<Lock_impl_threads*>(li);
    234   int err = pthread_cond_wait(&this->cond_, &lit->mutex_);
    235   if (err != 0)
    236     gold_fatal(_("pthread_cond_wait failed: %s"), strerror(err));
    237 }
    238 
    239 void
    240 Condvar_impl_threads::signal()
    241 {
    242   int err = pthread_cond_signal(&this->cond_);
    243   if (err != 0)
    244     gold_fatal(_("pthread_cond_signal failed: %s"), strerror(err));
    245 }
    246 
    247 void
    248 Condvar_impl_threads::broadcast()
    249 {
    250   int err = pthread_cond_broadcast(&this->cond_);
    251   if (err != 0)
    252     gold_fatal(_("pthread_cond_broadcast failed: %s"), strerror(err));
    253 }
    254 
    255 #endif // defined(ENABLE_THREADS)
    256 
    257 // Methods for Condvar class.
    258 
    259 Condvar::Condvar(Lock& lock)
    260   : lock_(lock)
    261 {
    262   if (!parameters->options().threads())
    263     this->condvar_ = new Condvar_impl_nothreads;
    264   else
    265     {
    266 #ifdef ENABLE_THREADS
    267       this->condvar_ = new Condvar_impl_threads;
    268 #else
    269       gold_unreachable();
    270 #endif
    271     }
    272 }
    273 
    274 Condvar::~Condvar()
    275 {
    276   delete this->condvar_;
    277 }
    278 
    279 #ifdef ENABLE_THREADS
    280 
    281 // Class Once_initialize.  This exists to hold a pthread_once_t
    282 // structure for Once.
    283 
    284 class Once_initialize
    285 {
    286  public:
    287    Once_initialize()
    288 #if defined(__clang__) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4))
    289      : once_(PTHREAD_ONCE_INIT)
    290    { }
    291 #else
    292 // In Drawin PTHREAD_ONCE_INIT is {0x30B1BCBA, {0}} and the GCC < 4.4 doesn't support
    293 // extended initializer list as above */
    294    {
    295      pthread_once_t once_2 = PTHREAD_ONCE_INIT;
    296      once_ = once_2;
    297    }
    298 #endif
    299 
    300   // Return a pointer to the pthread_once_t variable.
    301   pthread_once_t*
    302   once_control()
    303   { return &this->once_; }
    304 
    305  private:
    306   pthread_once_t once_;
    307 };
    308 
    309 #endif // defined(ENABLE_THREADS)
    310 
    311 #ifdef ENABLE_THREADS
    312 
    313 // A single lock which controls access to once_pointer.  This is used
    314 // because we can't pass parameters to functions passed to
    315 // pthread_once.
    316 
    317 static pthread_mutex_t once_pointer_control = PTHREAD_MUTEX_INITIALIZER;
    318 
    319 // A pointer to Once structure we want to run.  Access to this is
    320 // controlled by once_pointer_control.
    321 
    322 static Once* once_pointer;
    323 
    324 // The argument to pass to the Once structure.  Access to this is
    325 // controlled by once_pointer_control.
    326 
    327 static void* once_arg;
    328 
    329 // A routine passed to pthread_once which runs the Once pointer.
    330 
    331 extern "C"
    332 {
    333 
    334 static void
    335 c_run_once(void)
    336 {
    337   once_pointer->internal_run(once_arg);
    338 }
    339 
    340 }
    341 
    342 #endif // defined(ENABLE_THREADS)
    343 
    344 // Class Once.
    345 
    346 Once::Once()
    347   : was_run_(false)
    348 #if defined(ENABLE_THREADS) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
    349     , was_run_lock_(0)
    350 #endif
    351 {
    352 #ifndef ENABLE_THREADS
    353   this->once_ = NULL;
    354 #else
    355   this->once_ = new Once_initialize();
    356 #endif
    357 }
    358 
    359 // Run the function once.
    360 
    361 void
    362 Once::run_once(void* arg)
    363 {
    364 #ifndef ENABLE_THREADS
    365 
    366   // If there is no threads support, we don't need to use pthread_once.
    367   if (!this->was_run_)
    368     this->internal_run(arg);
    369 
    370 #else // defined(ENABLE_THREADS)
    371 
    372   if (parameters->options_valid() && !parameters->options().threads())
    373     {
    374       // If we are not using threads, we don't need to lock.
    375       if (!this->was_run_)
    376 	this->internal_run(arg);
    377       return;
    378     }
    379 
    380   // If we have the sync builtins, use them to skip the lock if the
    381   // value has already been initialized.
    382 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
    383   while (true)
    384     {
    385       if (__sync_bool_compare_and_swap(&this->was_run_lock_, 0, 1))
    386 	break;
    387     }
    388   bool was_run = this->was_run_;
    389   while (true)
    390     {
    391       if (__sync_bool_compare_and_swap(&this->was_run_lock_, 1, 0))
    392 	break;
    393     }
    394   if (was_run)
    395     return;
    396 #endif
    397 
    398   // Since we can't pass parameters to routines called by
    399   // pthread_once, we use a static variable: once_pointer.  This in
    400   // turns means that we need to use a mutex to control access to
    401   // once_pointer.
    402 
    403   int err = pthread_mutex_lock(&once_pointer_control);
    404   if (err != 0)
    405     gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err));
    406 
    407   once_pointer = this;
    408   once_arg = arg;
    409 
    410   err = pthread_once(this->once_->once_control(), c_run_once);
    411   if (err != 0)
    412     gold_fatal(_("pthread_once failed: %s"), strerror(err));
    413 
    414   once_pointer = NULL;
    415   once_arg = NULL;
    416 
    417   err = pthread_mutex_unlock(&once_pointer_control);
    418   if (err != 0)
    419     gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err));
    420 
    421 #endif // defined(ENABLE_THREADS)
    422 }
    423 
    424 // Actually run the function in the child class.  This function will
    425 // be run only once.
    426 
    427 void
    428 Once::internal_run(void* arg)
    429 {
    430   this->do_run_once(arg);
    431   this->was_run_ = true;
    432 }
    433 
    434 // Class Initialize_lock.
    435 
    436 // Initialize the lock.
    437 
    438 bool
    439 Initialize_lock::initialize()
    440 {
    441   // We can't initialize the lock until we have read the options.
    442   if (!parameters->options_valid())
    443     return false;
    444   else
    445     {
    446       this->run_once(NULL);
    447       return true;
    448     }
    449 }
    450 
    451 // Initialize the lock exactly once.
    452 
    453 void
    454 Initialize_lock::do_run_once(void*)
    455 {
    456   *this->pplock_ = new Lock();
    457 }
    458 
    459 } // End namespace gold.
    460