1// gold-threads.cc -- thread support for gold 2 3// Copyright (C) 2006-2017 Free Software Foundation, Inc. 4// Written by Ian Lance Taylor <iant@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 35namespace gold 36{ 37 38class Condvar_impl_nothreads; 39 40// The non-threaded version of Lock_impl. 41 42class 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 74class Condvar_impl_threads; 75 76// The threaded version of Lock_impl. 77 78class 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 88private: 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 98Lock_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_mutexattr_init failed: %s"), strerror(err)); 104#ifdef PTHREAD_MUTEX_ADAPTIVE_NP 105 err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); 106 if (err != 0) 107 gold_fatal(_("pthread_mutexattr_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 119Lock_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 126void 127Lock_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 134void 135Lock_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 146Lock::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 160Lock::~Lock() 161{ 162 delete this->lock_; 163} 164 165// The non-threaded version of Condvar_impl. 166 167class 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 193class 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 216Condvar_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 223Condvar_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 230void 231Condvar_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 239void 240Condvar_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 247void 248Condvar_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 259Condvar::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 274Condvar::~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 284class Once_initialize 285{ 286 public: 287 Once_initialize() 288 : once_(PTHREAD_ONCE_INIT) 289 { } 290 291 // Return a pointer to the pthread_once_t variable. 292 pthread_once_t* 293 once_control() 294 { return &this->once_; } 295 296 private: 297 pthread_once_t once_; 298}; 299 300#endif // defined(ENABLE_THREADS) 301 302#ifdef ENABLE_THREADS 303 304// A single lock which controls access to once_pointer. This is used 305// because we can't pass parameters to functions passed to 306// pthread_once. 307 308static pthread_mutex_t once_pointer_control = PTHREAD_MUTEX_INITIALIZER; 309 310// A pointer to Once structure we want to run. Access to this is 311// controlled by once_pointer_control. 312 313static Once* once_pointer; 314 315// The argument to pass to the Once structure. Access to this is 316// controlled by once_pointer_control. 317 318static void* once_arg; 319 320// A routine passed to pthread_once which runs the Once pointer. 321 322extern "C" 323{ 324 325static void 326c_run_once(void) 327{ 328 once_pointer->internal_run(once_arg); 329} 330 331} 332 333#endif // defined(ENABLE_THREADS) 334 335// Class Once. 336 337Once::Once() 338 : was_run_(false) 339#if defined(ENABLE_THREADS) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) 340 , was_run_lock_(0) 341#endif 342{ 343#ifndef ENABLE_THREADS 344 this->once_ = NULL; 345#else 346 this->once_ = new Once_initialize(); 347#endif 348} 349 350// Run the function once. 351 352void 353Once::run_once(void* arg) 354{ 355#ifndef ENABLE_THREADS 356 357 // If there is no threads support, we don't need to use pthread_once. 358 if (!this->was_run_) 359 this->internal_run(arg); 360 361#else // defined(ENABLE_THREADS) 362 363 if (parameters->options_valid() && !parameters->options().threads()) 364 { 365 // If we are not using threads, we don't need to lock. 366 if (!this->was_run_) 367 this->internal_run(arg); 368 return; 369 } 370 371 // If we have the sync builtins, use them to skip the lock if the 372 // value has already been initialized. 373#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 374 while (true) 375 { 376 if (__sync_bool_compare_and_swap(&this->was_run_lock_, 0, 1)) 377 break; 378 } 379 bool was_run = this->was_run_; 380 while (true) 381 { 382 if (__sync_bool_compare_and_swap(&this->was_run_lock_, 1, 0)) 383 break; 384 } 385 if (was_run) 386 return; 387#endif 388 389 // Since we can't pass parameters to routines called by 390 // pthread_once, we use a static variable: once_pointer. This in 391 // turns means that we need to use a mutex to control access to 392 // once_pointer. 393 394 int err = pthread_mutex_lock(&once_pointer_control); 395 if (err != 0) 396 gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err)); 397 398 once_pointer = this; 399 once_arg = arg; 400 401 err = pthread_once(this->once_->once_control(), c_run_once); 402 if (err != 0) 403 gold_fatal(_("pthread_once failed: %s"), strerror(err)); 404 405 once_pointer = NULL; 406 once_arg = NULL; 407 408 err = pthread_mutex_unlock(&once_pointer_control); 409 if (err != 0) 410 gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err)); 411 412#endif // defined(ENABLE_THREADS) 413} 414 415// Actually run the function in the child class. This function will 416// be run only once. 417 418void 419Once::internal_run(void* arg) 420{ 421 this->do_run_once(arg); 422 this->was_run_ = true; 423} 424 425// Class Initialize_lock. 426 427// Initialize the lock. 428 429bool 430Initialize_lock::initialize() 431{ 432 // We can't initialize the lock until we have read the options. 433 if (!parameters->options_valid()) 434 return false; 435 else 436 { 437 this->run_once(NULL); 438 return true; 439 } 440} 441 442// Initialize the lock exactly once. 443 444void 445Initialize_lock::do_run_once(void*) 446{ 447 *this->pplock_ = new Lock(); 448} 449 450} // End namespace gold. 451